Remove unnecessary f/o in lazy classes WIP
diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt
index 0225cb4..0ce1996 100644
--- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt
+++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/pipeline/convertToIr.kt
@@ -24,7 +24,12 @@
 import org.jetbrains.kotlin.fir.backend.utils.generatedBuiltinsDeclarationsFileName
 import org.jetbrains.kotlin.fir.backend.utils.unsubstitutedScope
 import org.jetbrains.kotlin.fir.declarations.FirFile
+import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
 import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
+import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyProperty
+import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyPropertyAccessor
+import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyPropertyForPureField
+import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction
 import org.jetbrains.kotlin.fir.moduleData
 import org.jetbrains.kotlin.fir.resolve.ScopeSession
 import org.jetbrains.kotlin.fir.scopes.staticScopeForBackend
@@ -39,6 +44,8 @@
 import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase
 import org.jetbrains.kotlin.ir.irFlag
 import org.jetbrains.kotlin.ir.overrides.IrFakeOverrideBuilder
+import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
+import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
 import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
 import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
 import org.jetbrains.kotlin.ir.types.classOrFail
@@ -360,7 +367,7 @@
                 }
             }
             if (clazz is IrLazyDeclarationBase) {
-                buildFakeOverridesForLazyClass(clazz as Fir2IrLazyClass, resolver)
+                resolveOverridenSymbolsInLazyClass(clazz as Fir2IrLazyClass, resolver)
             } else {
                 buildFakeOverridesForClass(clazz, false)
             }
@@ -420,72 +427,40 @@
         }
     }
 
