FIR2IR: fix processing of classes created on the fly

finding local parent and create it on the fly, instead of the requested
class.
avoiding double processing of class members and properly handling
"innerness"
fixes localClassMetadata test problem with propLocal.<>.D
This commit is contained in:
Ilya Chernikov
2022-08-03 16:00:54 +02:00
parent dfa1e8d03d
commit 982ab8beac
@@ -7,10 +7,12 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.containingClassForLocalAttr
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
@@ -203,22 +205,34 @@ class Fir2IrClassifierStorage(
// This function is called when we refer local class earlier than we reach its declaration
// This can happen e.g. when implicit return type has a local class constructor
private fun createLocalIrClassOnTheFly(klass: FirClass): IrClass {
val result = when (klass) {
is FirAnonymousObject -> createIrAnonymousObject(klass, irParent = temporaryParent).apply {
converter.processAnonymousObjectOnTheFly(klass, this)
// finding the parent class that actually contains the [klass] in the tree - it is the root one that should be created on the fly
val classOrLocalParent = generateSequence(klass) { c ->
(c as? FirRegularClass)?.containingClassForLocalAttr?.let {
(firProvider.symbolProvider.getSymbolByLookupTag(it)?.fir as? FirClass)?.takeIf {
it.declarations.contains(c)
}
}
}.last()
val result = when (classOrLocalParent) {
is FirAnonymousObject -> createIrAnonymousObject(classOrLocalParent, irParent = temporaryParent).apply {
converter.processAnonymousObjectOnTheFly(classOrLocalParent, this)
}
is FirRegularClass -> {
converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, temporaryParent)
}
is FirRegularClass -> converter.processLocalClassAndNestedClassesOnTheFly(klass, temporaryParent)
}
// Note: usually member creation and f/o binding is delayed till non-local classes are processed in Fir2IrConverter
// If non-local classes are already created (this means we are in body translation) we do everything immediately
// The last variant is possible for local variables like 'val a = object : Any() { ... }'
if (processMembersOfClassesOnTheFlyImmediately) {
processMembersOfClassCreatedOnTheFly(klass, result)
processMembersOfClassCreatedOnTheFly(classOrLocalParent, result)
converter.bindFakeOverridesInClass(result)
} else {
localClassesCreatedOnTheFly[klass] = result
localClassesCreatedOnTheFly[classOrLocalParent] = result
}
return result
return if (classOrLocalParent === klass) result
else (getCachedIrClass(klass)
?: error("Assuming that all nested classes of ${classOrLocalParent.classId.asString()} should already be cached"))
}
// Note: this function is called exactly once, right after Fir2IrConverter finished f/o binding for regular classes