[KLIB] Add FakeOverrideSignature take 2

#KT-72296 Fixed
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ic/FileSignatureRemover.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ic/FileSignatureRemover.kt
index 6e837cd..b44bdf9 100644
--- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ic/FileSignatureRemover.kt
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ic/FileSignatureRemover.kt
@@ -19,6 +19,8 @@
     is IdSignature.LocalSignature -> false
     is IdSignature.LoweredDeclarationSignature -> original.containsFileSignature(moduleName)
     is IdSignature.ScopeLocalDeclaration -> false
+    is IdSignature.FakeOverrideSignature ->
+        containerClass.containsFileSignature(moduleName)
     is IdSignature.SpecialFakeOverrideSignature ->
         memberSignature.containsFileSignature(moduleName) || overriddenSignatures.any { it.containsFileSignature(moduleName) }
     is IdSignature.FileSignature -> true
@@ -32,6 +34,7 @@
     is IdSignature.LocalSignature -> this
     is IdSignature.LoweredDeclarationSignature -> rebuildSignature(moduleName)
     is IdSignature.ScopeLocalDeclaration -> this
+    is IdSignature.FakeOverrideSignature -> rebuildSignature(moduleName)
     is IdSignature.SpecialFakeOverrideSignature -> rebuildSignature(moduleName)
     is IdSignature.FileSignature -> rebuildSignature(moduleName)
 }
@@ -48,6 +51,11 @@
 private fun IdSignature.LoweredDeclarationSignature.rebuildSignature(moduleName: String): IdSignature =
     IdSignature.LoweredDeclarationSignature(original.rebuildSignature(moduleName), stage, index)
 
+private fun IdSignature.FakeOverrideSignature.rebuildSignature(moduleName: String): IdSignature =
+    IdSignature.FakeOverrideSignature(
+        containerClass.rebuildSignature(moduleName),
+        id, mask, description
+    )
 
 private fun IdSignature.SpecialFakeOverrideSignature.rebuildSignature(moduleName: String): IdSignature =
     IdSignature.SpecialFakeOverrideSignature(
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/serialization/WasmSerializer.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/serialization/WasmSerializer.kt
index 2391b48..f85f170 100644
--- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/serialization/WasmSerializer.kt
+++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/serialization/WasmSerializer.kt
@@ -440,6 +440,7 @@
             is IdSignature.LocalSignature -> withTag(IdSignatureTags.LOCAL) { serializeLocalSignature(idSignature) }
             is IdSignature.LoweredDeclarationSignature -> withTag(IdSignatureTags.LOWERED_DECLARATION) { serializeLoweredDeclarationSignature(idSignature) }
             is IdSignature.ScopeLocalDeclaration -> withTag(IdSignatureTags.SCOPE_LOCAL_DECLARATION) { serializeScopeLocalDeclaration(idSignature) }
+            is IdSignature.FakeOverrideSignature -> TODO("FakeOverrideSignature deserialization")
             is IdSignature.SpecialFakeOverrideSignature -> withTag(IdSignatureTags.SPECIAL_FAKE_OVERRIDE) { serializeSpecialFakeOverrideSignature(idSignature) }
             is IdSignature.FileSignature -> withTag(IdSignatureTags.FILE) { serializeString(idSignature.fileName) }
         }
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignature.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignature.kt
index 392b8c4..373497d 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignature.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignature.kt
@@ -490,6 +490,33 @@
         }
     }
 
+    data class FakeOverrideSignature(
+        val containerClass: IdSignature,
+        val id: Long,
+        val mask: Long,
+        val description: String?,
+    ) : IdSignature() {
+        override val isPubliclyVisible: Boolean
+            get() = containerClass.isPubliclyVisible
+
+        override val visibleCrossFile: Boolean
+            get() = containerClass.visibleCrossFile
+
+        override val isLocal: Boolean
+            get() = containerClass.visibleCrossFile
+
+        override fun topLevelSignature() =
+            containerClass.topLevelSignature()
+
+        override fun nearestPublicSig() =
+            if (isPubliclyVisible)
+                this
+            else
+                containerClass.nearestPublicSig()
+
+        override fun packageFqName() = containerClass.packageFqName()
+    }
+
     /**
      * [KT-42020](https://youtrack.jetbrains.com/issue/KT-42020)
      *
@@ -556,8 +583,7 @@
      * This signature is not navigatable through files.
      *
      * @property id An ordered index of the declaration inside the file.
-     *   **Important**: For fake overrides, this is the hash of the mangle name.
-     *   TODO: Consider using specialized signatures for local fake overrides, KT-72296
+     * In ABI version prior to 2.2.0, for fake overrides this is the hash of the mangle name.
      */
     class FileLocalSignature(val container: IdSignature, val id: Long, val description: String? = null) : IdSignature() {
         override val isPubliclyVisible: Boolean get() = false
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignatureRenderer.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignatureRenderer.kt
index 1a5dec2..f3bc70f 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignatureRenderer.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IdSignatureRenderer.kt
@@ -18,6 +18,7 @@
         is IdSignature.LocalSignature -> render(signature)
         is IdSignature.FileLocalSignature -> render(signature)
         is IdSignature.ScopeLocalDeclaration -> render(signature)
+        is IdSignature.FakeOverrideSignature -> render(signature)
         is IdSignature.SpecialFakeOverrideSignature -> render(signature)
         is IdSignature.LoweredDeclarationSignature -> render(signature)
     }
@@ -54,6 +55,13 @@
         renderDescriptionForLocalSignature(description) // Always include description for local signatures if there is any.
     }
 
+    private fun StringBuilder.render(signature: IdSignature.FakeOverrideSignature): StringBuilder = with(signature) {
+        append("(FO) ")
+        append(if (showDescriptionForPublicSignatures) signature.description ?: id else id)
+        append('[').append(mask.toString(2)).append(']')
+        append(" in class ").append(containerClass)
+    }
+
     private fun StringBuilder.render(signature: IdSignature.SpecialFakeOverrideSignature): StringBuilder =
         render(signature.memberSignature)
 