-    @OptIn(UnsafeDuringIrConstructionAPI::class)
-    private fun buildFakeOverridesForLazyClass(
+    private fun resolveOverridenSymbolsInLazyClass(
         clazz: Fir2IrLazyClass,
         resolver: SpecialFakeOverrideSymbolsResolver,
     ) {
-        val declarationStorage = clazz.declarationStorage
-        val lookupTag = clazz.fir.symbol.toLookupTag()
-
-        val allFromSuper = clazz.superTypes.flatMap { superType ->
-            superType.classOrFail.owner.declarations
-        }
-
-        val functionNames = mutableSetOf<Name>()
-        val propertyNames = mutableSetOf<Name>()
-        for (decl in allFromSuper) {
-            when (decl) {
-                is IrSimpleFunction -> functionNames.add(decl.name)
-                is IrProperty -> propertyNames.add(decl.name)
-            }
-        }
-
-        listOfNotNull(
-            clazz.fir.unsubstitutedScope(clazz),
-            clazz.fir.staticScopeForBackend(clazz.session, clazz.scopeSession)
-        ).forEach { scope ->
-            for (name in functionNames) {
-                scope.processFunctionsByName(name) { function ->
-                    val declaration = declarationStorage.getIrFunctionSymbol(function, lookupTag).owner as IrSimpleFunction
+        /*
+         * Eventually, we should be able to process lazy classes with the same code.
+         *
+         * Now we can't do this, because overriding by Java function is not supported correctly in IR builder.
+         * In most cases, nothing need to be done for lazy classes. For other cases, it is
+         * caller responsibility to handle them.
+         *
+         * Super-classes already have processed fake overrides at this moment.
+         * Also, all Fir2IrLazyClass super-classes are always platform classes,
+         * so it's valid to process it with empty expect-actual mapping.
+         *
+         * But this is still a hack, and should be removed within KT-64352
+         */
+        @OptIn(UnsafeDuringIrConstructionAPI::class)
+        for (declaration in clazz.declarations) {
+            when (declaration) {
+                is IrSimpleFunction -> {
                     declaration.overriddenSymbols = declaration.overriddenSymbols.map { resolver.getReferencedSimpleFunction(it) }
                 }
-            }
-            for (name in propertyNames) {
-                scope.processPropertiesByName(name) { property ->
-                    if (property is FirPropertySymbol) {
-                        val declaration = declarationStorage.getIrPropertySymbol(property, lookupTag).owner as IrProperty
-                        declaration.overriddenSymbols = declaration.overriddenSymbols.map { resolver.getReferencedProperty(it) }
-                        declaration.getter?.let { getter ->
-                            getter.overriddenSymbols = getter.overriddenSymbols.map { resolver.getReferencedSimpleFunction(it) }
-                        }
-                        declaration.setter?.let { setter ->
-                            setter.overriddenSymbols = setter.overriddenSymbols.map { resolver.getReferencedSimpleFunction(it) }
-                        }
+                is IrProperty -> {
+                    declaration.overriddenSymbols = declaration.overriddenSymbols.map { resolver.getReferencedProperty(it) }
+                    declaration.getter?.let { getter ->
+                        getter.overriddenSymbols = getter.overriddenSymbols.map { resolver.getReferencedSimpleFunction(it) }
+                    }
+                    declaration.setter?.let { setter ->
+                        setter.overriddenSymbols = setter.overriddenSymbols.map { resolver.getReferencedSimpleFunction(it) }
                     }
                 }
             }
         }
-
-        /*for (decl in allFromSuper) {
-            when (decl) {
-                is IrSimpleFunction -> {
-                    decl as Fir2IrLazySimpleFunction
-
-                    scope.processOverriddenFunctionsAndSelf(decl.fir.symbol) { func ->
-                        fakeOverrides += declarationStorage.getIrFunctionSymbol(func, lookupTag).owner as IrSimpleFunction
-                        ProcessorAction.NEXT
-                    }
-                }
-                is IrProperty -> {
-                    decl as Fir2IrLazyProperty
-                    scope.processOverriddenProperties(decl.fir.symbol) { property ->
-                        fakeOverrides += declarationStorage.getIrPropertySymbol(property, lookupTag).owner as IrProperty
-                        ProcessorAction.NEXT
-                    }
-                }
-            }
-        }*/
     }
 
 
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 d5e3052..555f5cd 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
@@ -5,41 +5,36 @@
 
 package org.jetbrains.kotlin.fir.backend
 
-import org.jetbrains.kotlin.builtins.StandardNames
 import org.jetbrains.kotlin.descriptors.ClassKind
 import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
 import org.jetbrains.kotlin.descriptors.Visibilities
 import org.jetbrains.kotlin.descriptors.Visibility
 import org.jetbrains.kotlin.fir.backend.generators.addDeclarationToParent
 import org.jetbrains.kotlin.fir.backend.generators.isExternalParent
-import org.jetbrains.kotlin.fir.backend.generators.isFakeOverride
 import org.jetbrains.kotlin.fir.backend.utils.ConversionTypeOrigin
 import org.jetbrains.kotlin.fir.backend.utils.unsubstitutedScope
 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.originalOrSelf
 import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
 import org.jetbrains.kotlin.fir.resolve.toClassSymbol
-import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
-import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
-import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
-import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
-import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
+import org.jetbrains.kotlin.fir.scopes.collectAllFunctions
 import org.jetbrains.kotlin.fir.scopes.staticScopeForBackend
+import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
+import org.jetbrains.kotlin.fir.symbols.impl.*
+import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
 import org.jetbrains.kotlin.fir.types.ConeClassLikeLookupTag
 import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
 import org.jetbrains.kotlin.ir.declarations.*
 import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
 import org.jetbrains.kotlin.ir.symbols.*
 import org.jetbrains.kotlin.ir.symbols.impl.*
-import org.jetbrains.kotlin.ir.util.isEnumClass
-import org.jetbrains.kotlin.ir.util.isObject
-import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.ir.util.classIdOrFail
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.name.SpecialNames
 import org.jetbrains.kotlin.name.StandardClassIds
+import org.jetbrains.kotlin.utils.addIfNotNull
 import org.jetbrains.kotlin.utils.addToStdlib.runIf
 import java.util.concurrent.ConcurrentHashMap
 
@@ -69,6 +64,7 @@
     )
 
     private val localClassesCreatedOnTheFly: MutableMap<FirClass, IrClass> = mutableMapOf()
+    private val lazyClassesToInitializeMembers = ArrayDeque<Fir2IrLazyClass>()
 
     /**
      * This function is quite messy and doesn't have a good contract of what exactly is traversed.
@@ -230,40 +226,72 @@
 
         classCache[firClass] = symbol
         check(irParent.isExternalParent()) { "Source classes should be created separately before referencing" }
+        getIrClassRecursionLevel++
         val irClass = lazyDeclarationsGenerator.createIrLazyClass(firClass, irParent, symbol)
         addDeclarationToParent(irClass, irParent)
-        initializeLazyIrClassDeclarations(classId, irClass)
+
+        lazyClassesToInitializeMembers.add(irClass)
+        if (--getIrClassRecursionLevel == 0) {
+            processMembersOfLazyClasses()
+        }
+
         return irClass
     }
 
+    private var getIrClassRecursionLevel = 0
+
+    private fun processMembersOfLazyClasses() {
+        while (true) {
+            val irClass = lazyClassesToInitializeMembers.removeFirstOrNull() ?: break
+            initializeLazyIrClassDeclarations(irClass)
+        }
+    }
+
     @OptIn(UnsafeDuringIrConstructionAPI::class)
-    private fun initializeLazyIrClassDeclarations(classId: ClassId, irClass: Fir2IrLazyClass) {
-        if (classId.packageFqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME) {
+    private fun initializeLazyIrClassDeclarations(irClass: Fir2IrLazyClass) {
+        val classId = irClass.classIdOrFail
+        if (classId.packageFqName.startsWith(Name.identifier("kotlin"))) {
             irClass.computeAllDeclarations()
         } else {
             val lookupTag = irClass.fir.symbol.toLookupTag()
 
-            val callableNames = when (irClass.kind) {
-                ClassKind.ENUM_CLASS ->
-                    Fir2IrDeclarationStorage.ENUM_SYNTHETIC_NAMES.keys
-                ClassKind.INTERFACE -> {
-                    val functions = irClass.fir.declarations.filterIsInstance<FirSimpleFunction>()
-                    val sam = functions.singleOrNull { it.isAbstract }
-                    setOfNotNull(sam?.name)
-                }
-                else -> emptySet()
+            val functionNames = mutableSetOf<Name>()
+            val propertyNames = mutableSetOf<Name>()
+            if (irClass.kind == ClassKind.ENUM_CLASS || classId == StandardClassIds.Enum) {
+                propertyNames += listOf("name", "ordinal", "entries")
+                    .map { Name.identifier(it) }
+                functionNames += listOf("values", "valueOf")
+                    .map { Name.identifier(it) }
+            }
+            if (irClass.kind == ClassKind.INTERFACE) {
+                /*val callableNames = scope.getCallableNames()
+                val singleCallableName = callableNames.singleOrNull()
+                if (singleCallableName != null) {
+                    val singleCallable = scope.getFunctions(singleCallableName).singleOrNull()
+                    if (singleCallable != null && singleCallable.isAbstract) {
+                        functionNames += singleCallable.name
+                    }
+                }*/
+
+                //val functions = irClass.fir.declarations.filterIsInstance<FirSimpleFunction>()
+                val scope = irClass.fir.unsubstitutedScope(c.session, c.scopeSession, withForcedTypeCalculator = false, memberRequiredPhase = null)
+                val functions = scope.collectAllFunctions()
+                val sam = functions.singleOrNull { it.isAbstract }
+                functionNames.addIfNotNull(sam?.name)
             }
 
-            if (callableNames.isNotEmpty()) {
+            if (functionNames.isNotEmpty() || propertyNames.isNotEmpty()) {
                 listOfNotNull(
                     irClass.fir.unsubstitutedScope(c),
                     irClass.fir.staticScopeForBackend(session, scopeSession),
                 ).forEach { scope ->
-                    for (name in callableNames) {
+                    for (name in functionNames) {
                         scope.processFunctionsByName(name) { symbol ->
                             declarationStorage.getIrFunctionSymbol(symbol, lookupTag)
                         }
+                    }
 
+                    for (name in propertyNames) {
                         scope.processPropertiesByName(name) { property ->
                             if (property is FirPropertySymbol) {
                                 declarationStorage.getIrPropertySymbol(property, lookupTag)
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt
index 6cd8e4d..a8690fe 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt
@@ -20,11 +20,14 @@
 import org.jetbrains.kotlin.fir.declarations.utils.*
 import org.jetbrains.kotlin.fir.descriptors.FirBuiltInsPackageFragment
 import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
+import org.jetbrains.kotlin.fir.lazy.AbstractFir2IrLazyDeclaration
+import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
 import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyConstructor
 import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyProperty
 import org.jetbrains.kotlin.fir.lazy.Fir2IrLazySimpleFunction
 import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
 import org.jetbrains.kotlin.fir.resolve.getContainingClass
+import org.jetbrains.kotlin.fir.resolve.isSubclassOf
 import org.jetbrains.kotlin.fir.resolve.providers.firProvider
 import org.jetbrains.kotlin.fir.resolve.toClassSymbol
 import org.jetbrains.kotlin.fir.resolve.toRegularClassSymbol
@@ -36,6 +39,7 @@
 import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
 import org.jetbrains.kotlin.ir.declarations.*
 import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.Companion.FILLED_FOR_UNBOUND_SYMBOL
+import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
 import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
 import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind
 import org.jetbrains.kotlin.ir.irFlag
@@ -43,6 +47,7 @@
 import org.jetbrains.kotlin.ir.symbols.impl.*
 import org.jetbrains.kotlin.ir.types.IrType
 import org.jetbrains.kotlin.ir.types.classOrNull
+import org.jetbrains.kotlin.ir.types.getClass
 import org.jetbrains.kotlin.ir.util.createThisReceiverParameter
 import org.jetbrains.kotlin.ir.util.render
 import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
@@ -53,6 +58,7 @@
 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability
 import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
 import org.jetbrains.kotlin.util.OperatorNameConventions
+import org.jetbrains.kotlin.utils.DFS
 import org.jetbrains.kotlin.utils.addToStdlib.runIf
 import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
 import org.jetbrains.kotlin.utils.exceptions.ExceptionAttachmentBuilder
@@ -654,13 +660,28 @@
         return getIrPropertySymbols(firPropertySymbol, fakeOverrideOwnerLookupTag).propertySymbol
     }
 
+    @OptIn(UnsafeDuringIrConstructionAPI::class)
     private fun getIrPropertySymbols(
         firPropertySymbol: FirPropertySymbol,
         fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
     ): PropertySymbols {
         val property = prepareProperty(firPropertySymbol.fir)
         getCachedIrPropertySymbols(property, fakeOverrideOwnerLookupTag)?.let { return it }
-        return createAndCacheIrPropertySymbols(property, fakeOverrideOwnerLookupTag)
+        val symbols = createAndCacheIrPropertySymbols(property, fakeOverrideOwnerLookupTag)
+
+        resolveLazyFakeOverrides(property.symbol, symbols.propertySymbol) { symbol, lookupTag -> getIrPropertySymbol(symbol, lookupTag) }
+        (symbols.propertySymbol as? IrPropertySymbolImpl)?.ownerIfBound()?.let { irProperty ->
+            irProperty.getter?.let { accessor ->
+                @OptIn(UnsafeDuringIrConstructionAPI::class)
+                accessor.overriddenSymbols = irProperty.overriddenSymbols.mapNotNull { it.owner.getter?.symbol }
+            }
+            irProperty.setter?.let { accessor ->
+                @OptIn(UnsafeDuringIrConstructionAPI::class)
+                accessor.overriddenSymbols = irProperty.overriddenSymbols.mapNotNull { it.owner.setter?.symbol }
+            }
+        }
+
+        return symbols
     }
 
     private fun createAndCacheIrPropertySymbols(
@@ -1089,6 +1110,7 @@
         }
     }
 
+    @OptIn(UnsafeDuringIrConstructionAPI::class)
     fun getIrFunctionSymbol(
         firFunctionSymbol: FirFunctionSymbol<*>,
         fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
@@ -1101,6 +1123,20 @@
         }
 
         getCachedIrFunctionSymbol(function, fakeOverrideOwnerLookupTag)?.let { return it }
+
+        val symbol = createIrFunction(function, isLocal, fakeOverrideOwnerLookupTag)
+        cacheIrFunctionSymbol(function, symbol, fakeOverrideOwnerLookupTag)
+
+        resolveLazyFakeOverrides(firFunctionSymbol, symbol, ::getIrFunctionSymbol)
+
+        return symbol
+    }
+
+    private fun createIrFunction(
+        function: FirFunction,
+        isLocal: Boolean,
+        fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag?,
+    ): IrSimpleFunctionSymbol {
         if (function is FirSimpleFunction && !isLocal) {
             val irParent = findIrParent(function, fakeOverrideOwnerLookupTag)
             if (irParent?.isExternalParent() == true) {
@@ -1121,14 +1157,11 @@
                 ).also {
                     check(it is Fir2IrLazySimpleFunction)
                 }
-                cacheIrFunctionSymbol(function, symbol, fakeOverrideOwnerLookupTag)
                 return symbol
             }
         }
 
-        val symbol = createMemberFunctionSymbol(function, fakeOverrideOwnerLookupTag, parentIsExternal = false)
-        cacheIrFunctionSymbol(function, symbol, fakeOverrideOwnerLookupTag)
-        return symbol
+        return createMemberFunctionSymbol(function, fakeOverrideOwnerLookupTag, parentIsExternal = false)
     }
 
     private inline fun <reified FC : FirCallableDeclaration, reified IS : IrSymbol> getCachedIrCallableSymbol(
@@ -1405,6 +1438,60 @@
         )
     }
 
+    @OptIn(UnsafeDuringIrConstructionAPI::class)
+    private inline fun <reified F : FirCallableDeclaration, reified S : FirCallableSymbol<F>> resolveLazyFakeOverrides(
+        firSymbol: S,
+        irSymbol: IrSymbol,
+        getIrSymbol: (S, ConeClassLikeLookupTag?) -> IrSymbol,
+    ) {
+        val realDeclaration = firSymbol.fir.unwrapFakeOverrides()
+        val realIrParent = findIrParent(realDeclaration, null)
+        if (realIrParent is Fir2IrLazyClass) {
+            val bottomLevelLazyClasses = when (irSymbol) {
+                is IrFakeOverrideSymbolBase<*, *, *> -> {
+                    val lookupTag = realDeclaration.containingClassLookupTag() ?: return
+
+                    @OptIn(UnsafeDuringIrConstructionAPI::class)
+                    val containingClass = irSymbol.containingClassSymbol.owner
+                    DFS.topologicalOrder(listOf(containingClass)) { it.superTypes.mapNotNull { it.getClass() as? IrClassImpl } }
+                        .flatMap { it.superTypes.mapNotNull { it.getClass() } }
+                        .filterIsInstance<Fir2IrLazyClass>()
+                        .filter { it.fir.isSubclassOf(lookupTag, session, isStrict = false) }
+                        .map { it.fir.symbol.toLookupTag() }
+                }
+                is IrSymbolBase<*, *> -> {
+                    @Suppress("UNCHECKED_CAST")
+                    val lazyDeclaration = (irSymbol.owner as AbstractFir2IrLazyDeclaration<F>).fir.symbol as S
+                    val thisClass = lazyDeclaration.containingClassLookupTag() ?: return
+
+                    var fakeOverridden = lazyDeclaration
+                    var fakeOverriddenClass: ConeClassLikeLookupTag? = null
+                    while (true) {
+                        fakeOverridden = fakeOverridden.originalIfFakeOverride() ?: break
+                        val upperClass = fakeOverridden.containingClassLookupTag() ?: break
+                        if (upperClass != thisClass) {
+                            fakeOverriddenClass = upperClass
+                            break
+                        }
+                    }
+
+                    listOfNotNull(fakeOverriddenClass)
+                }
+                else -> error(irSymbol)
+            }
+
+            val allOverridden = bottomLevelLazyClasses.map {
+                getIrSymbol(realDeclaration.symbol as S, it)
+            }
+            if (irSymbol is IrSymbolBase<*, *>) {
+                check(irSymbol !in allOverridden) { "irSymbol in allOverridden - $irSymbol" }
+                @Suppress("UNCHECKED_CAST")
+                val irDeclaration = irSymbol.owner as IrOverridableDeclaration<IrSymbol>
+                irDeclaration.overriddenSymbols = allOverridden
+            }
+        }
+    }
+
     companion object {
         internal val ENUM_SYNTHETIC_NAMES = mapOf(
             Name.identifier("values") to IrSyntheticBodyKind.ENUM_VALUES,
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyFakeOverrideGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyFakeOverrideGenerator.kt
index e4ffda2..e19bc04 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyFakeOverrideGenerator.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrLazyFakeOverrideGenerator.kt
@@ -36,7 +36,7 @@
      *
      * For detailed examples see the documentation to [computeFakeOverrideKeysImpl]
      */
-    internal fun computeFakeOverrideKeys(
+    fun computeFakeOverrideKeys(
         klass: FirClass,
         originalFunction: FirNamedFunctionSymbol,
     ): List<Pair<FirNamedFunctionSymbol, ConeClassLikeLookupTag>> {
@@ -60,7 +60,7 @@
      *
      * For detailed examples see the documentation to [computeFakeOverrideKeysImpl]
      */
-    internal fun computeFakeOverrideKeys(
+    fun computeFakeOverrideKeys(
         klass: FirClass,
         originalProperty: FirPropertySymbol,
     ): List<Pair<FirPropertySymbol, ConeClassLikeLookupTag>> {
@@ -83,7 +83,7 @@
      *
      * For detailed examples see the documentation to [computeFakeOverrideKeysImpl]
      */
-    internal fun computeFakeOverrideKeys(
+    fun computeFakeOverrideKeys(
         klass: FirClass,
         originalField: FirFieldSymbol,
     ): List<Pair<FirFieldSymbol, ConeClassLikeLookupTag>> {
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt
index da93d26..416c352 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyClass.kt
@@ -159,6 +159,8 @@
     //@UnsafeDuringIrConstructionAPI
     @OptIn(UnsafeDuringIrConstructionAPI::class)
     fun computeAllDeclarations(): List<IrDeclaration> {
+        computedDeclarationsNeededForSubclasses = true
+
         val result = mutableListOf<IrDeclaration>()
         // NB: it's necessary to take all callables from scope,
         // e.g. to avoid accessing un-enhanced Java declarations with FirJavaTypeRef etc. inside
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt
index 344c157..c2d4b23 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt
@@ -297,15 +297,7 @@
         declarationStorage.leaveScope(accessor.symbol)
     }
 
-    override var overriddenSymbols: List<IrPropertySymbol> by symbolsMappingForLazyClasses.lazyMappedPropertyListVar(lock) lazy@{
-        if (containingClass == null || parent !is Fir2IrLazyClass) return@lazy emptyList()
-
-        val baseFunctionWithDispatchReceiverTag =
-            lazyFakeOverrideGenerator.computeFakeOverrideKeys(containingClass, fir.symbol)
-        baseFunctionWithDispatchReceiverTag.map { (symbol, dispatchReceiverLookupTag) ->
-            declarationStorage.getIrPropertySymbol(symbol, dispatchReceiverLookupTag) as IrPropertySymbol
-        }
-    }
+    override var overriddenSymbols: List<IrPropertySymbol> = emptyList()
 
     override var metadata: MetadataSource?
         get() = null
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyAccessor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyAccessor.kt
index 754bd29..c2b2b4f 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyAccessor.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyAccessor.kt
@@ -64,34 +64,7 @@
         if (isSetter) builtins.unitType else firParentProperty.returnTypeRef.toIrType(typeConverter, conversionTypeContext)
     }
 
-    override var overriddenSymbols: List<IrSimpleFunctionSymbol> by symbolsMappingForLazyClasses.lazyMappedFunctionListVar(lock) {
-        if (firParentClass == null) return@lazyMappedFunctionListVar emptyList()
-        // If property accessor is created then corresponding property is definitely created too
-        @OptIn(UnsafeDuringIrConstructionAPI::class)
-        val correspondingProperty = correspondingPropertySymbol!!.owner
-        correspondingProperty.overriddenSymbols.mapNotNull {
-            /*
-             * Calculation of overridden symbols for lazy accessor may be called
-             * 1. during fir2ir transformation
-             * 2. somewhere in the backend, after fake-overrides were built
-             *
-             * In the first case declarationStorage knows about all symbols, so we always can search for accessor symbol in it
-             * But in the second case property symbols for fake-overrides are replaced with real one (in f/o generator) and
-             *   declarationStorage has no information about it. But at this point all symbols are already bound. So we can
-             *   just access the corresponding accessor using owner of the symbol
-             */
-            when {
-                it.isBound -> @OptIn(UnsafeDuringIrConstructionAPI::class) when (isSetter) {
-                    false -> it.owner.getter?.symbol
-                    true -> it.owner.setter?.symbol
-                }
-                else -> when (isSetter) {
-                    false -> declarationStorage.findGetterOfProperty(it)
-                    true -> declarationStorage.findSetterOfProperty(it)
-                }
-            }
-        }
-    }
+    override var overriddenSymbols: List<IrSimpleFunctionSymbol> = emptyList()
 
     override val initialSignatureFunction: IrFunction? by lazy {
         val originalFirFunction = (fir as? FirSyntheticPropertyAccessor)?.delegate ?: return@lazy null
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyForPureField.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyForPureField.kt
index a42d33e..7505811 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyForPureField.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyPropertyForPureField.kt
@@ -22,7 +22,7 @@
 
 class Fir2IrLazyPropertyForPureField(
     private val c: Fir2IrComponents,
-    private val field: Fir2IrLazyField,
+    val field: Fir2IrLazyField,
     override val symbol: IrPropertySymbol,
     parent: IrDeclarationParent
 ) : IrProperty(), Fir2IrComponents by c {
@@ -31,15 +31,7 @@
         symbol.bind(this)
     }
 
-    override var overriddenSymbols: List<IrPropertySymbol> by symbolsMappingForLazyClasses.lazyMappedPropertyListVar(lock) lazy@{
-        val containingClass = field.containingClass ?: return@lazy emptyList()
-
-        val baseFieldsWithDispatchReceiverTag =
-            lazyFakeOverrideGenerator.computeFakeOverrideKeys(containingClass, field.fir.symbol)
-        baseFieldsWithDispatchReceiverTag.map { (symbol, dispatchReceiverLookupTag) ->
-            declarationStorage.getIrSymbolForField(symbol, dispatchReceiverLookupTag) as IrPropertySymbol
-        }
-    }
+    override var overriddenSymbols: List<IrPropertySymbol> = emptyList()
 
     override var annotations: List<IrConstructorCall>
         get() = emptyList()
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt
index 9e38803..0c69968 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazySimpleFunction.kt
@@ -27,7 +27,7 @@
     endOffset: Int,
     origin: IrDeclarationOrigin,
     override val fir: FirSimpleFunction,
-    private val firParent: FirRegularClass?,
+    val firParent: FirRegularClass?,
     symbol: IrSimpleFunctionSymbol,
     parent: IrDeclarationParent,
     isFakeOverride: Boolean
@@ -48,15 +48,7 @@
         fir.symbol.resolvedReturnTypeRef.toIrType(typeConverter)
     }
 
-    override var overriddenSymbols: List<IrSimpleFunctionSymbol> by symbolsMappingForLazyClasses.lazyMappedFunctionListVar(lock) lazy@{
-        if (firParent == null || parent !is Fir2IrLazyClass) return@lazy emptyList()
-
-        val baseFunctionWithDispatchReceiverTag =
-            lazyFakeOverrideGenerator.computeFakeOverrideKeys(firParent, fir.symbol)
-        baseFunctionWithDispatchReceiverTag.map { (symbol, dispatchReceiverLookupTag) ->
-            declarationStorage.getIrFunctionSymbol(symbol, dispatchReceiverLookupTag) as IrSimpleFunctionSymbol
-        }
-    }
+    override var overriddenSymbols: List<IrSimpleFunctionSymbol> = emptyList()
 
     override val initialSignatureFunction: IrFunction? by lazy {
         val originalFunction = fir.initialSignatureAttr ?: return@lazy null