~ tmp37 ~ 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
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt
index 8c5537d..ffc38e7 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt
@@ -6,10 +6,12 @@
package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.descriptors.*
+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
@@ -202,22 +204,34 @@
// 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)
+ }
}
- is FirRegularClass -> converter.processLocalClassAndNestedClassesOnTheFly(klass, temporaryParent)
+ }.last()
+ val result = when (classOrLocalParent) {
+ is FirAnonymousObject -> createIrAnonymousObject(classOrLocalParent, irParent = temporaryParent).apply {
+ converter.processAnonymousObjectOnTheFly(classOrLocalParent, this)
+ }
+ is FirRegularClass -> {
+ converter.processLocalClassAndNestedClassesOnTheFly(classOrLocalParent, 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
diff --git a/js/js.translator/testData/box/multiModule/localClassMetadata.kt b/js/js.translator/testData/box/multiModule/localClassMetadata.kt
index 4f96042..e9ca9e0 100644
--- a/js/js.translator/testData/box/multiModule/localClassMetadata.kt
+++ b/js/js.translator/testData/box/multiModule/localClassMetadata.kt
@@ -65,6 +65,7 @@
}
// MODULE: main(lib)
+// NO_COMMON_FILES
// FILE: main.kt
fun box(): String {
val result = C().test()