[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>
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|
}
@@ -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 {
@@ -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");
@@ -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);
}
@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 {
@@ -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 {
@@ -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)
}
@@ -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(