diff --git a/compiler/ir/serialization.common/src/KotlinIr.proto b/compiler/ir/serialization.common/src/KotlinIr.proto
index 82e02d4..5261f32f 100644
--- a/compiler/ir/serialization.common/src/KotlinIr.proto
+++ b/compiler/ir/serialization.common/src/KotlinIr.proto
@@ -44,6 +44,13 @@
   optional int32 debug_info = 5;
 }
 
+message FakeOverrideSignature {
+  required int32 container_class = 1;
+  required int64 member_uniq_id = 2;
+  optional int64 flags = 3 [default = 0];
+  optional int32 debug_info = 4;
+}
+
 message FileLocalIdSignature {
   required int32 container = 1;
   required int64 local_id = 2;
@@ -69,6 +76,7 @@
     FileLocalIdSignature private_sig = 2;
     AccessorIdSignature accessor_sig = 3;
     int32 scoped_local_sig = 4;
+    FakeOverrideSignature fake_override_sig = 8;
     CompositeSignature composite_sig = 5;
     LocalSignature local_sig = 6;
     FileSignature file_sig = 7;
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IdSignatureDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IdSignatureDeserializer.kt
index f0b064a..5929e8c 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IdSignatureDeserializer.kt
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IdSignatureDeserializer.kt
@@ -11,6 +11,7 @@
 import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.CommonIdSignature as ProtoCommonIdSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.CompositeSignature as ProtoCompositeSignature
+import org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature as ProtoFakeOverrideSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.FileLocalIdSignature as ProtoFileLocalIdSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.FileSignature as ProtoFileSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature as ProtoIdSignature
@@ -85,6 +86,13 @@
         return IdSignature.CompositeSignature(containerSig, innerSig)
     }
 
+    private fun deserializeFakeOverrideSignature(proto: ProtoFakeOverrideSignature): IdSignature.FakeOverrideSignature {
+        val containerClass = deserializeIdSignature(proto.containerClass)
+        val memberId = proto.memberUniqId
+        val description = if (proto.hasDebugInfo()) libraryFile.debugInfo(proto.debugInfo)?.let(irInterner::string) else null
+        return IdSignature.FakeOverrideSignature(containerClass, memberId, proto.flags, description)
+    }
+
     private fun deserializeLocalIdSignature(proto: ProtoLocalSignature): IdSignature.LocalSignature {
         val localFqn = irInterner.string(libraryFile.deserializeFqName(proto.localFqNameList))
         val localHash = if (proto.hasLocalHash()) proto.localHash else null
@@ -102,6 +110,7 @@
             ProtoIdSignature.IdSigCase.PRIVATE_SIG -> deserializeFileLocalIdSignature(proto.privateSig)
             ProtoIdSignature.IdSigCase.SCOPED_LOCAL_SIG -> deserializeScopeLocalIdSignature(proto.scopedLocalSig)
             ProtoIdSignature.IdSigCase.COMPOSITE_SIG -> deserializeCompositeIdSignature(proto.compositeSig)
+            ProtoIdSignature.IdSigCase.FAKE_OVERRIDE_SIG -> deserializeFakeOverrideSignature(proto.fakeOverrideSig)
             ProtoIdSignature.IdSigCase.LOCAL_SIG -> deserializeLocalIdSignature(proto.localSig)
             ProtoIdSignature.IdSigCase.FILE_SIG -> deserializeFileIdSignature(proto.fileSig)
             else -> error("Unexpected IdSignature kind: ${proto.idSigCase}")
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IdSignatureSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IdSignatureSerializer.kt
index 37ded0d..e1b30fbc 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IdSignatureSerializer.kt
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IdSignatureSerializer.kt
@@ -8,6 +8,7 @@
 import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.CommonIdSignature as ProtoCommonIdSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.CompositeSignature as ProtoCompositeSignature
+import org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature as ProtoFakeOverrideSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.FileLocalIdSignature as ProtoFileLocalIdSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.FileSignature as ProtoFileSignature
 import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature as ProtoIdSignature
@@ -75,6 +76,20 @@
         return proto.build()
     }
 
+    private fun serializeFakeOverrideSignature(signature: IdSignature.FakeOverrideSignature): ProtoFakeOverrideSignature {
+        val proto = ProtoFakeOverrideSignature.newBuilder()
+        proto.containerClass = protoIdSignature(signature.containerClass)
+
+        proto.memberUniqId = signature.id
+        if (signature.mask != 0L) {
+            proto.flags = signature.mask
+        }
+
+        signature.description?.let { proto.debugInfo = serializeDebugInfo(it) }
+
+        return proto.build()
+    }
+
     @Suppress("UNUSED_PARAMETER")
     private fun serializeFileSignature(signature: IdSignature.FileSignature): ProtoFileSignature = ProtoFileSignature.getDefaultInstance()
 
@@ -98,6 +113,7 @@
             is IdSignature.CompositeSignature -> proto.compositeSig = serializeCompositeSignature(idSignature)
             is IdSignature.LocalSignature -> proto.localSig = serializeLocalSignature(idSignature)
             is IdSignature.FileSignature -> proto.fileSig = serializeFileSignature(idSignature)
