From 0c0c53cc2e5dfa76a99431d7756047c965279c95 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 10 Feb 2021 12:08:18 +0300 Subject: [PATCH] [FE] Don't analyze members with CLASSIFIERS kind filter in AbstractLazyMemberScope This commit introduces partial support of descriptorKindFilter in `AbstractPsiBasedDeclarationProvider`. Without it there may be an error in following case: ``` sealed class Base class Derived : Base() class Test(val x: Base) { private val y = when (x) { is Derived -> null } } ``` Here we start to resolve type of `y`, then go to computation of inheritors of sealed class Base, which also may be inside Test, so we need get all nested classifiers in Test. But without this filtration we will start computing descriptor for `y` again, which leads to ReenteringLazyComputationException #KT-44316 Fixed --- ...irOldFrontendDiagnosticsTestGenerated.java | 6 +++++ .../AbstractPsiBasedDeclarationProvider.kt | 9 +++++-- .../lazy/descriptors/LazyClassMemberScope.kt | 18 +++++++++++++- .../diagnostics/tests/sealed/kt44316.kt | 11 +++++++++ .../diagnostics/tests/sealed/kt44316.txt | 24 +++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 +++++ .../kotlin/resolve/scopes/MemberScope.kt | 18 ++++++++++++++ 7 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/sealed/kt44316.kt create mode 100644 compiler/testData/diagnostics/tests/sealed/kt44316.txt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 79364c10df4..56b9c23c588 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -24391,6 +24391,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt"); } + @Test + @TestMetadata("kt44316.kt") + public void testKt44316() throws Exception { + runTest("compiler/testData/diagnostics/tests/sealed/kt44316.kt"); + } + @Test @TestMetadata("Local.kt") public void testLocal() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt index 3b970c0baf0..70a17de9e55 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt @@ -88,8 +88,13 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage internal fun toInfoString() = toString() + ": " + index().toString() - override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List = - index().allDeclarations + override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List { + val allDeclarations = index().allDeclarations + if (kindFilter == DescriptorKindFilter.CLASSIFIERS) { + return allDeclarations.filter { it is KtClassOrObject || it is KtTypeAlias } + } + return allDeclarations + } override fun getFunctionDeclarations(name: Name): List = index().functions[name.safeNameForLazyResolve()].toList() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt index a58ac3c2ca5..6cb62886d62 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt @@ -70,10 +70,26 @@ open class LazyClassMemberScope( result.toList() } + private val allClassifierDescriptors = storageManager.createLazyValue { + val result = LinkedHashSet( + computeDescriptorsFromDeclaredElements( + DescriptorKindFilter.CLASSIFIERS, + MemberScope.ALL_NAME_FILTER, + NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS + ) + ) + addSyntheticCompanionObject(result, NoLookupLocation.FOR_ALREADY_TRACKED) + addSyntheticNestedClasses(result, NoLookupLocation.FOR_ALREADY_TRACKED) + result.toList() + } + override fun getContributedDescriptors( kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean - ): Collection = allDescriptors() + ): Collection = when (kindFilter) { + DescriptorKindFilter.CLASSIFIERS -> allClassifierDescriptors() + else -> allDescriptors() + } protected open fun computeExtraDescriptors(location: LookupLocation): Collection { val result = ArrayList() diff --git a/compiler/testData/diagnostics/tests/sealed/kt44316.kt b/compiler/testData/diagnostics/tests/sealed/kt44316.kt new file mode 100644 index 00000000000..cd55b84deb6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sealed/kt44316.kt @@ -0,0 +1,11 @@ +// FIR_IDENTICAL +// KT-44316 + +sealed class Base +class Derived : Base() + +class Test(val x: Base) { + private val y = when (x) { + is Derived -> null + } +} diff --git a/compiler/testData/diagnostics/tests/sealed/kt44316.txt b/compiler/testData/diagnostics/tests/sealed/kt44316.txt new file mode 100644 index 00000000000..6e077339484 --- /dev/null +++ b/compiler/testData/diagnostics/tests/sealed/kt44316.txt @@ -0,0 +1,24 @@ +package + +public sealed class Base { + internal constructor Base() + 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 Derived : Base { + public constructor Derived() + 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 Test { + public constructor Test(/*0*/ x: Base) + public final val x: Base + private final val y: kotlin.Nothing? + 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-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index c9b5822b670..9ab80c8a85b 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -24481,6 +24481,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt"); } + @Test + @TestMetadata("kt44316.kt") + public void testKt44316() throws Exception { + runTest("compiler/testData/diagnostics/tests/sealed/kt44316.kt"); + } + @Test @TestMetadata("Local.kt") public void testLocal() throws Exception { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt index bd8224e80ed..3bc4e41cb33 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/MemberScope.kt @@ -138,6 +138,24 @@ class DescriptorKindFilter( } } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as DescriptorKindFilter + + if (excludes != other.excludes) return false + if (kindMask != other.kindMask) return false + + return true + } + + override fun hashCode(): Int { + var result = excludes.hashCode() + result = 31 * result + kindMask + return result + } + companion object { private var nextMaskValue: Int = 0x01 private fun nextMask() = nextMaskValue.apply { nextMaskValue = nextMaskValue shl 1 }