From e1cb13bd90a2955263a7e5cc0edf6e9ccf359603 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 29 Oct 2015 16:45:53 +0300 Subject: [PATCH] Qualifier no longer defers "(nested) class vs package" resolution. Consider FQN 'a.b.c'. If 'a' is a classifier in the current scope, resolve rest in the corresponding class scope. Otherwise (if 'a' is a package), find the maximum possible prefix 'a.b' resolving to a package, resolve rest in the corresponding package scope. --- .../resolve/QualifiedExpressionResolver.kt | 15 ++- .../resolve/scopes/receivers/Qualifier.kt | 127 ++++++++++++------ .../tests/imports/TopLevelClassVsPackage.kt | 4 +- .../GenericClassVsPackage.kt | 9 +- .../GenericClassVsPackage.txt | 4 +- .../qualifiedExpression/PackageVsClass2.kt | 15 +++ .../qualifiedExpression/PackageVsClass2.txt | 37 +++++ .../qualifiedExpression/PackageVsRootClass.kt | 2 +- .../visibleClassVsQualifiedClass.kt | 12 +- .../checkers/JetDiagnosticsTestGenerated.java | 6 + 10 files changed, 169 insertions(+), 62 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.kt create mode 100644 compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index 338506b33d3..fd82987dd6f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -26,7 +26,8 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope -import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ClassifierQualifier +import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier import org.jetbrains.kotlin.resolve.source.KotlinSourceElement @@ -426,10 +427,14 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa } private fun storageQualifier(trace: BindingTrace, referenceExpression: KtSimpleNameExpression, descriptor: DeclarationDescriptor) { - if (descriptor is PackageViewDescriptor || descriptor is ClassifierDescriptor) { - val qualifier = QualifierReceiver(referenceExpression, descriptor as? PackageViewDescriptor, descriptor as? ClassifierDescriptor) - trace.record(BindingContext.QUALIFIER, qualifier.expression, qualifier) - } + val qualifier = + when (descriptor) { + is PackageViewDescriptor -> PackageQualifier(referenceExpression, descriptor) + is ClassifierDescriptor -> ClassifierQualifier(referenceExpression, descriptor) + else -> return + } + + trace.record(BindingContext.QUALIFIER, qualifier.expression, qualifier) } private fun isVisible( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt index 826b98eb237..c0f41a8f7c1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt @@ -61,10 +61,8 @@ public interface Qualifier: ReceiverValue { public val scope: KtScope } -class QualifierReceiver ( - val referenceExpression: KtSimpleNameExpression, - override val packageView: PackageViewDescriptor?, - override val classifier: ClassifierDescriptor? +abstract class QualifierReceiver( + val referenceExpression: KtSimpleNameExpression ) : Qualifier { override val expression: KtExpression = referenceExpression.getTopmostParentQualifiedExpressionForSelector() ?: referenceExpression @@ -74,54 +72,79 @@ class QualifierReceiver ( override var resultingDescriptor: DeclarationDescriptor by Delegates.notNull() - override val scope: KtScope get() { - val scopes = ArrayList(4) - - val classObjectTypeScope = (classifier as? ClassDescriptor)?.classObjectType?.memberScope?.let { - FilteringScope(it) { it !is ClassDescriptor } - } - scopes.addIfNotNull(classObjectTypeScope) - - scopes.addIfNotNull(packageView?.memberScope) - - if (classifier is ClassDescriptor) { - scopes.add(classifier.staticScope) - - if (classifier.kind != ClassKind.ENUM_ENTRY) { - scopes.add(classifier.unsubstitutedInnerClassesScope) - } - } - - return ChainedScope(descriptor, "Member scope for $name as package or class or object", *scopes.toTypedArray()) - } - fun getClassObjectReceiver(): ReceiverValue = (classifier as? ClassDescriptor)?.classObjectType?.let { ExpressionReceiver(referenceExpression, it) } ?: ReceiverValue.NO_RECEIVER - fun getNestedClassesAndPackageMembersScope(): KtScope { - val scopes = ArrayList(4) - - scopes.addIfNotNull(packageView?.memberScope) - - if (classifier is ClassDescriptor) { - scopes.add(classifier.getStaticScope()) - - if (classifier.getKind() != ClassKind.ENUM_ENTRY) { - scopes.add(DescriptorUtils.getStaticNestedClassesScope(classifier)) - } - } - - return ChainedScope(descriptor, "Static scope for " + name + " as package or class or object", *scopes.toTypedArray()) - } + abstract fun getNestedClassesAndPackageMembersScope(): KtScope override fun getType(): KotlinType = throw IllegalStateException("No type corresponds to QualifierReceiver '$this'") override fun exists() = true - - override fun toString() = "Package{$packageView} OR Class{$classifier}" } +class PackageQualifier( + referenceExpression: KtSimpleNameExpression, + override val packageView: PackageViewDescriptor +) : QualifierReceiver(referenceExpression) { + + override val classifier: ClassifierDescriptor? get() = null + + override val scope: KtScope get() = packageView.memberScope + + override fun getNestedClassesAndPackageMembersScope(): KtScope = packageView.memberScope + + override fun toString() = "Package{$packageView}" +} + +class ClassifierQualifier( + referenceExpression: KtSimpleNameExpression, + override val classifier: ClassifierDescriptor +) : QualifierReceiver(referenceExpression) { + + override val packageView: PackageViewDescriptor? get() = null + + override val scope: KtScope get() { + if (classifier !is ClassDescriptor) { + return KtScope.Empty + } + + val scopes = ArrayList(3) + + val classObjectTypeScope = classifier.classObjectType?.memberScope?.let { + FilteringScope(it) { it !is ClassDescriptor } + } + scopes.addIfNotNull(classObjectTypeScope) + + scopes.add(classifier.staticScope) + + if (classifier.kind != ClassKind.ENUM_ENTRY) { + scopes.add(classifier.unsubstitutedInnerClassesScope) + } + + return ChainedScope(descriptor, "Member scope for $name as class or object", *scopes.toTypedArray()) + } + + override fun getNestedClassesAndPackageMembersScope(): KtScope { + if (classifier !is ClassDescriptor) { + return KtScope.Empty + } + + val scopes = ArrayList(2) + + scopes.add(classifier.staticScope) + + if (classifier.kind != ClassKind.ENUM_ENTRY) { + scopes.add(DescriptorUtils.getStaticNestedClassesScope(classifier)) + } + + return ChainedScope(descriptor, "Static scope for $name as class or object", *scopes.toTypedArray()) + } + + override fun toString() = "Classifier{$classifier}" +} + + fun createQualifier( expression: KtSimpleNameExpression, receiver: ReceiverValue, @@ -141,7 +164,18 @@ fun createQualifier( context.trace.recordScope(context.scope, expression) - val qualifier = QualifierReceiver(expression, packageViewDescriptor, classifierDescriptor) + val qualifier = + if (receiver is PackageQualifier) + if (packageViewDescriptor != null) + PackageQualifier(expression, packageViewDescriptor) + else + ClassifierQualifier(expression, classifierDescriptor!!) + else + if (classifierDescriptor != null) + ClassifierQualifier(expression, classifierDescriptor) + else + PackageQualifier(expression, packageViewDescriptor!!) + context.trace.record(QUALIFIER, qualifier.expression, qualifier) return qualifier } @@ -150,6 +184,8 @@ fun QualifierReceiver.resolveAsStandaloneExpression( context: ExpressionTypingContext, symbolUsageValidator: SymbolUsageValidator ): KotlinType? { + val classifier = this.classifier + resolveAndRecordReferenceTarget(context, symbolUsageValidator, selector = null) if (classifier is TypeParameterDescriptor) { context.trace.report(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(referenceExpression, classifier)) @@ -168,6 +204,8 @@ fun QualifierReceiver.resolveAsReceiverInQualifiedExpression( symbolUsageValidator: SymbolUsageValidator, selector: DeclarationDescriptor? ) { + val classifier = this.classifier + resolveAndRecordReferenceTarget(context, symbolUsageValidator, selector) if (classifier is TypeParameterDescriptor) { context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(referenceExpression, classifier)) @@ -191,6 +229,9 @@ private fun QualifierReceiver.resolveReferenceTarget( symbolUsageValidator: SymbolUsageValidator, selector: DeclarationDescriptor? ): DeclarationDescriptor { + val classifier = this.classifier + val packageView = this.packageView + if (classifier is TypeParameterDescriptor) { return classifier } diff --git a/compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt b/compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt index 0673fb29956..4317d323edc 100644 --- a/compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt +++ b/compiler/testData/diagnostics/tests/imports/TopLevelClassVsPackage.kt @@ -46,7 +46,7 @@ fun test2(_a: a) { _ab._ab() val _ab2 = a.b() - _ab2._ab() // todo + _ab2._ab() _fun() } @@ -62,7 +62,7 @@ fun test3(_a: a) { _ab._ab() val _ab2 = a.b() - _ab2._ab() // todo + _ab2._ab() _fun() } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/qualifiedExpression/GenericClassVsPackage.kt b/compiler/testData/diagnostics/tests/qualifiedExpression/GenericClassVsPackage.kt index 27c332badcd..8b40039c0d8 100644 --- a/compiler/testData/diagnostics/tests/qualifiedExpression/GenericClassVsPackage.kt +++ b/compiler/testData/diagnostics/tests/qualifiedExpression/GenericClassVsPackage.kt @@ -30,9 +30,10 @@ fun test(ab_c: c) { ab_c3.ab_c() } -fun test2(a_bc: a.b.c) { - a_bc.a_bc() // todo - a_bc.ab_c() // todo +// NB according to the maximum package prefix rule, 'a.b.c' denotes 'c' in package 'a.b' (thus ab_c, not a_bc) +fun test2(ab_c: a.b.c) { + ab_c.a_bc() + ab_c.ab_c() } @@ -66,7 +67,7 @@ fun test(a_b: b) { _ab._ab() val _ab2 = a.b() - _ab2._ab() // todo + _ab2._ab() } fun test2(_ab: a.b) { diff --git a/compiler/testData/diagnostics/tests/qualifiedExpression/GenericClassVsPackage.txt b/compiler/testData/diagnostics/tests/qualifiedExpression/GenericClassVsPackage.txt index 24b7ef07d16..32979ff96ca 100644 --- a/compiler/testData/diagnostics/tests/qualifiedExpression/GenericClassVsPackage.txt +++ b/compiler/testData/diagnostics/tests/qualifiedExpression/GenericClassVsPackage.txt @@ -42,7 +42,7 @@ package a { package public fun test(/*0*/ ab_c: a.b.c): kotlin.Unit -public fun test2(/*0*/ a_bc: a.b.c): kotlin.Unit +public fun test2(/*0*/ ab_c: a.b.c): kotlin.Unit package a { @@ -110,3 +110,5 @@ package a { // -- Module: -- } } + + diff --git a/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.kt b/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.kt new file mode 100644 index 00000000000..0b08c173578 --- /dev/null +++ b/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.kt @@ -0,0 +1,15 @@ +// MODULE: m1 +// FILE: a.kt +package a + +class b { + fun a_b() {} +} + +// MODULE: m2(m1) +// FILE: b.kt +package test + +class a + +val x = a.b() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.txt b/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.txt new file mode 100644 index 00000000000..cb080b2574a --- /dev/null +++ b/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.txt @@ -0,0 +1,37 @@ +// -- Module: -- +package + +package a { + + public final class b { + public constructor b() + public final fun a_b(): kotlin.Unit + 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 + } +} + + +// -- Module: -- +package + +package a { + + public final class b { + // -- Module: -- + } +} + +package test { + public val x: [ERROR : Type for a.b()] + + public final class a { + public constructor a() + 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/testData/diagnostics/tests/qualifiedExpression/PackageVsRootClass.kt b/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsRootClass.kt index 1ec94f8ccf0..e81b8ef51d5 100644 --- a/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsRootClass.kt +++ b/compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsRootClass.kt @@ -40,5 +40,5 @@ fun test(_ab: a.b) { _ab._ab() val _ab2 = a.b() - _ab2._ab() // todo + _ab2._ab() // todo } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/qualifiedExpression/visibleClassVsQualifiedClass.kt b/compiler/testData/diagnostics/tests/qualifiedExpression/visibleClassVsQualifiedClass.kt index 13c29e6792b..9d116812ff2 100644 --- a/compiler/testData/diagnostics/tests/qualifiedExpression/visibleClassVsQualifiedClass.kt +++ b/compiler/testData/diagnostics/tests/qualifiedExpression/visibleClassVsQualifiedClass.kt @@ -25,10 +25,10 @@ class a {} fun test(a_: a.b) { a_.a_b() - val a_2 = a.b() - a_2.a_b() // todo: must be unresolved - a_2.some_ab() - a_2.a_() + val a_2 = a.b() + a_2.a_b() + a_2.some_ab() + a_2.a_() } // FILE: c2.kt @@ -44,7 +44,7 @@ fun test(_ab: a.b) { _ab.other2_ab() val _ab2 = a.b() - _ab2.other2_ab() // todo + _ab2.other2_ab() } // FILE: c3.kt @@ -54,5 +54,5 @@ fun test(_ab: a.b) { _ab.some_ab() val _ab2 = a.b() - _ab2.some_ab() // todo + _ab2.some_ab() } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 0f42ad3cdfe..5ac178ced29 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -11862,6 +11862,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("PackageVsClass2.kt") + public void testPackageVsClass2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsClass2.kt"); + doTest(fileName); + } + @TestMetadata("PackageVsRootClass.kt") public void testPackageVsRootClass() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/qualifiedExpression/PackageVsRootClass.kt");