+            is IdSignature.FakeOverrideSignature -> proto.fakeOverrideSig = serializeFakeOverrideSignature(idSignature)
             is IdSignature.SpecialFakeOverrideSignature -> {}
             is IdSignature.LoweredDeclarationSignature -> error("LoweredDeclarationSignature is not expected here")
         }
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt
index 4142e8c..fd17ed4 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileSerializer.kt
@@ -284,27 +284,28 @@
     }
 
     private fun serializeIrSymbol(symbol: IrSymbol, isDeclared: Boolean = false): Long {
-        val signature: IdSignature = runIf(settings.reuseExistingSignaturesForSymbols) { symbol.signature }
-            ?: when (symbol) {
-                is IrFileSymbol -> IdSignature.FileSignature(symbol) // TODO: special signature for files?
-                else -> {
-                    val symbolOwner = symbol.owner
+        val signature: IdSignature = runIf(settings.reuseExistingSignaturesForSymbols) {
+            symbol.signature ?: symbol.privateSignature?.takeIf { it is IdSignature.FakeOverrideSignature }
+        } ?: when (symbol) {
+            is IrFileSymbol -> IdSignature.FileSignature(symbol) // TODO: special signature for files?
+            else -> {
+                val symbolOwner = symbol.owner
 
-                    // Compute the signature:
-                    when {
-                        symbolOwner is IrDeclaration -> declarationTable.signatureByDeclaration(
-                            symbolOwner,
-                            settings.compatibilityMode.legacySignaturesForPrivateAndLocalDeclarations,
-                            recordInSignatureClashDetector = isDeclared
-                        )
+                // Compute the signature:
+                when {
+                    symbolOwner is IrDeclaration -> declarationTable.signatureByDeclaration(
+                        symbolOwner,
+                        settings.compatibilityMode.legacySignaturesForPrivateAndLocalDeclarations,
+                        recordInSignatureClashDetector = isDeclared
+                    )
 
-                        symbolOwner is IrReturnableBlock && settings.abiCompatibilityLevel.isAtLeast(ABI_LEVEL_2_2) ->
-                            declarationTable.signatureByReturnableBlock(symbolOwner)
+                    symbolOwner is IrReturnableBlock && settings.abiCompatibilityLevel.isAtLeast(ABI_LEVEL_2_2) ->
+                        declarationTable.signatureByReturnableBlock(symbolOwner)
 
-                        else -> error("Expected symbol owner: ${symbolOwner.render()}")
-                    }
+                    else -> error("Expected symbol owner: ${symbolOwner.render()}")
                 }
             }
+        }
 
         val signatureId = idSignatureSerializer.protoIdSignature(signature)
         val symbolKind = protoSymbolKind(symbol)
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/FakeOverrideSignature.java b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/FakeOverrideSignature.java
new file mode 100644
index 0000000..e4006e8
--- /dev/null
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/FakeOverrideSignature.java
@@ -0,0 +1,566 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: compiler/ir/serialization.common/src/KotlinIr.proto
+
+package org.jetbrains.kotlin.backend.common.serialization.proto;
+
+/**
+ * Protobuf type {@code org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature}
+ */
+public final class FakeOverrideSignature extends
+    org.jetbrains.kotlin.protobuf.GeneratedMessageLite implements
+    // @@protoc_insertion_point(message_implements:org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature)
+    FakeOverrideSignatureOrBuilder {
+  // Use FakeOverrideSignature.newBuilder() to construct.
+  private FakeOverrideSignature(org.jetbrains.kotlin.protobuf.GeneratedMessageLite.Builder builder) {
+    super(builder);
+    this.unknownFields = builder.getUnknownFields();
+  }
+  private FakeOverrideSignature(boolean noInit) { this.unknownFields = org.jetbrains.kotlin.protobuf.ByteString.EMPTY;}
+
+  private static final FakeOverrideSignature defaultInstance;
+  public static FakeOverrideSignature getDefaultInstance() {
+    return defaultInstance;
+  }
+
+  public FakeOverrideSignature getDefaultInstanceForType() {
+    return defaultInstance;
+  }
+
+  private final org.jetbrains.kotlin.protobuf.ByteString unknownFields;
+  private FakeOverrideSignature(
+      org.jetbrains.kotlin.protobuf.CodedInputStream input,
+      org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+    initFields();
+    int mutable_bitField0_ = 0;
+    org.jetbrains.kotlin.protobuf.ByteString.Output unknownFieldsOutput =
+        org.jetbrains.kotlin.protobuf.ByteString.newOutput();
+    org.jetbrains.kotlin.protobuf.CodedOutputStream unknownFieldsCodedOutput =
+        org.jetbrains.kotlin.protobuf.CodedOutputStream.newInstance(
+            unknownFieldsOutput, 1);
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          default: {
+            if (!parseUnknownField(input, unknownFieldsCodedOutput,
+                                   extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+          case 8: {
+            bitField0_ |= 0x00000001;
+            containerClass_ = input.readInt32();
+            break;
+          }
+          case 16: {
+            bitField0_ |= 0x00000002;
+            memberUniqId_ = input.readInt64();
+            break;
+          }
+          case 24: {
+            bitField0_ |= 0x00000004;
+            flags_ = input.readInt64();
+            break;
+          }
+          case 32: {
+            bitField0_ |= 0x00000008;
+            debugInfo_ = input.readInt32();
+            break;
+          }
+        }
+      }
+    } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException(
+          e.getMessage()).setUnfinishedMessage(this);
+    } finally {
+      try {
+        unknownFieldsCodedOutput.flush();
+      } catch (java.io.IOException e) {
+      // Should not happen
+      } finally {
+        unknownFields = unknownFieldsOutput.toByteString();
+      }
+      makeExtensionsImmutable();
+    }
+  }
+  public static org.jetbrains.kotlin.protobuf.Parser<FakeOverrideSignature> PARSER =
+      new org.jetbrains.kotlin.protobuf.AbstractParser<FakeOverrideSignature>() {
+    public FakeOverrideSignature parsePartialFrom(
+        org.jetbrains.kotlin.protobuf.CodedInputStream input,
+        org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+      return new FakeOverrideSignature(input, extensionRegistry);
+    }
+  };
+
+  @java.lang.Override
+  public org.jetbrains.kotlin.protobuf.Parser<FakeOverrideSignature> getParserForType() {
+    return PARSER;
+  }
+
+  private int bitField0_;
+  public static final int CONTAINER_CLASS_FIELD_NUMBER = 1;
+  private int containerClass_;
+  /**
+   * <code>required int32 container_class = 1;</code>
+   */
+  public boolean hasContainerClass() {
+    return ((bitField0_ & 0x00000001) == 0x00000001);
+  }
+  /**
+   * <code>required int32 container_class = 1;</code>
+   */
+  public int getContainerClass() {
+    return containerClass_;
+  }
+
+  public static final int MEMBER_UNIQ_ID_FIELD_NUMBER = 2;
+  private long memberUniqId_;
+  /**
+   * <code>required int64 member_uniq_id = 2;</code>
+   */
+  public boolean hasMemberUniqId() {
+    return ((bitField0_ & 0x00000002) == 0x00000002);
+  }
+  /**
+   * <code>required int64 member_uniq_id = 2;</code>
+   */
+  public long getMemberUniqId() {
+    return memberUniqId_;
+  }
+
+  public static final int FLAGS_FIELD_NUMBER = 3;
+  private long flags_;
+  /**
+   * <code>optional int64 flags = 3 [default = 0];</code>
+   */
+  public boolean hasFlags() {
+    return ((bitField0_ & 0x00000004) == 0x00000004);
+  }
+  /**
+   * <code>optional int64 flags = 3 [default = 0];</code>
+   */
+  public long getFlags() {
+    return flags_;
+  }
+
+  public static final int DEBUG_INFO_FIELD_NUMBER = 4;
+  private int debugInfo_;
+  /**
+   * <code>optional int32 debug_info = 4;</code>
+   */
+  public boolean hasDebugInfo() {
+    return ((bitField0_ & 0x00000008) == 0x00000008);
+  }
+  /**
+   * <code>optional int32 debug_info = 4;</code>
+   */
+  public int getDebugInfo() {
+    return debugInfo_;
+  }
+
+  private void initFields() {
+    containerClass_ = 0;
+    memberUniqId_ = 0L;
+    flags_ = 0L;
+    debugInfo_ = 0;
+  }
+  private byte memoizedIsInitialized = -1;
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    if (!hasContainerClass()) {
+      memoizedIsInitialized = 0;
+      return false;
+    }
+    if (!hasMemberUniqId()) {
+      memoizedIsInitialized = 0;
+      return false;
+    }
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  public void writeTo(org.jetbrains.kotlin.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    getSerializedSize();
+    if (((bitField0_ & 0x00000001) == 0x00000001)) {
+      output.writeInt32(1, containerClass_);
+    }
+    if (((bitField0_ & 0x00000002) == 0x00000002)) {
+      output.writeInt64(2, memberUniqId_);
+    }
+    if (((bitField0_ & 0x00000004) == 0x00000004)) {
+      output.writeInt64(3, flags_);
+    }
+    if (((bitField0_ & 0x00000008) == 0x00000008)) {
+      output.writeInt32(4, debugInfo_);
+    }
+    output.writeRawBytes(unknownFields);
+  }
+
+  private int memoizedSerializedSize = -1;
+  public int getSerializedSize() {
+    int size = memoizedSerializedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (((bitField0_ & 0x00000001) == 0x00000001)) {
+      size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+        .computeInt32Size(1, containerClass_);
+    }
+    if (((bitField0_ & 0x00000002) == 0x00000002)) {
+      size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+        .computeInt64Size(2, memberUniqId_);
+    }
+    if (((bitField0_ & 0x00000004) == 0x00000004)) {
+      size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+        .computeInt64Size(3, flags_);
+    }
+    if (((bitField0_ & 0x00000008) == 0x00000008)) {
+      size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+        .computeInt32Size(4, debugInfo_);
+    }
+    size += unknownFields.size();
+    memoizedSerializedSize = size;
+    return size;
+  }
+
+  private static final long serialVersionUID = 0L;
+  @java.lang.Override
+  protected java.lang.Object writeReplace()
+      throws java.io.ObjectStreamException {
+    return super.writeReplace();
+  }
+
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseFrom(
+      org.jetbrains.kotlin.protobuf.ByteString data)
+      throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseFrom(
+      org.jetbrains.kotlin.protobuf.ByteString data,
+      org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseFrom(byte[] data)
+      throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseFrom(
+      byte[] data,
+      org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return PARSER.parseFrom(input);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseFrom(
+      java.io.InputStream input,
+      org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return PARSER.parseFrom(input, extensionRegistry);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return PARSER.parseDelimitedFrom(input);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseDelimitedFrom(
+      java.io.InputStream input,
+      org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return PARSER.parseDelimitedFrom(input, extensionRegistry);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseFrom(
+      org.jetbrains.kotlin.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return PARSER.parseFrom(input);
+  }
+  public static org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parseFrom(
+      org.jetbrains.kotlin.protobuf.CodedInputStream input,
+      org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return PARSER.parseFrom(input, extensionRegistry);
+  }
+
+  public static Builder newBuilder() { return Builder.create(); }
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder(org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature prototype) {
+    return newBuilder().mergeFrom(prototype);
+  }
+  public Builder toBuilder() { return newBuilder(this); }
+
+  /**
+   * Protobuf type {@code org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature}
+   */
+  public static final class Builder extends
+      org.jetbrains.kotlin.protobuf.GeneratedMessageLite.Builder<
+        org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature, Builder>
+      implements
+      // @@protoc_insertion_point(builder_implements:org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature)
+      org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignatureOrBuilder {
+    // Construct using org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private void maybeForceBuilderInitialization() {
+    }
+    private static Builder create() {
+      return new Builder();
+    }
+
+    public Builder clear() {
+      super.clear();
+      containerClass_ = 0;
+      bitField0_ = (bitField0_ & ~0x00000001);
+      memberUniqId_ = 0L;
+      bitField0_ = (bitField0_ & ~0x00000002);
+      flags_ = 0L;
+      bitField0_ = (bitField0_ & ~0x00000004);
+      debugInfo_ = 0;
+      bitField0_ = (bitField0_ & ~0x00000008);
+      return this;
+    }
+
+    public Builder clone() {
+      return create().mergeFrom(buildPartial());
+    }
+
+    public org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature getDefaultInstanceForType() {
+      return org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.getDefaultInstance();
+    }
+
+    public org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature build() {
+      org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    public org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature buildPartial() {
+      org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature result = new org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature(this);
+      int from_bitField0_ = bitField0_;
+      int to_bitField0_ = 0;
+      if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+        to_bitField0_ |= 0x00000001;
+      }
+      result.containerClass_ = containerClass_;
+      if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+        to_bitField0_ |= 0x00000002;
+      }
+      result.memberUniqId_ = memberUniqId_;
+      if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+        to_bitField0_ |= 0x00000004;
+      }
+      result.flags_ = flags_;
+      if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+        to_bitField0_ |= 0x00000008;
+      }
+      result.debugInfo_ = debugInfo_;
+      result.bitField0_ = to_bitField0_;
+      return result;
+    }
+
+    public Builder mergeFrom(org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature other) {
+      if (other == org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.getDefaultInstance()) return this;
+      if (other.hasContainerClass()) {
+        setContainerClass(other.getContainerClass());
+      }
+      if (other.hasMemberUniqId()) {
+        setMemberUniqId(other.getMemberUniqId());
+      }
+      if (other.hasFlags()) {
+        setFlags(other.getFlags());
+      }
+      if (other.hasDebugInfo()) {
+        setDebugInfo(other.getDebugInfo());
+      }
+      setUnknownFields(
+          getUnknownFields().concat(other.unknownFields));
+      return this;
+    }
+
+    public final boolean isInitialized() {
+      if (!hasContainerClass()) {
+        
+        return false;
+      }
+      if (!hasMemberUniqId()) {
+        
+        return false;
+      }
+      return true;
+    }
+
+    public Builder mergeFrom(
+        org.jetbrains.kotlin.protobuf.CodedInputStream input,
+        org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature) e.getUnfinishedMessage();
+        throw e;
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+    private int bitField0_;
+
+    private int containerClass_ ;
+    /**
+     * <code>required int32 container_class = 1;</code>
+     */
+    public boolean hasContainerClass() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>required int32 container_class = 1;</code>
+     */
+    public int getContainerClass() {
+      return containerClass_;
+    }
+    /**
+     * <code>required int32 container_class = 1;</code>
+     */
+    public Builder setContainerClass(int value) {
+      bitField0_ |= 0x00000001;
+      containerClass_ = value;
+      
+      return this;
+    }
+    /**
+     * <code>required int32 container_class = 1;</code>
+     */
+    public Builder clearContainerClass() {
+      bitField0_ = (bitField0_ & ~0x00000001);
+      containerClass_ = 0;
+      
+      return this;
+    }
+
+    private long memberUniqId_ ;
+    /**
+     * <code>required int64 member_uniq_id = 2;</code>
+     */
+    public boolean hasMemberUniqId() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>required int64 member_uniq_id = 2;</code>
+     */
+    public long getMemberUniqId() {
+      return memberUniqId_;
+    }
+    /**
+     * <code>required int64 member_uniq_id = 2;</code>
+     */
+    public Builder setMemberUniqId(long value) {
+      bitField0_ |= 0x00000002;
+      memberUniqId_ = value;
+      
+      return this;
+    }
+    /**
+     * <code>required int64 member_uniq_id = 2;</code>
+     */
+    public Builder clearMemberUniqId() {
+      bitField0_ = (bitField0_ & ~0x00000002);
+      memberUniqId_ = 0L;
+      
+      return this;
+    }
+
+    private long flags_ ;
+    /**
+     * <code>optional int64 flags = 3 [default = 0];</code>
+     */
+    public boolean hasFlags() {
+      return ((bitField0_ & 0x00000004) == 0x00000004);
+    }
+    /**
+     * <code>optional int64 flags = 3 [default = 0];</code>
+     */
+    public long getFlags() {
+      return flags_;
+    }
+    /**
+     * <code>optional int64 flags = 3 [default = 0];</code>
+     */
+    public Builder setFlags(long value) {
+      bitField0_ |= 0x00000004;
+      flags_ = value;
+      
+      return this;
+    }
+    /**
+     * <code>optional int64 flags = 3 [default = 0];</code>
+     */
+    public Builder clearFlags() {
+      bitField0_ = (bitField0_ & ~0x00000004);
+      flags_ = 0L;
+      
+      return this;
+    }
+
+    private int debugInfo_ ;
+    /**
+     * <code>optional int32 debug_info = 4;</code>
+     */
+    public boolean hasDebugInfo() {
+      return ((bitField0_ & 0x00000008) == 0x00000008);
+    }
+    /**
+     * <code>optional int32 debug_info = 4;</code>
+     */
+    public int getDebugInfo() {
+      return debugInfo_;
+    }
+    /**
+     * <code>optional int32 debug_info = 4;</code>
+     */
+    public Builder setDebugInfo(int value) {
+      bitField0_ |= 0x00000008;
+      debugInfo_ = value;
+      
+      return this;
+    }
+    /**
+     * <code>optional int32 debug_info = 4;</code>
+     */
+    public Builder clearDebugInfo() {
+      bitField0_ = (bitField0_ & ~0x00000008);
+      debugInfo_ = 0;
+      
+      return this;
+    }
+
+    // @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature)
+  }
+
+  static {
+    defaultInstance = new FakeOverrideSignature(true);
+    defaultInstance.initFields();
+  }
+
+  // @@protoc_insertion_point(class_scope:org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature)
+}
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/FakeOverrideSignatureOrBuilder.java b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/FakeOverrideSignatureOrBuilder.java
new file mode 100644
index 0000000..41d55ac
--- /dev/null
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/FakeOverrideSignatureOrBuilder.java
@@ -0,0 +1,45 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: compiler/ir/serialization.common/src/KotlinIr.proto
+
+package org.jetbrains.kotlin.backend.common.serialization.proto;
+
+public interface FakeOverrideSignatureOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature)
+    org.jetbrains.kotlin.protobuf.MessageLiteOrBuilder {
+
+  /**
+   * <code>required int32 container_class = 1;</code>
+   */
+  boolean hasContainerClass();
+  /**
+   * <code>required int32 container_class = 1;</code>
+   */
+  int getContainerClass();
+
+  /**
+   * <code>required int64 member_uniq_id = 2;</code>
+   */
+  boolean hasMemberUniqId();
+  /**
+   * <code>required int64 member_uniq_id = 2;</code>
+   */
+  long getMemberUniqId();
+
+  /**
+   * <code>optional int64 flags = 3 [default = 0];</code>
+   */
+  boolean hasFlags();
+  /**
+   * <code>optional int64 flags = 3 [default = 0];</code>
+   */
+  long getFlags();
+
+  /**
+   * <code>optional int32 debug_info = 4;</code>
+   */
+  boolean hasDebugInfo();
+  /**
+   * <code>optional int32 debug_info = 4;</code>
+   */
+  int getDebugInfo();
+}
\ No newline at end of file
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/IdSignature.java b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/IdSignature.java
index 6a82a50..24e79b6 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/IdSignature.java
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/IdSignature.java
@@ -136,6 +136,19 @@
             idSigCase_ = 7;
             break;
           }
