From c899f6dae33f7ecf68623e26fedfd3e4ff824aef Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 1 Dec 2022 16:54:51 +0100 Subject: [PATCH] [LL FIR] fix lazy resolution of member property statuses for anonymous objects Previously, statuses of superclass which are not local was not ignored Sometimes it worked in the IDE by calling lazyResolveToPhase which is a violation of the lazy resolution contract ^KT-54890 --- .../anonympuseObjectInInvalidPosition.txt | 2 +- ...nosisCompilerFirTestdataTestGenerated.java | 6 ++ ...TouchedTilContractsPhaseTestGenerated.java | 5 ++ .../resolve/localClasses/anonObject.fir.txt | 29 +++++++ .../resolve/localClasses/anonObject.kt | 11 +++ .../runners/FirDiagnosticTestGenerated.java | 6 ++ ...DiagnosticsWithLightTreeTestGenerated.java | 6 ++ .../FirStatusResolveTransformer.kt | 75 +++++++++---------- .../resolve/transformers/FirStatusResolver.kt | 9 ++- 9 files changed, 104 insertions(+), 45 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.kt diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/errors/anonympuseObjectInInvalidPosition.txt b/analysis/low-level-api-fir/testdata/lazyResolve/errors/anonympuseObjectInInvalidPosition.txt index de26931600b..b8259e91d30 100644 --- a/analysis/low-level-api-fir/testdata/lazyResolve/errors/anonympuseObjectInInvalidPosition.txt +++ b/analysis/low-level-api-fir/testdata/lazyResolve/errors/anonympuseObjectInInvalidPosition.txt @@ -156,7 +156,7 @@ FILE: anonympuseObjectInInvalidPosition.kt } private [BODY_RESOLVE] get(): - public abstract [SUPER_TYPES] interface A<[SUPER_TYPES] T> : R|kotlin/Any| { + public abstract [TYPES] interface A<[TYPES] T> : R|kotlin/Any| { public abstract [STATUS] fun x(): R|kotlin/Unit| } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java index a34edcc6117..ccbf506a6a4 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java @@ -3145,6 +3145,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/localClasses"), Pattern.compile("^([^.]+)\\.kt$"), null, true); } + @Test + @TestMetadata("anonObject.kt") + public void testAnonObject() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.kt"); + } + @Test @TestMetadata("anonymousInAnonymous.kt") public void testAnonymousInAnonymous() throws Exception { diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index b86989e7b5f..5121b1d1ada 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -2768,6 +2768,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/localClasses"), Pattern.compile("^([^.]+)\\.kt$"), null, true); } + @TestMetadata("anonObject.kt") + public void testAnonObject() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.kt"); + } + @TestMetadata("anonymousInAnonymous.kt") public void testAnonymousInAnonymous() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/anonymousInAnonymous.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.fir.txt b/compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.fir.txt new file mode 100644 index 00000000000..c3445ff7087 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.fir.txt @@ -0,0 +1,29 @@ +FILE: a.kt + public final object A : R|kotlin/Any| { + private constructor(): R|A| { + super() + } + + public final val O: R|B| = object : R|B| { + private constructor(): R|| { + super() + } + + protected final override val message: R|kotlin/String| = String(expression expected) + protected get(): R|kotlin/String| + + } + + public get(): R|B| + + } +FILE: b.kt + public abstract class B : R|kotlin/Any| { + public constructor(): R|B| { + super() + } + + protected abstract val message: R|kotlin/String| + protected get(): R|kotlin/String| + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.kt b/compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.kt new file mode 100644 index 00000000000..c315b7a0b26 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.kt @@ -0,0 +1,11 @@ +// FILE: a.kt +object A { + val O = object : B() { + override val message = "expression expected" + } +} + +// FILE: b.kt +abstract class B { + protected abstract val message: String +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 58afb847c01..6b743fee875 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -3145,6 +3145,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/localClasses"), Pattern.compile("^([^.]+)\\.kt$"), null, true); } + @Test + @TestMetadata("anonObject.kt") + public void testAnonObject() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.kt"); + } + @Test @TestMetadata("anonymousInAnonymous.kt") public void testAnonymousInAnonymous() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 7cf72f9628e..626f85a64fe 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -3145,6 +3145,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/localClasses"), Pattern.compile("^([^.]+)\\.kt$"), null, true); } + @Test + @TestMetadata("anonObject.kt") + public void testAnonObject() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/anonObject.kt"); + } + @Test @TestMetadata("anonymousInAnonymous.kt") public void testAnonymousInAnonymous() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt index bccc29d4952..d9dfbdf810f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt @@ -5,19 +5,14 @@ package org.jetbrains.kotlin.fir.resolve.transformers -import org.jetbrains.kotlin.descriptors.EffectiveVisibility -import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.caches.firCachesFactory import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.utils.isInline -import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.LocalClassesNavigationInfo import org.jetbrains.kotlin.fir.scopes.FirCompositeScope import org.jetbrains.kotlin.fir.scopes.FirScope @@ -102,23 +97,23 @@ open class FirStatusResolveTransformer( return true } - override fun transformRegularClass( - regularClass: FirRegularClass, + override fun transformClassContent( + firClass: FirClass, data: FirResolvedDeclarationStatus? - ): FirStatement = whileAnalysing(regularClass) { - val computationStatus = statusComputationSession.startComputing(regularClass) - forceResolveStatusesOfSupertypes(regularClass) + ): FirStatement { + val computationStatus = statusComputationSession.startComputing(firClass) + forceResolveStatusesOfSupertypes(firClass) /* * Status of class may be already calculated if that class was in supertypes of one of previous classes */ if (computationStatus != StatusComputationSession.StatusComputationStatus.Computed) { - regularClass.transformStatus(this, statusResolver.resolveStatus(regularClass, containingClass, isLocal = false)) - if (regularClass.isInline) { - regularClass.valueClassRepresentation = computeValueClassRepresentation(regularClass, session) + firClass.transformStatus(this, statusResolver.resolveStatus(firClass, containingClass, isLocal = false)) + if (firClass is FirRegularClass && firClass.isInline) { + firClass.valueClassRepresentation = computeValueClassRepresentation(firClass, session) } } - return transformClass(regularClass, data).also { - statusComputationSession.endComputing(regularClass) + return transformClass(firClass, data).also { + statusComputationSession.endComputing(firClass) } } } @@ -145,31 +140,31 @@ open class FirDesignatedStatusResolveTransformer( return !designation.classLocated } - override fun transformRegularClass( - regularClass: FirRegularClass, + override fun transformClassContent( + firClass: FirClass, data: FirResolvedDeclarationStatus? - ): FirStatement = whileAnalysing(regularClass) { - if (designation.shouldSkipClass(regularClass)) return regularClass - regularClass.symbol.lazyResolveToPhase(FirResolvePhase.TYPES) + ): FirStatement = whileAnalysing(firClass) { + if (designation.shouldSkipClass(firClass)) return firClass + firClass.symbol.lazyResolveToPhase(FirResolvePhase.TYPES) val classLocated = designation.classLocated /* * In designated status resolve we should resolve status only of target class and it's members */ if (classLocated) { - assert(regularClass == designation.targetClass) - val computationStatus = statusComputationSession.startComputing(regularClass) - forceResolveStatusesOfSupertypes(regularClass) + assert(firClass == designation.targetClass) + val computationStatus = statusComputationSession.startComputing(firClass) + forceResolveStatusesOfSupertypes(firClass) if (computationStatus != StatusComputationSession.StatusComputationStatus.Computed) { - regularClass.transformStatus(this, statusResolver.resolveStatus(regularClass, containingClass, isLocal = false)) + firClass.transformStatus(this, statusResolver.resolveStatus(firClass, containingClass, isLocal = false)) } } else { - if (regularClass.status !is FirResolvedDeclarationStatus) { - regularClass.transformStatus(this, statusResolver.resolveStatus(regularClass, containingClass, isLocal = false)) - statusComputationSession.computeOnlyClassStatus(regularClass) + if (firClass.status !is FirResolvedDeclarationStatus) { + firClass.transformStatus(this, statusResolver.resolveStatus(firClass, containingClass, isLocal = false)) + statusComputationSession.computeOnlyClassStatus(firClass) } } - return transformClass(regularClass, data).also { - if (classLocated) statusComputationSession.endComputing(regularClass) + return transformClass(firClass, data).also { + if (classLocated) statusComputationSession.endComputing(firClass) } } } @@ -268,25 +263,23 @@ abstract class AbstractFirStatusResolveTransformer( return transformDeclaration(typeAlias, data) as FirTypeAlias } - abstract override fun transformRegularClass( + override fun transformRegularClass( regularClass: FirRegularClass, data: FirResolvedDeclarationStatus? + ): FirStatement = whileAnalysing(regularClass) { + transformClassContent(regularClass, data) + } + + abstract fun transformClassContent( + firClass: FirClass, + data: FirResolvedDeclarationStatus? ): FirStatement override fun transformAnonymousObject( anonymousObject: FirAnonymousObject, data: FirResolvedDeclarationStatus? ): FirStatement = whileAnalysing(anonymousObject) { - anonymousObject.transformStatus( - this, - FirResolvedDeclarationStatusImpl( - anonymousObject.status.visibility, - anonymousObject.status.modality ?: Modality.FINAL, - EffectiveVisibility.Local - ) - ) - @Suppress("UNCHECKED_CAST") - return transformClass(anonymousObject, data) + transformClassContent(anonymousObject, data) } open fun transformDeclarationContent( @@ -329,7 +322,7 @@ abstract class AbstractFirStatusResolveTransformer( } as FirStatement } - protected fun forceResolveStatusesOfSupertypes(regularClass: FirRegularClass) { + protected fun forceResolveStatusesOfSupertypes(regularClass: FirClass) { for (superTypeRef in regularClass.superTypeRefs) { forceResolveStatusOfCorrespondingClass(superTypeRef) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolver.kt index 1a6d14c4fc3..83b7ead2bbd 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolver.kt @@ -152,12 +152,15 @@ class FirStatusResolver( } fun resolveStatus( - regularClass: FirRegularClass, + firClass: FirClass, containingClass: FirClass?, isLocal: Boolean ): FirResolvedDeclarationStatus { - val status = regularClass.applyExtensionTransformers { transformStatus(it, regularClass, containingClass, isLocal) } - return resolveStatus(regularClass, status, containingClass, null, isLocal, emptyList()) + val status = when (firClass) { + is FirRegularClass -> firClass.applyExtensionTransformers { transformStatus(it, firClass, containingClass, isLocal) } + else -> firClass.status + } + return resolveStatus(firClass, status, containingClass, null, isLocal, emptyList()) } fun resolveStatus(