fixup! [Analysis API FIR] Initialize properties of `KtCallableSignature` lazily
diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/signatures/KtFe10FunctionLikeSignature.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/signatures/KtFe10FunctionLikeSignature.kt
index e97e119..ff3b76c 100644
--- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/signatures/KtFe10FunctionLikeSignature.kt
+++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/signatures/KtFe10FunctionLikeSignature.kt
@@ -5,6 +5,7 @@
 
 package org.jetbrains.kotlin.analysis.api.descriptors.signatures
 
+import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
 import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
 import org.jetbrains.kotlin.analysis.api.signatures.KtFunctionLikeSignature
 import org.jetbrains.kotlin.analysis.api.signatures.KtVariableLikeSignature
@@ -14,11 +15,15 @@
 import org.jetbrains.kotlin.analysis.api.types.KtType
 
 internal class KtFe10FunctionLikeSignature<out S : KtFunctionLikeSymbol>(
-    symbol: S,
+    private val _symbol: S,
     private val _returnType: KtType,
     private val _receiverType: KtType?,
     private val _valueParameters: List<KtVariableLikeSignature<KtValueParameterSymbol>>,
-) : KtFunctionLikeSignature<S>(symbol) {
+) : KtFunctionLikeSignature<S>() {
+    override val token: KtLifetimeToken
+        get() = _symbol.token
+    override val symbol: S
+        get() = withValidityAssertion { _symbol }
     override val returnType: KtType
         get() = withValidityAssertion { _returnType }
     override val receiverType: KtType?
@@ -26,16 +31,18 @@
     override val valueParameters: List<KtVariableLikeSignature<KtValueParameterSymbol>>
         get() = withValidityAssertion { _valueParameters }
 
-    override fun substitute(substitutor: KtSubstitutor): KtFunctionLikeSignature<S> = KtFe10FunctionLikeSignature(
-        symbol,
-        substitutor.substitute(returnType),
-        receiverType?.let { substitutor.substitute(it) },
-        valueParameters.map { valueParameter ->
-            KtFe10VariableLikeSignature<KtValueParameterSymbol>(
-                valueParameter.symbol,
-                substitutor.substitute(valueParameter.returnType),
-                valueParameter.receiverType?.let { substitutor.substitute(it) }
-            )
-        }
-    )
+    override fun substitute(substitutor: KtSubstitutor): KtFunctionLikeSignature<S> = withValidityAssertion {
+        KtFe10FunctionLikeSignature(
+            symbol,
+            substitutor.substitute(returnType),
+            receiverType?.let { substitutor.substitute(it) },
+            valueParameters.map { valueParameter ->
+                KtFe10VariableLikeSignature<KtValueParameterSymbol>(
+                    valueParameter.symbol,
+                    substitutor.substitute(valueParameter.returnType),
+                    valueParameter.receiverType?.let { substitutor.substitute(it) }
+                )
+            }
+        )
+    }
 }
diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/signatures/KtFe10VariableLikeSignature.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/signatures/KtFe10VariableLikeSignature.kt
index 539377e..509af9f 100644
--- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/signatures/KtFe10VariableLikeSignature.kt
+++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/signatures/KtFe10VariableLikeSignature.kt
@@ -5,6 +5,7 @@
 
 package org.jetbrains.kotlin.analysis.api.descriptors.signatures
 
+import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
 import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
 import org.jetbrains.kotlin.analysis.api.signatures.KtVariableLikeSignature
 import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
@@ -12,18 +13,24 @@
 import org.jetbrains.kotlin.analysis.api.types.KtType
 
 internal class KtFe10VariableLikeSignature<out S : KtVariableLikeSymbol>(
-    symbol: S,
+    private val _symbol: S,
     private val _returnType: KtType,
     private val _receiverType: KtType?,
-) : KtVariableLikeSignature<S>(symbol) {
+) : KtVariableLikeSignature<S>() {
+    override val token: KtLifetimeToken
+        get() = _symbol.token
+    override val symbol: S
+        get() = withValidityAssertion { _symbol }
     override val returnType: KtType
         get() = withValidityAssertion { _returnType }
     override val receiverType: KtType?
         get() = withValidityAssertion { _receiverType }
 
-    override fun substitute(substitutor: KtSubstitutor): KtVariableLikeSignature<S> = KtFe10VariableLikeSignature(
-        symbol,
-        substitutor.substitute(returnType),
-        receiverType?.let { substitutor.substitute(it) },
-    )
+    override fun substitute(substitutor: KtSubstitutor): KtVariableLikeSignature<S> = withValidityAssertion {
+        KtFe10VariableLikeSignature(
+            symbol,
+            substitutor.substitute(returnType),
+            receiverType?.let { substitutor.substitute(it) },
+        )
+    }
 }
