[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
This commit is contained in:
Ilya Kirillov
2022-12-01 16:54:51 +01:00
parent c66fbf5c0e
commit c899f6dae3
9 changed files with 104 additions and 45 deletions
@@ -156,7 +156,7 @@ FILE: anonympuseObjectInInvalidPosition.kt
} }
private [BODY_RESOLVE] get(): <ERROR TYPE REF: Wrong number of type arguments> private [BODY_RESOLVE] get(): <ERROR TYPE REF: Wrong number of type arguments>
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| public abstract [STATUS] fun x(): R|kotlin/Unit|
} }
@@ -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); 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 @Test
@TestMetadata("anonymousInAnonymous.kt") @TestMetadata("anonymousInAnonymous.kt")
public void testAnonymousInAnonymous() throws Exception { public void testAnonymousInAnonymous() throws Exception {
@@ -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); 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") @TestMetadata("anonymousInAnonymous.kt")
public void testAnonymousInAnonymous() throws Exception { public void testAnonymousInAnonymous() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/anonymousInAnonymous.kt"); runTest("compiler/fir/analysis-tests/testData/resolve/localClasses/anonymousInAnonymous.kt");
@@ -0,0 +1,29 @@
FILE: a.kt
public final object A : R|kotlin/Any| {
private constructor(): R|A| {
super<R|kotlin/Any|>()
}
public final val O: R|B| = object : R|B| {
private constructor(): R|<anonymous>| {
super<R|B|>()
}
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<R|kotlin/Any|>()
}
protected abstract val message: R|kotlin/String|
protected get(): R|kotlin/String|
}
@@ -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
}
@@ -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); 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 @Test
@TestMetadata("anonymousInAnonymous.kt") @TestMetadata("anonymousInAnonymous.kt")
public void testAnonymousInAnonymous() throws Exception { public void testAnonymousInAnonymous() throws Exception {
@@ -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); 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 @Test
@TestMetadata("anonymousInAnonymous.kt") @TestMetadata("anonymousInAnonymous.kt")
public void testAnonymousInAnonymous() throws Exception { public void testAnonymousInAnonymous() throws Exception {
@@ -5,19 +5,14 @@
package org.jetbrains.kotlin.fir.resolve.transformers 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.FirSession
import org.jetbrains.kotlin.fir.caches.firCachesFactory import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.declarations.* 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.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.ScopeSession 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.resolve.transformers.body.resolve.LocalClassesNavigationInfo
import org.jetbrains.kotlin.fir.scopes.FirCompositeScope import org.jetbrains.kotlin.fir.scopes.FirCompositeScope
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
@@ -102,23 +97,23 @@ open class FirStatusResolveTransformer(
return true return true
} }
override fun transformRegularClass( override fun transformClassContent(
regularClass: FirRegularClass, firClass: FirClass,
data: FirResolvedDeclarationStatus? data: FirResolvedDeclarationStatus?
): FirStatement = whileAnalysing(regularClass) { ): FirStatement {
val computationStatus = statusComputationSession.startComputing(regularClass) val computationStatus = statusComputationSession.startComputing(firClass)
forceResolveStatusesOfSupertypes(regularClass) forceResolveStatusesOfSupertypes(firClass)
/* /*
* Status of class may be already calculated if that class was in supertypes of one of previous classes * Status of class may be already calculated if that class was in supertypes of one of previous classes
*/ */
if (computationStatus != StatusComputationSession.StatusComputationStatus.Computed) { if (computationStatus != StatusComputationSession.StatusComputationStatus.Computed) {
regularClass.transformStatus(this, statusResolver.resolveStatus(regularClass, containingClass, isLocal = false)) firClass.transformStatus(this, statusResolver.resolveStatus(firClass, containingClass, isLocal = false))
if (regularClass.isInline) { if (firClass is FirRegularClass && firClass.isInline) {
regularClass.valueClassRepresentation = computeValueClassRepresentation(regularClass, session) firClass.valueClassRepresentation = computeValueClassRepresentation(firClass, session)
} }
} }
return transformClass(regularClass, data).also { return transformClass(firClass, data).also {
statusComputationSession.endComputing(regularClass) statusComputationSession.endComputing(firClass)
} }
} }
} }
@@ -145,31 +140,31 @@ open class FirDesignatedStatusResolveTransformer(
return !designation.classLocated return !designation.classLocated
} }
override fun transformRegularClass( override fun transformClassContent(
regularClass: FirRegularClass, firClass: FirClass,
data: FirResolvedDeclarationStatus? data: FirResolvedDeclarationStatus?
): FirStatement = whileAnalysing(regularClass) { ): FirStatement = whileAnalysing(firClass) {
if (designation.shouldSkipClass(regularClass)) return regularClass if (designation.shouldSkipClass(firClass)) return firClass
regularClass.symbol.lazyResolveToPhase(FirResolvePhase.TYPES) firClass.symbol.lazyResolveToPhase(FirResolvePhase.TYPES)
val classLocated = designation.classLocated val classLocated = designation.classLocated
/* /*
* In designated status resolve we should resolve status only of target class and it's members * In designated status resolve we should resolve status only of target class and it's members
*/ */
if (classLocated) { if (classLocated) {
assert(regularClass == designation.targetClass) assert(firClass == designation.targetClass)
val computationStatus = statusComputationSession.startComputing(regularClass) val computationStatus = statusComputationSession.startComputing(firClass)
forceResolveStatusesOfSupertypes(regularClass) forceResolveStatusesOfSupertypes(firClass)
if (computationStatus != StatusComputationSession.StatusComputationStatus.Computed) { if (computationStatus != StatusComputationSession.StatusComputationStatus.Computed) {
regularClass.transformStatus(this, statusResolver.resolveStatus(regularClass, containingClass, isLocal = false)) firClass.transformStatus(this, statusResolver.resolveStatus(firClass, containingClass, isLocal = false))
} }
} else { } else {
if (regularClass.status !is FirResolvedDeclarationStatus) { if (firClass.status !is FirResolvedDeclarationStatus) {
regularClass.transformStatus(this, statusResolver.resolveStatus(regularClass, containingClass, isLocal = false)) firClass.transformStatus(this, statusResolver.resolveStatus(firClass, containingClass, isLocal = false))
statusComputationSession.computeOnlyClassStatus(regularClass) statusComputationSession.computeOnlyClassStatus(firClass)
} }
} }
return transformClass(regularClass, data).also { return transformClass(firClass, data).also {
if (classLocated) statusComputationSession.endComputing(regularClass) if (classLocated) statusComputationSession.endComputing(firClass)
} }
} }
} }
@@ -268,25 +263,23 @@ abstract class AbstractFirStatusResolveTransformer(
return transformDeclaration(typeAlias, data) as FirTypeAlias return transformDeclaration(typeAlias, data) as FirTypeAlias
} }
abstract override fun transformRegularClass( override fun transformRegularClass(
regularClass: FirRegularClass, regularClass: FirRegularClass,
data: FirResolvedDeclarationStatus? data: FirResolvedDeclarationStatus?
): FirStatement = whileAnalysing(regularClass) {
transformClassContent(regularClass, data)
}
abstract fun transformClassContent(
firClass: FirClass,
data: FirResolvedDeclarationStatus?
): FirStatement ): FirStatement
override fun transformAnonymousObject( override fun transformAnonymousObject(
anonymousObject: FirAnonymousObject, anonymousObject: FirAnonymousObject,
data: FirResolvedDeclarationStatus? data: FirResolvedDeclarationStatus?
): FirStatement = whileAnalysing(anonymousObject) { ): FirStatement = whileAnalysing(anonymousObject) {
anonymousObject.transformStatus( transformClassContent(anonymousObject, data)
this,
FirResolvedDeclarationStatusImpl(
anonymousObject.status.visibility,
anonymousObject.status.modality ?: Modality.FINAL,
EffectiveVisibility.Local
)
)
@Suppress("UNCHECKED_CAST")
return transformClass(anonymousObject, data)
} }
open fun transformDeclarationContent( open fun transformDeclarationContent(
@@ -329,7 +322,7 @@ abstract class AbstractFirStatusResolveTransformer(
} as FirStatement } as FirStatement
} }
protected fun forceResolveStatusesOfSupertypes(regularClass: FirRegularClass) { protected fun forceResolveStatusesOfSupertypes(regularClass: FirClass) {
for (superTypeRef in regularClass.superTypeRefs) { for (superTypeRef in regularClass.superTypeRefs) {
forceResolveStatusOfCorrespondingClass(superTypeRef) forceResolveStatusOfCorrespondingClass(superTypeRef)
} }
@@ -152,12 +152,15 @@ class FirStatusResolver(
} }
fun resolveStatus( fun resolveStatus(
regularClass: FirRegularClass, firClass: FirClass,
containingClass: FirClass?, containingClass: FirClass?,
isLocal: Boolean isLocal: Boolean
): FirResolvedDeclarationStatus { ): FirResolvedDeclarationStatus {
val status = regularClass.applyExtensionTransformers { transformStatus(it, regularClass, containingClass, isLocal) } val status = when (firClass) {
return resolveStatus(regularClass, status, containingClass, null, isLocal, emptyList()) is FirRegularClass -> firClass.applyExtensionTransformers { transformStatus(it, firClass, containingClass, isLocal) }
else -> firClass.status
}
return resolveStatus(firClass, status, containingClass, null, isLocal, emptyList())
} }
fun resolveStatus( fun resolveStatus(