+          case 66: {
+            org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.Builder subBuilder = null;
+            if (idSigCase_ == 8) {
+              subBuilder = ((org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature) idSig_).toBuilder();
+            }
+            idSig_ = input.readMessage(org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.PARSER, extensionRegistry);
+            if (subBuilder != null) {
+              subBuilder.mergeFrom((org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature) idSig_);
+              idSig_ = subBuilder.buildPartial();
+            }
+            idSigCase_ = 8;
+            break;
+          }
         }
       }
     } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
@@ -178,6 +191,7 @@
     PRIVATE_SIG(2),
     ACCESSOR_SIG(3),
     SCOPED_LOCAL_SIG(4),
+    FAKE_OVERRIDE_SIG(8),
     COMPOSITE_SIG(5),
     LOCAL_SIG(6),
     FILE_SIG(7),
@@ -192,6 +206,7 @@
         case 2: return PRIVATE_SIG;
         case 3: return ACCESSOR_SIG;
         case 4: return SCOPED_LOCAL_SIG;
+        case 8: return FAKE_OVERRIDE_SIG;
         case 5: return COMPOSITE_SIG;
         case 6: return LOCAL_SIG;
         case 7: return FILE_SIG;
@@ -279,6 +294,23 @@
     return 0;
   }
 
