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:
+21
-7
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user