\ No newline at end of file
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt
index 5ff2490..a9a187b 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/KtSymbolByFirBuilder.kt
@@ -63,8 +63,8 @@
 import org.jetbrains.kotlin.types.Variance
 import kotlin.contracts.ExperimentalContracts
 import kotlin.contracts.contract
-import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirFunctionFirSymbolBasedSignature
-import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirPropertyFirSymbolBasedSignature
+import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirFunctionLikeSubstitutorBasedSignature
+import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirVariableLikeSubstitutorBasedSignature
 
 /**
  * Maps FirElement to KtSymbol & ConeType to KtType, thread safe
@@ -222,8 +222,7 @@
 
         fun buildFunctionSignature(firSymbol: FirNamedFunctionSymbol): KtFunctionLikeSignature<KtFirFunctionSymbol> {
             firSymbol.lazyResolveToPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
-            val functionSymbol = buildFunctionSymbol(firSymbol)
-            return KtFirFunctionFirSymbolBasedSignature(functionSymbol, firSymbol, analysisSession.firSymbolBuilder)
+            return KtFirFunctionLikeSubstitutorBasedSignature(analysisSession.token, firSymbol, analysisSession.firSymbolBuilder)
         }
 
         fun buildAnonymousFunctionSymbol(firSymbol: FirAnonymousFunctionSymbol): KtFirAnonymousFunctionSymbol {
@@ -303,7 +302,7 @@
 
         fun buildPropertySignature(firSymbol: FirPropertySymbol): KtVariableLikeSignature<KtVariableSymbol> {
             firSymbol.lazyResolveToPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
-            return KtFirPropertyFirSymbolBasedSignature(buildPropertySymbol(firSymbol), firSymbol, analysisSession.firSymbolBuilder)
+            return KtFirVariableLikeSubstitutorBasedSignature(analysisSession.token, firSymbol, analysisSession.firSymbolBuilder)
         }
 
         fun buildLocalVariableSymbol(firSymbol: FirPropertySymbol): KtFirLocalVariableSymbol {
@@ -320,6 +319,9 @@
         }
 
         fun buildValueParameterSymbol(firSymbol: FirValueParameterSymbol): KtValueParameterSymbol {
+            firSymbol.fir.unwrapSubstitutionOverrideIfNeeded()?.let {
+                return buildValueParameterSymbol(it.symbol)
+            }
             return symbolsCache.cache(firSymbol) {
                 KtFirValueParameterSymbol(firSymbol, analysisSession)
             }
@@ -511,8 +513,8 @@
     private inline fun <reified T : FirCallableDeclaration> T.unwrapUseSiteSubstitutionOverride(): T? {
         val originalDeclaration = originalForSubstitutionOverride ?: return null
 
-        val containingClass = getContainingClass(rootSession) ?: return null
-        val originalContainingClass = originalDeclaration.getContainingClass(rootSession) ?: return null
+        val containingClass = getContainingMemberOrSelf().getContainingClass(rootSession) ?: return null
+        val originalContainingClass = originalDeclaration.getContainingMemberOrSelf().getContainingClass(rootSession) ?: return null
 
         // If substitution override does not change the containing class of the FIR declaration,
         // it is a use-site substitution override
@@ -521,6 +523,11 @@
         return originalDeclaration
     }
 
+    private fun FirCallableDeclaration.getContainingMemberOrSelf(): FirCallableDeclaration = when (this) {
+        is FirValueParameter -> containingFunctionSymbol.fir
+        else -> this
+    }
+
     /**
      * We want to unwrap a SUBSTITUTION_OVERRIDE wrapper if it doesn't affect the declaration's signature in any way. If the signature
      * is somehow changed, then we want to keep the wrapper.
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSignatureSubstitutor.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSignatureSubstitutor.kt
index 4876038..8584e04 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSignatureSubstitutor.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSignatureSubstitutor.kt
@@ -6,20 +6,27 @@
 package org.jetbrains.kotlin.analysis.api.fir.components
 
 import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
-import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirFunctionLikeSymbolBasedSignature
-import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirVariableLikeSymbolBasedSignature
+import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirFunctionLikeDummySignature
+import org.jetbrains.kotlin.analysis.api.fir.signatures.KtFirVariableLikeDummySignature
+import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
 import org.jetbrains.kotlin.analysis.api.impl.base.components.AbstractKtSignatureSubstitutor
 import org.jetbrains.kotlin.analysis.api.signatures.KtFunctionLikeSignature
 import org.jetbrains.kotlin.analysis.api.signatures.KtVariableLikeSignature
 import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
 import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
 
 internal class KtFirSignatureSubstitutor(
     override val analysisSession: KtFirAnalysisSession
 ) : AbstractKtSignatureSubstitutor(), KtFirAnalysisSessionComponent {
-    override fun <S : KtFunctionLikeSymbol> asSignature(symbol: S): KtFunctionLikeSignature<S> =
-        KtFirFunctionLikeSymbolBasedSignature<S>(symbol)
+    override fun <S : KtFunctionLikeSymbol> asSignature(symbol: S): KtFunctionLikeSignature<S> {
+        val firSymbol = (symbol as KtFirSymbol<*>).firSymbol as FirFunctionSymbol<*>
+        return KtFirFunctionLikeDummySignature<S>(analysisSession.token, firSymbol, analysisSession.firSymbolBuilder)
+    }
 
-    override fun <S : KtVariableLikeSymbol> asSignature(symbol: S): KtVariableLikeSignature<S> =
-        KtFirVariableLikeSymbolBasedSignature<S>(symbol)
+    override fun <S : KtVariableLikeSymbol> asSignature(symbol: S): KtVariableLikeSignature<S> {
+        val firSymbol = (symbol as KtFirSymbol<*>).firSymbol as FirVariableSymbol<*>
+        return KtFirVariableLikeDummySignature<S>(analysisSession.token, firSymbol, analysisSession.firSymbolBuilder)
+    }
 }
\ No newline at end of file
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/FirSymbolBasedSignature.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/FirSymbolBasedSignature.kt
index a4efa4f..96ecfc6 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/FirSymbolBasedSignature.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/FirSymbolBasedSignature.kt
@@ -6,8 +6,9 @@
 package org.jetbrains.kotlin.analysis.api.fir.signatures
 
 import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
+import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
 
-internal interface FirSymbolBasedSignature<S> {
-    val firSymbol: S
+internal interface FirSymbolBasedSignature {
+    val firSymbol: FirCallableSymbol<*>
     val firSymbolBuilder: KtSymbolByFirBuilder
 }
\ No newline at end of file
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/KtFirFunctionLikeSignature.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/KtFirFunctionLikeSignature.kt
index 95de238..3dedb27 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/KtFirFunctionLikeSignature.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/KtFirFunctionLikeSignature.kt
@@ -6,67 +6,82 @@
 package org.jetbrains.kotlin.analysis.api.fir.signatures
 
 import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
-import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFunctionSymbol
+import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
+import org.jetbrains.kotlin.analysis.api.fir.types.AbstractKtFirSubstitutor
 import org.jetbrains.kotlin.analysis.api.fir.utils.cached
-import org.jetbrains.kotlin.analysis.api.impl.base.types.KtChainedSubstitutor
+import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
+import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
 import org.jetbrains.kotlin.analysis.api.signatures.KtFunctionLikeSignature
 import org.jetbrains.kotlin.analysis.api.signatures.KtVariableLikeSignature
 import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
 import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.receiverType
 import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
 import org.jetbrains.kotlin.analysis.api.types.KtType
-import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
+import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
+import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
+import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
+import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
 import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
 
-internal sealed class KtFirFunctionLikeSignature<out S : KtFunctionLikeSymbol>(ktSymbol: S) : KtFunctionLikeSignature<S>(ktSymbol) {
+internal sealed class KtFirFunctionLikeSignature<out S : KtFunctionLikeSymbol> : KtFunctionLikeSignature<S>(), FirSymbolBasedSignature {
     abstract override fun substitute(substitutor: KtSubstitutor): KtFirFunctionLikeSignature<S>
 }
 
-internal class KtFirFunctionLikeSubstitutorBasedSignature<out S : KtFunctionLikeSymbol>(
-    override val signature: KtFunctionLikeSignature<S>,
-    override val substitutor: KtSubstitutor,
-) : KtFirFunctionLikeSignature<S>(signature.symbol), SubstitutorBasedSignature<KtFunctionLikeSignature<S>> {
-    override val returnType: KtType by cached {
-        substitutor.substitute(signature.returnType)
-    }
-    override val receiverType: KtType? by cached {
-        signature.receiverType?.let { substitutor.substitute(it) }
-    }
-    override val valueParameters: List<KtVariableLikeSignature<KtValueParameterSymbol>> by cached {
-        signature.valueParameters.map { it.substitute(substitutor) }
-    }
-
-    override fun substitute(substitutor: KtSubstitutor): KtFirFunctionLikeSignature<S> = when {
-        substitutor is KtSubstitutor.Empty -> this
-        else -> KtFirFunctionLikeSubstitutorBasedSignature(signature, KtChainedSubstitutor(this.substitutor, substitutor))
-    }
-}
-
-internal open class KtFirFunctionLikeSymbolBasedSignature<S : KtFunctionLikeSymbol>(ktSymbol: S) : KtFirFunctionLikeSignature<S>(ktSymbol) {
-    override val valueParameters: List<KtVariableLikeSignature<KtValueParameterSymbol>> by cached {
-        ktSymbol.valueParameters.map { KtFirVariableLikeSymbolBasedSignature(it) }
-    }
-
-    override fun substitute(substitutor: KtSubstitutor): KtFirFunctionLikeSignature<S> = when {
-        substitutor is KtSubstitutor.Empty -> this
-        else -> KtFirFunctionLikeSubstitutorBasedSignature(this, substitutor)
-    }
-}
-
-internal class KtFirFunctionFirSymbolBasedSignature(
-    ktSymbol: KtFirFunctionSymbol,
-    override val firSymbol: FirNamedFunctionSymbol,
+internal class KtFirFunctionLikeDummySignature<out S : KtFunctionLikeSymbol>(
+    override val token: KtLifetimeToken,
+    override val firSymbol: FirFunctionSymbol<*>,
     override val firSymbolBuilder: KtSymbolByFirBuilder,
-) : KtFirFunctionLikeSymbolBasedSignature<KtFirFunctionSymbol>(ktSymbol), FirSymbolBasedSignature<FirNamedFunctionSymbol> {
+) : KtFirFunctionLikeSignature<S>() {
+    @Suppress("UNCHECKED_CAST")
+    override val symbol: S
+        get() = withValidityAssertion { firSymbol.buildSymbol(firSymbolBuilder) as S }
+    override val returnType: KtType
+        get() = withValidityAssertion { symbol.returnType }
+    override val receiverType: KtType?
+        get() = withValidityAssertion { symbol.receiverType }
+    override val valueParameters: List<KtVariableLikeSignature<KtValueParameterSymbol>> by cached {
+        firSymbol.valueParameterSymbols.map { KtFirVariableLikeDummySignature(token, it, firSymbolBuilder) }
+    }
+
+    override fun substitute(substitutor: KtSubstitutor): KtFirFunctionLikeSignature<S> = withValidityAssertion {
+        if (substitutor is KtSubstitutor.Empty) return@withValidityAssertion this
+        require(substitutor is AbstractKtFirSubstitutor<*>)
+
+        KtFirFunctionLikeSubstitutorBasedSignature(token, firSymbol, firSymbolBuilder, substitutor.substitutor)
+    }
+}
+
+internal class KtFirFunctionLikeSubstitutorBasedSignature<out S : KtFunctionLikeSymbol>(
+    override val token: KtLifetimeToken,
+    override val firSymbol: FirFunctionSymbol<*>,
+    override val firSymbolBuilder: KtSymbolByFirBuilder,
+    override val coneSubstitutor: ConeSubstitutor = ConeSubstitutor.Empty,
+) : KtFirFunctionLikeSignature<S>(), SubstitutorBasedSignature {
+    @Suppress("UNCHECKED_CAST")
+    override val symbol: S
+        get() = withValidityAssertion { firSymbol.buildSymbol(firSymbolBuilder) as S }
     override val returnType: KtType by cached {
-        firSymbolBuilder.typeBuilder.buildKtType(firSymbol.resolvedReturnType)
+        firSymbolBuilder.typeBuilder.buildKtType(coneSubstitutor.substituteOrSelf(firSymbol.resolvedReturnType))
     }
     override val receiverType: KtType? by cached {
-        firSymbol.resolvedReceiverTypeRef?.let { firSymbolBuilder.typeBuilder.buildKtType(it) }
+        val receiverTypeRef = when (val fir = firSymbol.fir) {
+            is FirPropertyAccessor -> fir.propertySymbol.resolvedReceiverTypeRef
+            else -> firSymbol.resolvedReceiverTypeRef
+        }
+        receiverTypeRef?.let { firSymbolBuilder.typeBuilder.buildKtType(coneSubstitutor.substituteOrSelf(it.type)) }
     }
     override val valueParameters: List<KtVariableLikeSignature<KtValueParameterSymbol>> by cached {
-        ktSymbol.valueParameters.zip(firSymbol.fir.valueParameters).map { (ktValueParameterSymbol, firValueParameter) ->
-            KtFirValueParameterFirSymbolBasedSignature(ktValueParameterSymbol, firValueParameter.symbol, firSymbolBuilder)
+        firSymbol.fir.valueParameters.map { firValueParameter ->
+            KtFirVariableLikeSubstitutorBasedSignature(token, firValueParameter.symbol, firSymbolBuilder, coneSubstitutor)
         }
     }
+
+    override fun substitute(substitutor: KtSubstitutor): KtFirFunctionLikeSignature<S> = withValidityAssertion {
+        if (substitutor is KtSubstitutor.Empty) return@withValidityAssertion this
+        require(substitutor is AbstractKtFirSubstitutor<*>)
+        val chainedSubstitutor = ChainedSubstitutor(coneSubstitutor, substitutor.substitutor)
+
+        KtFirFunctionLikeSubstitutorBasedSignature(token, firSymbol, firSymbolBuilder, chainedSubstitutor)
+    }
 }
\ No newline at end of file
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/KtFirVariableLikeSignature.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/KtFirVariableLikeSignature.kt
index 57fc955..9ebe829 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/KtFirVariableLikeSignature.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/KtFirVariableLikeSignature.kt
@@ -6,76 +6,75 @@
 package org.jetbrains.kotlin.analysis.api.fir.signatures
 
 import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
+import org.jetbrains.kotlin.analysis.api.fir.buildSymbol
+import org.jetbrains.kotlin.analysis.api.fir.types.AbstractKtFirSubstitutor
 import org.jetbrains.kotlin.analysis.api.fir.utils.cached
-import org.jetbrains.kotlin.analysis.api.impl.base.types.KtChainedSubstitutor
+import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
 import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
 import org.jetbrains.kotlin.analysis.api.signatures.KtVariableLikeSignature
-import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
 import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.KtVariableSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.receiverType
 import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
 import org.jetbrains.kotlin.analysis.api.types.KtType
-import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
+import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
+import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
 import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
 import org.jetbrains.kotlin.fir.types.arrayElementType
 import org.jetbrains.kotlin.fir.types.coneType
+import org.jetbrains.kotlin.utils.addToStdlib.applyIf
 
-internal sealed class KtFirVariableLikeSignature<out S : KtVariableLikeSymbol>(ktSymbol: S) : KtVariableLikeSignature<S>(ktSymbol) {
+internal sealed class KtFirVariableLikeSignature<out S : KtVariableLikeSymbol> : KtVariableLikeSignature<S>(), FirSymbolBasedSignature {
     abstract override fun substitute(substitutor: KtSubstitutor): KtFirVariableLikeSignature<S>
 }
 
-internal class KtFirVariableLikeSubstitutorBasedSignature<out S : KtVariableLikeSymbol>(
-    override val signature: KtVariableLikeSignature<S>,
-    override val substitutor: KtSubstitutor,
-) : KtFirVariableLikeSignature<S>(signature.symbol), SubstitutorBasedSignature<KtVariableLikeSignature<S>> {
-    override val returnType: KtType by cached {
-        substitutor.substitute(signature.returnType)
-    }
-    override val receiverType: KtType? by cached {
-        signature.receiverType?.let { substitutor.substitute(it) }
-    }
-
-    override fun substitute(substitutor: KtSubstitutor): KtFirVariableLikeSignature<S> = when {
-        substitutor is KtSubstitutor.Empty -> this
-        else -> KtFirVariableLikeSubstitutorBasedSignature(signature, KtChainedSubstitutor(this.substitutor, substitutor))
-    }
-}
-
-internal open class KtFirVariableLikeSymbolBasedSignature<out S : KtVariableLikeSymbol>(
-    ktSymbol: S
-) : KtFirVariableLikeSignature<S>(ktSymbol) {
-    override fun substitute(substitutor: KtSubstitutor): KtFirVariableLikeSignature<S> = when {
-        substitutor is KtSubstitutor.Empty -> this
-        else -> KtFirVariableLikeSubstitutorBasedSignature(this, substitutor)
-    }
-}
-
-internal class KtFirPropertyFirSymbolBasedSignature(
-    ktSymbol: KtVariableSymbol,
-    override val firSymbol: FirPropertySymbol,
+internal class KtFirVariableLikeDummySignature<out S : KtVariableLikeSymbol>(
+    override val token: KtLifetimeToken,
+    override val firSymbol: FirVariableSymbol<*>,
     override val firSymbolBuilder: KtSymbolByFirBuilder,
-) : KtFirVariableLikeSymbolBasedSignature<KtVariableSymbol>(ktSymbol), FirSymbolBasedSignature<FirPropertySymbol> {
+) : KtFirVariableLikeSignature<S>() {
+    @Suppress("UNCHECKED_CAST")
+    override val symbol: S
+        get() = withValidityAssertion { firSymbol.buildSymbol(firSymbolBuilder) as S }
+    override val returnType: KtType
+        get() = withValidityAssertion { symbol.returnType }
+    override val receiverType: KtType?
+        get() = withValidityAssertion { symbol.receiverType }
+
+    override fun substitute(substitutor: KtSubstitutor): KtFirVariableLikeSignature<S> = withValidityAssertion {
+        if (substitutor is KtSubstitutor.Empty) return@withValidityAssertion this
+        require(substitutor is AbstractKtFirSubstitutor<*>)
+
+        KtFirVariableLikeSubstitutorBasedSignature(token, firSymbol, firSymbolBuilder, substitutor.substitutor)
+    }
+}
+
+internal class KtFirVariableLikeSubstitutorBasedSignature<out S : KtVariableLikeSymbol>(
+    override val token: KtLifetimeToken,
+    override val firSymbol: FirVariableSymbol<*>,
+    override val firSymbolBuilder: KtSymbolByFirBuilder,
+    override val coneSubstitutor: ConeSubstitutor = ConeSubstitutor.Empty,
+) : KtFirVariableLikeSignature<S>(), SubstitutorBasedSignature {
+    @Suppress("UNCHECKED_CAST")
+    override val symbol: S
+        get() = withValidityAssertion { firSymbol.buildSymbol(firSymbolBuilder) as S }
     override val returnType: KtType by cached {
-        firSymbolBuilder.typeBuilder.buildKtType(firSymbol.resolvedReturnType)
+        val isVarargValueParameter = (firSymbol as? FirValueParameterSymbol)?.isVararg == true
+        val coneType = firSymbol.resolvedReturnType.applyIf(isVarargValueParameter) { arrayElementType() ?: this }
+
+        firSymbolBuilder.typeBuilder.buildKtType(coneSubstitutor.substituteOrSelf(coneType))
     }
     override val receiverType: KtType? by cached {
         firSymbol.resolvedReceiverTypeRef?.let { typeRef ->
-            firSymbolBuilder.typeBuilder.buildKtType(typeRef.coneType)
+            firSymbolBuilder.typeBuilder.buildKtType(coneSubstitutor.substituteOrSelf(typeRef.coneType))
         }
     }
-}
 
-internal class KtFirValueParameterFirSymbolBasedSignature(
-    ktSymbol: KtValueParameterSymbol,
-    override val firSymbol: FirValueParameterSymbol,
-    override val firSymbolBuilder: KtSymbolByFirBuilder,
-) : KtFirVariableLikeSymbolBasedSignature<KtValueParameterSymbol>(ktSymbol), FirSymbolBasedSignature<FirValueParameterSymbol> {
-    override val returnType: KtType by cached {
-        var coneType = firSymbol.resolvedReturnType
-        if (firSymbol.isVararg) {
-            coneType = coneType.arrayElementType() ?: coneType
-        }
-        firSymbolBuilder.typeBuilder.buildKtType(coneType)
+    override fun substitute(substitutor: KtSubstitutor): KtFirVariableLikeSignature<S> = withValidityAssertion {
+        if (substitutor is KtSubstitutor.Empty) return@withValidityAssertion this
+        require(substitutor is AbstractKtFirSubstitutor<*>)
+        val chainedSubstitutor = ChainedSubstitutor(coneSubstitutor, substitutor.substitutor)
+
+        KtFirVariableLikeSubstitutorBasedSignature(token, firSymbol, firSymbolBuilder, chainedSubstitutor)
     }
-    override val receiverType: KtType? get() = withValidityAssertion { null }
 }
\ No newline at end of file
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/SubstitutorBasedSignature.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/SubstitutorBasedSignature.kt
index d498e91..f10c651 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/SubstitutorBasedSignature.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/signatures/SubstitutorBasedSignature.kt
@@ -5,10 +5,8 @@
 
 package org.jetbrains.kotlin.analysis.api.fir.signatures
 
-import org.jetbrains.kotlin.analysis.api.signatures.KtCallableSignature
-import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
+import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
 
-interface SubstitutorBasedSignature<out S : KtCallableSignature<*>> {
-    val signature: S
-    val substitutor: KtSubstitutor
+internal interface SubstitutorBasedSignature {
+    val coneSubstitutor: ConeSubstitutor
 }
\ No newline at end of file
diff --git a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/types/KtChainedSubstitutor.kt b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/types/KtChainedSubstitutor.kt
deleted file mode 100644
index fc30224..0000000
--- a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/types/KtChainedSubstitutor.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.analysis.api.impl.base.types
-
-import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
-import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
-import org.jetbrains.kotlin.analysis.api.types.KtType
-
-class KtChainedSubstitutor(val first: KtSubstitutor, val second: KtSubstitutor) : KtSubstitutor {
-    override val token: KtLifetimeToken get() = first.token
-    override fun substituteOrNull(type: KtType): KtType? = first.substituteOrNull(type)?.let { second.substituteOrNull(it) }
-}
\ No newline at end of file
diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt
index 0b240ac..3750aad 100644
--- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt
+++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/cases/components/testUtils.kt
@@ -33,12 +33,6 @@
 @OptIn(KtAnalysisApiInternals::class)
 internal fun KtAnalysisSession.stringRepresentation(any: Any): String = with(any) {
     fun KtType.render() = asStringForDebugging().replace('/', '.')
-    fun String.indented() = replace("\n", "\n  ")
-    fun Any.clazz() = when (this) {
-        is KtVariableLikeSignature<*> -> KtVariableLikeSignature::class
-        is KtFunctionLikeSignature<*> -> KtFunctionLikeSignature::class
-        else -> this::class
-    }
     return when (this) {
         is KtFunctionLikeSymbol -> buildString {
             append(
@@ -96,8 +90,9 @@
         is Enum<*> -> name
         is Name -> asString()
         is CallableId -> toString()
+        is KtCallableSignature<*> -> this.stringRepresentation()
         else -> buildString {
-            val clazz = this@with.clazz()
+            val clazz = this@with::class
             val className = clazz.simpleName!!
             append(className)
             appendLine(":")
@@ -119,6 +114,31 @@
     }
 }
 
+context(KtAnalysisSession)
+private fun KtCallableSignature<*>.stringRepresentation(): String = buildString {
+    when (this@stringRepresentation) {
+        is KtFunctionLikeSignature<*> -> append(KtFunctionLikeSignature::class.simpleName)
+        is KtVariableLikeSignature<*> -> append(KtVariableLikeSignature::class.simpleName)
+    }
+    appendLine(":")
+    val memberProperties = listOfNotNull(
+        KtVariableLikeSignature<*>::name.takeIf { this@stringRepresentation is KtVariableLikeSignature<*> },
+        KtCallableSignature<*>::receiverType,
+        KtCallableSignature<*>::returnType,
+        KtCallableSignature<*>::symbol,
+        KtFunctionLikeSignature<*>::valueParameters.takeIf { this@stringRepresentation is KtFunctionLikeSignature<*> },
+        KtCallableSignature<*>::callableIdIfNonLocal
+    )
+    memberProperties.joinTo(this, separator = "\n  ", prefix = "  ") { property ->
+        @Suppress("UNCHECKED_CAST")
+        val value = (property as KProperty1<Any, *>).get(this@stringRepresentation)
+        val valueAsString = value?.let { stringRepresentation(it).indented() }
+        "${property.name} = $valueAsString"
+    }
+}
+
+private fun String.indented() = replace("\n", "\n  ")
+
 internal fun KtAnalysisSession.prettyPrintSignature(signature: KtCallableSignature<*>): String = prettyPrint {
     when (signature) {
         is KtFunctionLikeSignature -> {
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/signatures/KtFunctionLikeSignature.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/signatures/KtFunctionLikeSignature.kt
index 94c4949..1e7421e 100644
--- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/signatures/KtFunctionLikeSignature.kt
+++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/signatures/KtFunctionLikeSignature.kt
@@ -5,29 +5,15 @@
 
 package org.jetbrains.kotlin.analysis.api.signatures
 
-import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
-import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
 import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
 import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.receiverType
 import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
 import org.jetbrains.kotlin.analysis.api.types.KtType
 
 /**
  * A signature of a function-like symbol. This includes functions, getters, setters, lambdas, etc.
  */