+  public static final int FAKE_OVERRIDE_SIG_FIELD_NUMBER = 8;
+  /**
+   * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+   */
+  public boolean hasFakeOverrideSig() {
+    return idSigCase_ == 8;
+  }
+  /**
+   * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+   */
+  public org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature getFakeOverrideSig() {
+    if (idSigCase_ == 8) {
+       return (org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature) idSig_;
+    }
+    return org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.getDefaultInstance();
+  }
+
   public static final int COMPOSITE_SIG_FIELD_NUMBER = 5;
   /**
    * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.CompositeSignature composite_sig = 5;</code>
@@ -350,6 +382,12 @@
         return false;
       }
     }
+    if (hasFakeOverrideSig()) {
+      if (!getFakeOverrideSig().isInitialized()) {
+        memoizedIsInitialized = 0;
+        return false;
+      }
+    }
     if (hasCompositeSig()) {
       if (!getCompositeSig().isInitialized()) {
         memoizedIsInitialized = 0;
@@ -385,6 +423,9 @@
     if (idSigCase_ == 7) {
       output.writeMessage(7, (org.jetbrains.kotlin.backend.common.serialization.proto.FileSignature) idSig_);
     }
+    if (idSigCase_ == 8) {
+      output.writeMessage(8, (org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature) idSig_);
+    }
     output.writeRawBytes(unknownFields);
   }
 
@@ -423,6 +464,10 @@
       size += org.jetbrains.kotlin.protobuf.CodedOutputStream
         .computeMessageSize(7, (org.jetbrains.kotlin.backend.common.serialization.proto.FileSignature) idSig_);
     }
+    if (idSigCase_ == 8) {
+      size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+        .computeMessageSize(8, (org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature) idSig_);
+    }
     size += unknownFields.size();
     memoizedSerializedSize = size;
     return size;
@@ -554,6 +599,9 @@
       if (idSigCase_ == 4) {
         result.idSig_ = idSig_;
       }
+      if (idSigCase_ == 8) {
+        result.idSig_ = idSig_;
+      }
       if (idSigCase_ == 5) {
         result.idSig_ = idSig_;
       }
@@ -587,6 +635,10 @@
           setScopedLocalSig(other.getScopedLocalSig());
           break;
         }
+        case FAKE_OVERRIDE_SIG: {
+          mergeFakeOverrideSig(other.getFakeOverrideSig());
+          break;
+        }
         case COMPOSITE_SIG: {
           mergeCompositeSig(other.getCompositeSig());
           break;
@@ -621,6 +673,12 @@
           return false;
         }
       }
+      if (hasFakeOverrideSig()) {
+        if (!getFakeOverrideSig().isInitialized()) {
+          
+          return false;
+        }
+      }
       if (hasCompositeSig()) {
         if (!getCompositeSig().isInitialized()) {
           
@@ -892,6 +950,70 @@
     }
 
     /**
+     * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+     */
+    public boolean hasFakeOverrideSig() {
+      return idSigCase_ == 8;
+    }
+    /**
+     * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+     */
+    public org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature getFakeOverrideSig() {
+      if (idSigCase_ == 8) {
+        return (org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature) idSig_;
+      }
+      return org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.getDefaultInstance();
+    }
+    /**
+     * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+     */
+    public Builder setFakeOverrideSig(org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature value) {
+      if (value == null) {
+        throw new NullPointerException();
+      }
+      idSig_ = value;
+
+      idSigCase_ = 8;
+      return this;
+    }
+    /**
+     * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+     */
+    public Builder setFakeOverrideSig(
+        org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.Builder builderForValue) {
+      idSig_ = builderForValue.build();
+
+      idSigCase_ = 8;
+      return this;
+    }
+    /**
+     * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+     */
+    public Builder mergeFakeOverrideSig(org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature value) {
+      if (idSigCase_ == 8 &&
+          idSig_ != org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.getDefaultInstance()) {
+        idSig_ = org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature.newBuilder((org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature) idSig_)
+            .mergeFrom(value).buildPartial();
+      } else {
+        idSig_ = value;
+      }
+
+      idSigCase_ = 8;
+      return this;
+    }
+    /**
+     * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+     */
+    public Builder clearFakeOverrideSig() {
+      if (idSigCase_ == 8) {
+        idSigCase_ = 0;
+        idSig_ = null;
+        
+      }
+      return this;
+    }
+
+    /**
      * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.CompositeSignature composite_sig = 5;</code>
      */
     public boolean hasCompositeSig() {
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/IdSignatureOrBuilder.java b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/IdSignatureOrBuilder.java
index a0bb289..4bcc8c2 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/IdSignatureOrBuilder.java
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/proto/IdSignatureOrBuilder.java
@@ -44,6 +44,15 @@
   int getScopedLocalSig();
 
   /**
+   * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+   */
+  boolean hasFakeOverrideSig();
+  /**
+   * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature fake_override_sig = 8;</code>
+   */
+  org.jetbrains.kotlin.backend.common.serialization.proto.FakeOverrideSignature getFakeOverrideSig();
+
+  /**
    * <code>optional .org.jetbrains.kotlin.backend.common.serialization.proto.CompositeSignature composite_sig = 5;</code>
    */
   boolean hasCompositeSig();
diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureComputers.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureComputers.kt
index 7d2f4ba..aedbfcd 100644
--- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureComputers.kt
+++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/signature/IdSignatureComputers.kt
@@ -14,10 +14,13 @@
 import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
 import org.jetbrains.kotlin.ir.util.IdSignature
 import org.jetbrains.kotlin.ir.util.KotlinMangler
+import org.jetbrains.kotlin.ir.util.getPackageFragment
 import org.jetbrains.kotlin.ir.util.isFacadeClass
 import org.jetbrains.kotlin.ir.util.render
 import org.jetbrains.kotlin.ir.visitors.IrVisitorVoid
 import org.jetbrains.kotlin.ir.visitors.acceptVoid
+import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin
+import org.jetbrains.kotlin.library.metadata.KlibModuleOrigin
 
 class PublicIdSignatureComputer(val mangler: KotlinMangler.IrMangler) : IdSignatureComputer {
 
@@ -218,27 +221,76 @@
         is IrValueDeclaration -> generateScopeLocalSignature(declaration.name.asString())
         is IrAnonymousInitializer -> generateScopeLocalSignature("ANON INIT")
         is IrLocalDelegatedProperty -> generateScopeLocalSignature(declaration.name.asString())
+        is IrOverridableDeclaration<*> if (declaration.isFakeOverride) -> {
+            val fakeOverriddenInClass = declaration.parent as IrClass
+            val oldFormat = run {
+                val file = fakeOverriddenInClass.getPackageFragment() as? IrFile ?: return@run false
+                val klibOrigin = file.module.descriptor.getCapability(KlibModuleOrigin.CAPABILITY) as? DeserializedKlibModuleOrigin ?: return@run false
+                val version = klibOrigin.library.versions.abiVersion ?: return@run false
+                version.isAtMost(2, 1, 0)
+                        || klibOrigin.library.versions.compilerVersion == "2.2.0-dev-4719"
+            }
 
-        is IrSimpleFunction -> IdSignature.FileLocalSignature(
-            container = computeContainerIdSignature(declaration, compatibleMode),
-            id = if (declaration.isFakeOverride) {
-                declaration.stableIndexForFakeOverride(compatibleMode)
+            if (oldFormat) {
+                // Prior to kotlin 2.2.0, local fake overrides used FileLocalSignature, like other local declarations, but with id
+                // based on the declaration's name, instead of the location in a file.
+                // This was the solution to have a stable signature, that at the same time is predictable by the fake override builder,
+                // which does not know anything about locations in the IR file.
+                // It was changed to use a dedicated FakeOverrideSignature (KT-72296), but we still need to create signatures
+                // in the old format for declarations in the fake override builder, so that they will match with deserialized signatures
+                // at call-site, if the call-site comes from an older KLib.
+                // Fortunately, since this is a local declaration, it and all its call-sites must have been compiled within the same
+                // compilation, and so with the same ABI version.
+                IdSignature.FileLocalSignature(
+                    container = computeContainerIdSignature(declaration, compatibleMode),
+                    id = mangler.run { declaration.signatureMangle(compatibleMode) },
+                )
             } else {
-                ++localIndex
-            },
-            description = declaration.render()
-        )
+                val signatureBuilder = object : IdSignatureBuilder<IrDeclaration, KotlinMangler.IrMangler>() {
+                    override fun renderDeclarationForDescription(declaration: IrDeclaration): String = declaration.render()
+                    override val currentFileSignature: IdSignature.FileSignature? get() = null
+                    override val mangler: KotlinMangler.IrMangler get() = this@FileLocalIdSignatureComputer.mangler
+                    override fun accept(declaration: IrDeclaration) {
+                        when (declaration) {
+                            is IrSimpleFunction -> {
+                                val property = declaration.correspondingPropertySymbol
+                                if (property != null) {
+                                    visitProperty(property.owner)
+                                    setHashIdAndDescriptionFor(declaration, isPropertyAccessor = container == null)
+                                    classFqnSegments.add(declaration.name.asString())
+                                } else {
+                                    setHashIdAndDescriptionFor(declaration, isPropertyAccessor = false)
 
-        is IrProperty -> IdSignature.FileLocalSignature(
-            container = computeContainerIdSignature(declaration, compatibleMode),
-            id = if (declaration.isFakeOverride) {
-                declaration.stableIndexForFakeOverride(compatibleMode)
-            } else {
-                ++localIndex
-            },
-            description = declaration.render()
-        )
+                                    // If this is a local function, overwrite `description` with the IR function's rendered form.
+                                    setDescriptionIfLocalDeclaration(declaration)
+                                }
+                            }
+                            is IrProperty -> {
+                                visitProperty(declaration)
+                            }
+                            else -> error("Unexpected declaration: ${declaration.render()}")
+                        }
+                    }
 
+                    private fun visitProperty(declaration: IrProperty) {
+                        setHashIdAndDescriptionFor(declaration, isPropertyAccessor = false)
+                    }
+                }
+
+                val realSignature = signatureBuilder.buildSignature(declaration)
+                val commonSignature = when (realSignature) {
+                    is IdSignature.CommonSignature -> realSignature
+                    is IdSignature.AccessorSignature -> realSignature.accessorSignature
+                    else -> error("Unexpected signature type: ${realSignature.javaClass}")
+                }
+                IdSignature.FakeOverrideSignature(
+                    containerClass = signatureByDeclaration(fakeOverriddenInClass, compatibleMode),
+                    commonSignature.id!!,
+                    commonSignature.mask,
+                    commonSignature.description,
+                )
+            }
+        }
         else -> IdSignature.FileLocalSignature(
             container = computeContainerIdSignature(declaration, compatibleMode),
             id = ++localIndex,
@@ -249,17 +301,6 @@
     fun generateScopeLocalSignature(description: String): IdSignature =
         IdSignature.ScopeLocalDeclaration(scopeIndex++, description)
 
-    /**
-     * We shall have stable indices for local fake override functions/properties.
-     * This is necessary to be able to match the signature at the fake override call site
-     * with the fake override declaration constructed by the fake override builder component
-     * (which does not know anything about indices in the IR file).
-     *
-     * TODO: Consider using specialized signatures for local fake overrides, KT-72296
-     */
-    private fun IrOverridableDeclaration<*>.stableIndexForFakeOverride(compatibleMode: Boolean): Long =
-        mangler.run { this@stableIndexForFakeOverride.signatureMangle(compatibleMode) }
-
     companion object {
         private const val START_INDEX = 0
     }
diff --git a/compiler/testData/codegen/boxInline/anonymousObject/fakeOverrideInDefaultMultiModule.kt b/compiler/testData/codegen/boxInline/anonymousObject/fakeOverrideInDefaultMultiModule.kt
index 749775a..3fefa27 100644
--- a/compiler/testData/codegen/boxInline/anonymousObject/fakeOverrideInDefaultMultiModule.kt
+++ b/compiler/testData/codegen/boxInline/anonymousObject/fakeOverrideInDefaultMultiModule.kt
@@ -1,6 +1,4 @@
 // NO_CHECK_LAMBDA_INLINING
-// SKIP_UNBOUND_IR_SERIALIZATION
-// ^^^ Muted until KT-72296 is fixed.
 
 // MODULE: lib
 // FILE: lib.kt
diff --git a/compiler/testData/codegen/boxInline/anonymousObject/fakeOverrideMultiModule.kt b/compiler/testData/codegen/boxInline/anonymousObject/fakeOverrideMultiModule.kt
index a6afda9..781ad97 100644
--- a/compiler/testData/codegen/boxInline/anonymousObject/fakeOverrideMultiModule.kt
+++ b/compiler/testData/codegen/boxInline/anonymousObject/fakeOverrideMultiModule.kt
@@ -1,6 +1,4 @@
 // NO_CHECK_LAMBDA_INLINING
-// SKIP_UNBOUND_IR_SERIALIZATION
-// ^^^ Muted until KT-72296 is fixed.
 
 // MODULE: lib
 // FILE: lib.kt
diff --git a/compiler/testData/codegen/boxInline/innerClasses/fakeOverride.kt b/compiler/testData/codegen/boxInline/innerClasses/fakeOverride.kt
index 62fff41..3ec84aa 100644
--- a/compiler/testData/codegen/boxInline/innerClasses/fakeOverride.kt
+++ b/compiler/testData/codegen/boxInline/innerClasses/fakeOverride.kt
@@ -1,6 +1,3 @@
-// SKIP_UNBOUND_IR_SERIALIZATION
-// ^^^ Muted until KT-72296 is fixed.
-
 // FILE: 1.kt
 open class C {
     fun o() = "O"
diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/KlibBasedCompilerTestDirectives.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/KlibBasedCompilerTestDirectives.kt
index 6d063ae..04112baa 100644
--- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/KlibBasedCompilerTestDirectives.kt
+++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/KlibBasedCompilerTestDirectives.kt
@@ -52,11 +52,8 @@
         """
             This is a directive to skip some test data files in unbound IR serialization tests
             (see `AbstractNativeUnboundIrSerializationTest` and generated subclasses).
-            
-            Some tests are known to have call sites of local fake overrides inside inline functions.
-            Currently, serialization of such call sites is not supported. It should be supported in KT-72296.
 
-            Other tests use exposure of private types from internal inline functions. This is already a compiler
+            Some tests use exposure of private types from internal inline functions. This is already a compiler
             warning in 2.1.0 (KT-69681), but soon will become a compiler error (KT-70916).
         """.trimIndent()
     )