-public abstract class KtFunctionLikeSignature<out S : KtFunctionLikeSymbol>(
-    private val _symbol: S
-) : KtCallableSignature<S>() {
-    override val token: KtLifetimeToken
-        get() = _symbol.token
-    override val symbol: S
-        get() = withValidityAssertion { _symbol }
-    override val returnType: KtType
-        get() = withValidityAssertion { _symbol.returnType }
-    override val receiverType: KtType?
-        get() = withValidityAssertion { _symbol.receiverType }
-
+public abstract class KtFunctionLikeSignature<out S : KtFunctionLikeSymbol> : KtCallableSignature<S>() {
     /**
      * The use-site-substituted value parameters.
      */
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/signatures/KtVariableLikeSignature.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/signatures/KtVariableLikeSignature.kt
index e7b405a..10f3be4 100644
--- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/signatures/KtVariableLikeSignature.kt
+++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/signatures/KtVariableLikeSignature.kt
@@ -8,10 +8,8 @@
 import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo
 import org.jetbrains.kotlin.analysis.api.annotations.KtConstantAnnotationValue
 import org.jetbrains.kotlin.analysis.api.annotations.annotationsByClassId
-import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
 import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
 import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.receiverType
 import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
 import org.jetbrains.kotlin.analysis.api.types.KtType
 import org.jetbrains.kotlin.builtins.StandardNames
@@ -23,18 +21,7 @@
 /**
  * A signature of a variable-like symbol. This includes properties, enum entries local variables, etc.
  */
-public abstract class KtVariableLikeSignature<out S : KtVariableLikeSymbol>(
-    private val _symbol: S,
-) : KtCallableSignature<S>() {
-    override val token: KtLifetimeToken
-        get() = _symbol.token
-    override val symbol: S
-        get() = withValidityAssertion { _symbol }
-    override val returnType: KtType
-        get() = withValidityAssertion { _symbol.returnType }
-    override val receiverType: KtType?
-        get() = withValidityAssertion { _symbol.receiverType }
-
+public abstract class KtVariableLikeSignature<out S : KtVariableLikeSymbol> : KtCallableSignature<S>() {
     /**
      * A name of the variable with respect to the `@ParameterName` annotation. Can be different from the [KtVariableLikeSymbol.name].
      *