~ WIP
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt
index 460eb3f..83150b7 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt
@@ -30,7 +30,7 @@
 import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
 
 class Candidate(
-    override val symbol: FirBasedSymbol<*>,
+    override var symbol: FirBasedSymbol<*>,
     // Here we may have an ExpressionReceiverValue
     // - in case a use-site receiver is explicit
     // - in some cases with static entities, no matter is a use-site receiver explicit or not
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
index 4081787..10a3257 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt
@@ -23,6 +23,7 @@
 import org.jetbrains.kotlin.fir.resolve.initialTypeOfCandidate
 import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
 import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer
+import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveContext
 import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
 import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformerDispatcher
 import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
@@ -33,15 +34,16 @@
 import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
 import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
 import org.jetbrains.kotlin.fir.visitors.transformSingle
-import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.resolve.calls.inference.addEqualityConstraintIfCompatible
 import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
 import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
 import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode
 import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
 import org.jetbrains.kotlin.types.model.StubTypeMarker
+import org.jetbrains.kotlin.types.model.TypeConstructorMarker
 import org.jetbrains.kotlin.types.model.TypeVariableMarker
 import org.jetbrains.kotlin.types.model.safeSubstitute
+import org.jetbrains.kotlin.util.OperatorNameConventions
 import org.jetbrains.kotlin.utils.addToStdlib.runIf
 
 class FirCallCompleter(
@@ -83,6 +85,30 @@
             call.replaceLambdaArgumentInvocationKinds(session)
         }
 
+        if (inferenceSession.skipCompletion(call, resolutionMode, completionMode)) {
+            if (candidate.callInfo.name == OperatorNameConventions.PROVIDE_DELEGATE && resolutionMode != ResolutionMode.ContextDependentDelegate) {
+                val inferenceSession = inferenceSession as FirDelegatedPropertyInferenceSession
+
+                inferenceSession.currentConstraintSystem.clearCaches()
+                val innerSet = candidate.freshVariables.mapTo(mutableSetOf()) { it.typeConstructor }
+                @Suppress("UNCHECKED_CAST")
+                inferenceSession.currentConstraintSystem.relevantTypeVariables = innerSet as MutableSet<TypeConstructorMarker>
+
+                runCompletionForCall(candidate, ConstraintSystemCompletionMode.FULL, call, initialType, analyzer)
+
+                inferenceSession.currentConstraintSystem.clearCaches()
+                inferenceSession.currentConstraintSystem.relevantTypeVariables = null
+            } else {
+                runCompletionForCall(candidate, ConstraintSystemCompletionMode.PARTIAL, call, initialType, analyzer)
+            }
+            // Running completion at least partially is required to filter out some of the candidates of subsequent calls,
+            // thus avoiding resolution ambiguity for them.
+            // Can't use `completionCall` in case it's FULL, because we can't force getValue() completion until BI lambdas in delegate expression are completed
+            // But those lambdas cannot be found at getValeu() calls as they don't belong there
+
+            return call
+        }
+
         return when (completionMode) {
             ConstraintSystemCompletionMode.FULL -> {
                 if (inferenceSession.shouldRunCompletion(call)) {
@@ -91,7 +117,7 @@
                         .buildAbstractResultingSubstitutor(session.typeContext) as ConeSubstitutor
                     val completedCall = call.transformSingle(
                         FirCallCompletionResultsWriterTransformer(
-                            session, finalSubstitutor,
+                            session, components.scopeSession, finalSubstitutor,
                             components.returnTypeCalculator,
                             session.typeApproximator,
                             components.dataFlowAnalyzer,
@@ -111,12 +137,6 @@
             ConstraintSystemCompletionMode.PARTIAL -> {
                 runCompletionForCall(candidate, completionMode, call, initialType, analyzer)
 
-                // Add top-level delegate call as partially resolved to inference session
-                if (resolutionMode is ResolutionMode.ContextDependentDelegate) {
-                    require(inferenceSession is FirDelegatedPropertyInferenceSession)
-                    inferenceSession.addPartiallyResolvedCall(call)
-                }
-
                 call
             }
 
@@ -210,7 +230,7 @@
         mode: FirCallCompletionResultsWriterTransformer.Mode = FirCallCompletionResultsWriterTransformer.Mode.Normal
     ): FirCallCompletionResultsWriterTransformer {
         return FirCallCompletionResultsWriterTransformer(
-            session, substitutor, components.returnTypeCalculator,
+            session, components.scopeSession, substitutor, components.returnTypeCalculator,
             session.typeApproximator,
             components.dataFlowAnalyzer,
             components.integerLiteralAndOperatorApproximationTransformer,
@@ -325,16 +345,23 @@
                 )
             }
 
-            transformer.context.withAnonymousFunctionTowerDataContext(lambdaArgument.symbol) {
+            val context: BodyResolveContext = transformer.context
+            context.withAnonymousFunctionTowerDataContext(lambdaArgument.symbol) {
                 if (builderInferenceSession != null) {
-                    transformer.context.withInferenceSession(builderInferenceSession) {
+                    context.withInferenceSession(builderInferenceSession) {
                         lambdaArgument.transformSingle(transformer, ResolutionMode.LambdaResolution(expectedReturnTypeRef))
                     }
                 } else {
-                    lambdaArgument.transformSingle(transformer, ResolutionMode.LambdaResolution(expectedReturnTypeRef))
+                    context.withInferenceSession(
+                        if (context.inferenceSession is FirDelegatedPropertyInferenceSession) {
+                            FirInferenceSession.DEFAULT
+                        } else context.inferenceSession
+                    ) {
+                        lambdaArgument.transformSingle(transformer, ResolutionMode.LambdaResolution(expectedReturnTypeRef))
+                    }
                 }
             }
-            transformer.context.dropContextForAnonymousFunction(lambdaArgument)
+            context.dropContextForAnonymousFunction(lambdaArgument)
 
             val returnArguments = components.dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambdaArgument)
 
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt
index a40d858..d4a4b2a 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirDelegatedPropertyInferenceSession.kt
@@ -6,22 +6,28 @@
 package org.jetbrains.kotlin.fir.resolve.inference
 
 import org.jetbrains.kotlin.fir.declarations.FirProperty
+import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
+import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin
 import org.jetbrains.kotlin.fir.expressions.FirResolvable
 import org.jetbrains.kotlin.fir.expressions.FirStatement
-import org.jetbrains.kotlin.fir.resolve.calls.*
-import org.jetbrains.kotlin.fir.resolve.inference.model.ConeFixVariableConstraintPosition
-import org.jetbrains.kotlin.fir.resolve.substitution.*
+import org.jetbrains.kotlin.fir.resolve.ResolutionMode
+import org.jetbrains.kotlin.fir.resolve.calls.Candidate
+import org.jetbrains.kotlin.fir.resolve.calls.InferenceError
+import org.jetbrains.kotlin.fir.resolve.calls.ResolutionContext
+import org.jetbrains.kotlin.fir.resolve.calls.candidate
+import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
+import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
 import org.jetbrains.kotlin.fir.types.*
+import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
-import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
 import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
 import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionContext
 import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintSystemCompletionMode
-import org.jetbrains.kotlin.resolve.calls.inference.model.BuilderInferencePosition
 import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
 import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
-import org.jetbrains.kotlin.resolve.calls.inference.registerTypeVariableIfNotPresent
-import org.jetbrains.kotlin.types.model.*
+import org.jetbrains.kotlin.types.model.TypeConstructorMarker
+import org.jetbrains.kotlin.types.model.TypeVariableMarker
+import org.jetbrains.kotlin.util.OperatorNameConventions
 
 class FirDelegatedPropertyInferenceSession(
     val property: FirProperty,
@@ -29,141 +35,74 @@
     private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
 ) : FirInferenceSessionForChainedResolve(resolutionContext) {
 
-    private val currentConstraintSystem = components.session.inferenceComponents.createConstraintSystem()
-    override val currentConstraintStorage: ConstraintStorage get() = currentConstraintSystem.currentStorage()
+    var currentConstraintSystem = components.session.inferenceComponents.createConstraintSystem()
+    override val currentConstraintStorage: ConstraintStorage
+        get() {
+            return currentConstraintSystem.currentStorage()
+        }
 
     private val unitType: ConeClassLikeType = components.session.builtinTypes.unitType.type
-    private lateinit var resultingConstraintSystem: NewConstraintSystem
-
-    private fun ConeKotlinType.containsStubType(): Boolean {
-        return this.contains {
-            it is ConeStubTypeForChainInference
-        }
-    }
-
-    private fun integrateResolvedCall(storage: ConstraintStorage) {
-        registerSyntheticVariables(storage)
-        val stubToTypeVariableSubstitutor = createToSyntheticTypeVariableSubstitutor()
-        integrateConstraints(
-            currentConstraintSystem,
-            storage,
-            stubToTypeVariableSubstitutor,
-            false
-        )
-    }
 
     override fun <T> addCompletedCall(call: T, candidate: Candidate) where T : FirResolvable, T : FirStatement {
-        partiallyResolvedCalls += call to candidate
-        if (candidate.isSuccessful) {
-            integrateResolvedCall(candidate.system.asReadOnlyStorage())
-        }
+        // TODO
     }
 
     override fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement {
-        super.addPartiallyResolvedCall(call)
-        if (call.candidate.isSuccessful) {
-            integrateResolvedCall(call.candidate.system.currentStorage())
-        }
+        // TODO
     }
 
-    override fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement {
-        val callee = call.calleeReference as? FirNamedReferenceWithCandidate ?: return true
+    override fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement = true
 
-        if (callee.candidate.system.hasContradiction) return true
+    override fun <T> skipCompletion(
+        call: T,
+        resolutionMode: ResolutionMode,
+        completionMode: ConstraintSystemCompletionMode
+    ): Boolean where T : FirResolvable, T : FirStatement {
+        if (!call.candidate.isSuccessful && call.isOperatorCallWithName { it == OperatorNameConventions.PROVIDE_DELEGATE }) return false
+        // Do not run completion for provideDelegate/getValue/setValue because they might affect each other
+        if (completionMode == ConstraintSystemCompletionMode.FULL && resolutionMode == ResolutionMode.ContextDependentDelegate) return false
 
-        val hasStubType =
-            callee.candidate.chosenExtensionReceiver?.typeRef?.coneType?.containsStubType() ?: false
-                    || callee.candidate.dispatchReceiver?.typeRef?.coneType?.containsStubType() ?: false
-
-        if (!hasStubType) {
+        if (resolutionMode == ResolutionMode.ContextDependentDelegate || call.isAnyOfDelegateOperators()) {
+            partiallyResolvedCalls.add(call to call.candidate)
+            currentConstraintSystem = call.candidate.system
             return true
         }
 
-        val system = call.candidate.system
-
-        val storage = system.getBuilder().currentStorage()
-
-        if (call.hasPostponed()) return true
-
-        return storage.notFixedTypeVariables.keys.all {
-            val variable = storage.allTypeVariables[it]
-            val isPostponed = variable != null && variable in storage.postponedTypeVariables
-            isPostponed || isSyntheticTypeVariable(variable!!) ||
-                    components.callCompleter.completer.variableFixationFinder.isTypeVariableHasProperConstraint(system, it)
-        }
+        return false
     }
 
-    private fun FirStatement.hasPostponed(): Boolean {
-        var result = false
-        processAllContainingCallCandidates(processBlocks = false) {
-            result = result || it.hasPostponed()
-        }
-        return result
+    private fun <T> T.isAnyOfDelegateOperators(): Boolean where T : FirResolvable, T : FirStatement = isOperatorCallWithName {
+        it == OperatorNameConventions.PROVIDE_DELEGATE || it == OperatorNameConventions.GET_VALUE || it == OperatorNameConventions.SET_VALUE
     }
 
-    private fun Candidate.hasPostponed(): Boolean {
-        return postponedAtoms.any { !it.analyzed }
+    private fun <T> T.isOperatorCallWithName(predicate: (Name) -> Boolean): Boolean where T : FirResolvable, T : FirStatement {
+        if (this !is FirFunctionCall) return false
+        val name = calleeReference.name
+        if (!predicate(name)) return false
+
+        return origin == FirFunctionCallOrigin.Operator
     }
 
+
     override fun inferPostponedVariables(
         lambda: ResolvedLambdaAtom,
         constraintSystemBuilder: ConstraintSystemBuilder,
         completionMode: ConstraintSystemCompletionMode
     ): Map<ConeTypeVariableTypeConstructor, ConeKotlinType>? = null
 
-    private fun createNonFixedTypeToVariableSubstitutor(): NotFixedTypeToVariableSubstitutorForDelegateInference {
-        val typeContext = components.session.typeContext
-
-        val bindings = mutableMapOf<TypeVariableMarker, ConeKotlinType>()
-        for ((variable, synthetic) in syntheticTypeVariableByTypeVariable) {
-            bindings[synthetic] = variable.defaultType(typeContext) as ConeKotlinType
-        }
-
-        return NotFixedTypeToVariableSubstitutorForDelegateInference(bindings, typeContext)
-    }
-
-
-    /*
-     * This creates Stub-preserving substitution to synthetic type variables
-     * Stub(R) => Stub(_R)
-     * R => _R
-     */
-    private fun createToSyntheticTypeVariableSubstitutor(): ConeSubstitutor {
-
-        val typeContext = components.session.typeContext
-        val bindings = mutableMapOf<TypeConstructorMarker, ConeKotlinType>()
-        for ((variable, syntheticVariable) in syntheticTypeVariableByTypeVariable) {
-            bindings[variable.freshTypeConstructor(typeContext)] = syntheticVariable.defaultType
-        }
-
-        return typeContext.typeSubstitutorByTypeConstructor(bindings)
-    }
-
-    override fun hasSyntheticTypeVariables(): Boolean {
-        return syntheticTypeVariableByTypeVariable.isNotEmpty()
-    }
-
-    override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean {
-        return typeVariable in syntheticTypeVariableByTypeVariable.values
+    override fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map<TypeConstructorMarker, ConeStubType> {
+        TODO("Not yet implemented")
     }
 
     override fun fixSyntheticTypeVariableWithNotEnoughInformation(
         typeVariable: TypeVariableMarker,
         completionContext: ConstraintSystemCompletionContext
     ) {
-        typeVariable as ConeTypeVariable
-        completionContext.fixVariable(
-            typeVariable,
-            ConeStubTypeForSyntheticFixation(
-                ConeStubTypeConstructor(typeVariable, isTypeVariableInSubtyping = false, isForFixation = true),
-                ConeNullability.create(typeVariable.defaultType.isMarkedNullable)
-            ),
-            ConeFixVariableConstraintPosition(typeVariable)
-        )
+        error("")
     }
 
     fun completeCandidates(): List<FirResolvable> {
-        val commonSystem = components.session.inferenceComponents.createConstraintSystem()
+        val commonSystem = currentConstraintSystem
 
         val notCompletedCalls = partiallyResolvedCalls.mapNotNull { partiallyResolvedCall ->
             partiallyResolvedCall.first.takeIf { resolvable ->
@@ -171,20 +110,6 @@
             }
         }
 
-        val stubToTypeVariableSubstitutor = createNonFixedTypeToVariableSubstitutor()
-
-        for ((call, candidate) in partiallyResolvedCalls) {
-            if (candidate.isSuccessful) {
-                integrateConstraints(
-                    commonSystem,
-                    candidate.system.asReadOnlyStorage(),
-                    stubToTypeVariableSubstitutor,
-                    call.candidate() != null
-                )
-            }
-        }
-
-
         resolutionContext.bodyResolveContext.withInferenceSession(DEFAULT) {
             @Suppress("UNCHECKED_CAST")
             components.callCompleter.completer.complete(
@@ -218,97 +143,18 @@
             }
         }
 
-        resultingConstraintSystem = commonSystem
         return notCompletedCalls
     }
 
     fun createFinalSubstitutor(): ConeSubstitutor {
-        val stubTypeSubstitutor = createNonFixedTypeToVariableSubstitutor()
-
         val typeContext = components.session.typeContext
-        val resultSubstitutor = resultingConstraintSystem.asReadOnlyStorage()
+        val t = currentConstraintSystem.asReadOnlyStorage()
             .buildAbstractResultingSubstitutor(typeContext) as ConeSubstitutor
-        return ChainedSubstitutor(stubTypeSubstitutor, resultSubstitutor)
-            .replaceStubsAndTypeVariablesToErrors(typeContext, stubTypesByTypeVariable.values.map { it.constructor })
+
+        return ChainedSubstitutor(t, t)
     }
 
-    private val stubTypesByTypeVariable: MutableMap<ConeTypeVariable, ConeStubType> = mutableMapOf()
-    private val syntheticTypeVariableByTypeVariable = mutableMapOf<TypeVariableMarker, ConeTypeVariable>()
+    override fun hasSyntheticTypeVariables(): Boolean = false
 
-    private fun registerSyntheticVariables(storage: ConstraintStorage) {
-        for (variableWithConstraints in storage.notFixedTypeVariables.values) {
-            val variable = variableWithConstraints.typeVariable as ConeTypeVariable
-
-            val syntheticVariable = syntheticTypeVariableByTypeVariable.getOrPut(variable) {
-                ConeTypeVariable("_" + variable.typeConstructor.name).also {
-                    currentConstraintSystem.registerVariable(it)
-                }
-            }
-
-            stubTypesByTypeVariable.getOrPut(variable) {
-                ConeStubTypeForChainInference(
-                    syntheticVariable,
-                    ConeNullability.create(syntheticVariable.defaultType.isMarkedNullable)
-                )
-            }
-        }
-    }
-
-    override fun createSyntheticStubTypes(system: NewConstraintSystemImpl): Map<TypeConstructorMarker, ConeStubType> {
-
-        val bindings = mutableMapOf<TypeConstructorMarker, ConeStubType>()
-        registerSyntheticVariables(system.currentStorage())
-        for (variable in system.postponedTypeVariables) {
-            variable as ConeTypeVariable
-
-            bindings[variable.typeConstructor] = stubTypesByTypeVariable[variable]!!
-        }
-
-        return bindings
-    }
-
-    override fun registerStubTypes(map: Map<TypeVariableMarker, StubTypeMarker>) {
-//        @Suppress("UNCHECKED_CAST")
-//        stubTypesByTypeVariable.putAll(map as Map<ConeTypeVariable, ConeStubType>)
-    }
-
-
-    private fun integrateConstraints(
-        commonSystem: NewConstraintSystemImpl,
-        storage: ConstraintStorage,
-        nonFixedToVariablesSubstitutor: ConeSubstitutor,
-        shouldIntegrateAllConstraints: Boolean
-    ) {
-        if (shouldIntegrateAllConstraints) {
-            storage.notFixedTypeVariables.values.forEach {
-                if (isSyntheticTypeVariable(it.typeVariable)) return@forEach
-                commonSystem.registerTypeVariableIfNotPresent(it.typeVariable)
-            }
-        }
-        /*
-        * storage can contain the following substitutions:
-        *  TypeVariable(A) -> ProperType
-        *  TypeVariable(B) -> Special-Non-Fixed-Type
-        *
-        * while substitutor from parameter map non-fixed types to the original type variable
-        * */
-        val callSubstitutor =
-            storage.buildAbstractResultingSubstitutor(commonSystem, transformTypeVariablesToErrorTypes = false) as ConeSubstitutor
-
-        for (initialConstraint in storage.initialConstraints) {
-            integrateConstraintToSystem(
-                commonSystem, initialConstraint, callSubstitutor, nonFixedToVariablesSubstitutor, storage.fixedTypeVariables
-            )
-        }
-
-        if (shouldIntegrateAllConstraints) {
-            for ((variableConstructor, type) in storage.fixedTypeVariables) {
-                val typeVariable = storage.allTypeVariables.getValue(variableConstructor)
-                if (isSyntheticTypeVariable(typeVariable)) continue
-
-                commonSystem.registerTypeVariableIfNotPresent(typeVariable)
-                commonSystem.addEqualityConstraint((typeVariable as ConeTypeVariable).defaultType, type, BuilderInferencePosition)
-            }
-        }
-    }
+    override fun isSyntheticTypeVariable(typeVariable: TypeVariableMarker): Boolean = false
 }
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt
index 3e7f83d..ccbbfd2 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirInferenceSession.kt
@@ -7,6 +7,7 @@
 
 import org.jetbrains.kotlin.fir.expressions.FirResolvable
 import org.jetbrains.kotlin.fir.expressions.FirStatement
+import org.jetbrains.kotlin.fir.resolve.ResolutionMode
 import org.jetbrains.kotlin.fir.resolve.calls.Candidate
 import org.jetbrains.kotlin.fir.types.ConeKotlinType
 import org.jetbrains.kotlin.fir.types.ConeStubType
@@ -26,6 +27,11 @@
     }
 
     abstract fun <T> shouldRunCompletion(call: T): Boolean where T : FirResolvable, T : FirStatement
+    open fun <T> skipCompletion(
+        call: T,
+        resolutionMode: ResolutionMode,
+        completionMode: ConstraintSystemCompletionMode
+    ): Boolean where T : FirResolvable, T : FirStatement = false
     abstract val currentConstraintStorage: ConstraintStorage
 
     abstract fun <T> addPartiallyResolvedCall(call: T) where T : FirResolvable, T : FirStatement
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt
index aa90ddd..4e2389f 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt
@@ -30,12 +30,16 @@
 import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterInQualifiedAccess
 import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom
 import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
+import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
 import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.*
+import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator
 import org.jetbrains.kotlin.fir.scopes.impl.ConvertibleIntegerOperators.binaryOperatorsWithSignedArgument
+import org.jetbrains.kotlin.fir.scopes.impl.FirClassSubstitutionScope
 import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperator
 import org.jetbrains.kotlin.fir.scopes.impl.isWrappedIntegerOperatorForUnsignedType
 import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
 import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
+import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
 import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
 import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
 import org.jetbrains.kotlin.fir.types.*
@@ -58,6 +62,7 @@
 
 class FirCallCompletionResultsWriterTransformer(
     override val session: FirSession,
+    private val scopeSession: ScopeSession,
     private val finalSubstitutor: ConeSubstitutor,
     private val typeCalculator: ReturnTypeCalculator,
     private val typeApproximator: ConeTypeApproximator,
@@ -101,6 +106,9 @@
         qualifiedAccessExpression: T, calleeReference: FirNamedReferenceWithCandidate,
     ): T {
         val subCandidate = calleeReference.candidate
+
+        subCandidate.refineSubstitutedSymbol()
+
         val declaration = subCandidate.symbol.fir
         val typeArguments = computeTypeArguments(qualifiedAccessExpression, subCandidate)
         val typeRef = if (declaration is FirCallableDeclaration) {
@@ -134,6 +142,12 @@
             }
         }
 
+        if (mode == Mode.DelegatedPropertyCompletion) {
+            // Update type for `$delegateField` in `$$delegateField.get/setValue()` calls inside accessors
+            val typeUpdater = TypeUpdaterForDelegateArguments()
+            qualifiedAccessExpression.transformExplicitReceiver(typeUpdater, null)
+        }
+
         var dispatchReceiver = subCandidate.dispatchReceiverExpression()
         var extensionReceiver = subCandidate.chosenExtensionReceiverExpression()
         if (!declaration.isWrappedIntegerOperator()) {
@@ -169,18 +183,58 @@
         return qualifiedAccessExpression
     }
 
+    private fun Candidate.refineSubstitutedSymbol() {
+        val updatedSymbol = symbol.refineSubstitutedSymbol() ?: return
+        val oldSymbol = symbol
+        symbol = updatedSymbol
+
+        if (updatedSymbol !is FirFunctionSymbol) return
+        require(oldSymbol is FirFunctionSymbol)
+
+        val oldArgumentMapping = argumentMapping ?: return
+        val oldValueParametersToNewMap = oldSymbol.valueParameterSymbols.zip(updatedSymbol.valueParameterSymbols).toMap()
+
+        argumentMapping = oldArgumentMapping.mapValuesTo(linkedMapOf()) {
+            oldValueParametersToNewMap[it.value.symbol]!!.fir
+        }
+
+        substitutor = substitutorByMap(
+            updatedSymbol.typeParameterSymbols.zip(freshVariables).associate { (typeParameter, typeVariable) ->
+                typeParameter to typeVariable.defaultType
+            },
+            session,
+        )
+    }
+
+    private fun FirBasedSymbol<*>.refineSubstitutedSymbol(): FirBasedSymbol<*>? {
+        val fir = fir
+        if (fir !is FirCallableDeclaration) return null
+
+        val dispatchReceiverType = fir.dispatchReceiverType ?: return null
+        val updatedDispatchReceiverType = finalSubstitutor.substituteOrNull(dispatchReceiverType) ?: return null
+
+        val scope =
+            updatedDispatchReceiverType.scope(
+                session,
+                scopeSession,
+                FakeOverrideTypeCalculator.DoNothing,
+                FirResolvePhase.STATUS
+            ) as? FirClassSubstitutionScope ?: return null
+
+        return when (val original = fir.originalForSubstitutionOverride) {
+            is FirSimpleFunction -> scope.createSubstitutionOverrideFunction(original.symbol)
+            is FirProperty -> scope.createSubstitutionOverrideProperty(original.symbol)
+            is FirConstructor -> scope.createSubstitutionOverrideConstructor(original.symbol)
+            else -> error("!!!")
+        }
+    }
+
     override fun transformQualifiedAccessExpression(
         qualifiedAccessExpression: FirQualifiedAccessExpression,
         data: ExpectedArgumentType?,
     ): FirStatement {
         val calleeReference = qualifiedAccessExpression.calleeReference as? FirNamedReferenceWithCandidate
-            ?: return run {
-                if (mode == Mode.DelegatedPropertyCompletion) {
-                    val typeUpdater = TypeUpdaterForDelegateArguments()
-                    qualifiedAccessExpression.transformSingle(typeUpdater, null)
-                }
-                qualifiedAccessExpression
-            }
+            ?: return qualifiedAccessExpression
         val result = prepareQualifiedTransform(qualifiedAccessExpression, calleeReference)
         val typeRef = result.typeRef as FirResolvedTypeRef
         val subCandidate = calleeReference.candidate
@@ -190,11 +244,6 @@
         result.replaceTypeRef(resultType)
         session.lookupTracker?.recordTypeResolveAsLookup(resultType, qualifiedAccessExpression.source, context.file.source)
 
-        if (mode == Mode.DelegatedPropertyCompletion) {
-            val typeUpdater = TypeUpdaterForDelegateArguments()
-            result.transformExplicitReceiver(typeUpdater, null)
-        }
-
         return result
     }
 
@@ -242,12 +291,6 @@
         result.replaceTypeRef(resultType)
         session.lookupTracker?.recordTypeResolveAsLookup(resultType, functionCall.source, context.file.source)
 
-        if (mode == Mode.DelegatedPropertyCompletion) {
-            val typeUpdater = TypeUpdaterForDelegateArguments()
-            result.argumentList.transformArguments(typeUpdater, null)
-            result.transformExplicitReceiver(typeUpdater, null)
-        }
-
         if (enableArrayOfCallTransformation) {
             return arrayOfCallTransformer.transformFunctionCall(result, session)
         }
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt
index b23fb7b..afe9b87 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt
@@ -35,7 +35,8 @@
 import org.jetbrains.kotlin.fir.resolve.inference.FirStubTypeTransformer
 import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom
 import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionType
-import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor
+import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor
+import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
 import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer
 import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolver
 import org.jetbrains.kotlin.fir.resolve.transformers.contracts.runContractResolveForFunction
@@ -47,6 +48,7 @@
 import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource
 import org.jetbrains.kotlin.fir.visitors.FirTransformer
 import org.jetbrains.kotlin.fir.visitors.transformSingle
+import org.jetbrains.kotlin.resolve.calls.inference.buildCurrentSubstitutor
 
 open class FirDeclarationsResolveTransformer(
     transformer: FirAbstractBodyResolveTransformerDispatcher
@@ -288,6 +290,7 @@
 
             val finalSubstitutor = createFinalSubstitutor()
 
+            // TODO: Replace just property/accessors return types instead
             val stubTypeCompletionResultsWriter = FirStubTypeTransformer(finalSubstitutor)
             property.transformSingle(stubTypeCompletionResultsWriter, null)
             property.replaceReturnTypeRef(
@@ -334,18 +337,10 @@
         if (delegateExpression is FirResolvable) {
             val calleeReference = delegateExpression.calleeReference
             if (calleeReference is FirNamedReferenceWithCandidate) {
-                val system = calleeReference.candidate.system
-                system.notFixedTypeVariables.forEach {
-                    system.markPostponedVariable(it.value.typeVariable)
-                }
-                val typeVariableTypeToStubType = context.inferenceSession.createSyntheticStubTypes(system)
-
-                val substitutor = createTypeSubstitutorByTypeConstructor(
-                    typeVariableTypeToStubType, session.typeContext, approximateIntegerLiterals = true
-                )
                 val delegateExpressionTypeRef = delegateExpression.typeRef
-                val stubTypeSubstituted = substitutor.substituteOrNull(delegateExpressionTypeRef.coneType)
-                delegateExpression.replaceTypeRef(delegateExpressionTypeRef.withReplacedConeType(stubTypeSubstituted))
+                val returnTypeSubstitutedWithTypeVariables =
+                    calleeReference.candidate.substitutor.substituteOrNull(delegateExpressionTypeRef.coneType)
+                delegateExpression.replaceTypeRef(delegateExpressionTypeRef.withReplacedConeType(returnTypeSubstitutedWithTypeVariables))
             }
         }
 
@@ -356,28 +351,23 @@
         // TODO: this generates some nodes in the control flow graph which we don't want if we
         //  end up not selecting this option, KT-59684
         transformer.expressionsTransformer.transformFunctionCallInternal(
-            provideDelegateCall, ResolutionMode.ContextIndependent, provideDelegate = true
+            provideDelegateCall, ResolutionMode.ContextIndependent, skipExplicitReceiverTransformation = true
         )
 
         // If we got successful candidate for provideDelegate, let's select it
         val provideDelegateCandidate = provideDelegateCall.candidate()
         if (provideDelegateCandidate != null && provideDelegateCandidate.isSuccessful) {
-            val system = provideDelegateCandidate.system
-            system.notFixedTypeVariables.forEach {
-                system.markPostponedVariable(it.value.typeVariable)
-            }
-            val typeVariableTypeToStubType = context.inferenceSession.createSyntheticStubTypes(system)
-            val substitutor = createTypeSubstitutorByTypeConstructor(
-                typeVariableTypeToStubType, session.typeContext, approximateIntegerLiterals = true
+            val substitutor = ChainedSubstitutor(
+                provideDelegateCandidate.substitutor,
+                context.inferenceSession.currentConstraintStorage.buildCurrentSubstitutor(
+                    session.typeContext, emptyMap()
+                ) as ConeSubstitutor
             )
 
-            val stubTypeSubstituted = substitutor.substituteOrSelf(
-                provideDelegateCandidate.substitutor.substituteOrSelf(
-                    components.typeFromCallee(provideDelegateCall).type
-                )
-            )
+            val toTypeVariableSubstituted =
+                substitutor.substituteOrSelf(components.typeFromCallee(provideDelegateCall).type)
 
-            provideDelegateCall.replaceTypeRef(provideDelegateCall.typeRef.resolvedTypeFromPrototype(stubTypeSubstituted))
+            provideDelegateCall.replaceTypeRef(provideDelegateCall.typeRef.resolvedTypeFromPrototype(toTypeVariableSubstituted))
             return provideDelegateCall
         }
 
diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
index a7f640b..ca9c7b7 100644
--- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
+++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt
@@ -29,6 +29,8 @@
 import org.jetbrains.kotlin.fir.resolve.*
 import org.jetbrains.kotlin.fir.resolve.calls.*
 import org.jetbrains.kotlin.fir.resolve.diagnostics.*
+import org.jetbrains.kotlin.fir.resolve.inference.FirDelegatedPropertyInferenceSession
+import org.jetbrains.kotlin.fir.resolve.inference.FirInferenceSession
 import org.jetbrains.kotlin.fir.resolve.inference.FirStubInferenceSession
 import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
 import org.jetbrains.kotlin.fir.resolve.transformers.replaceLambdaArgumentInvocationKinds
@@ -393,12 +395,14 @@
     }
 
     override fun transformFunctionCall(functionCall: FirFunctionCall, data: ResolutionMode): FirStatement =
-        transformFunctionCallInternal(functionCall, data, provideDelegate = false)
+        transformFunctionCallInternal(functionCall, data, skipExplicitReceiverTransformation = false)
 
     internal fun transformFunctionCallInternal(
         functionCall: FirFunctionCall,
         data: ResolutionMode,
-        provideDelegate: Boolean,
+        // Currently, it's only `true` for provideDelegate calls, because delegateExpression is already resolved as that stage.
+        // See also FirDeclarationsResolveTransformer.transformWrappedDelegateExpression
+        skipExplicitReceiverTransformation: Boolean,
     ): FirStatement =
         whileAnalysing(session, functionCall) {
             val calleeReference = functionCall.calleeReference
@@ -420,19 +424,21 @@
             functionCall.transformAnnotations(transformer, data)
             functionCall.replaceLambdaArgumentInvocationKinds(session)
             functionCall.transformTypeArguments(transformer, ResolutionMode.ContextIndependent)
-            val initialExplicitReceiver = functionCall.explicitReceiver
-            val withTransformedArguments = if (!resolvingAugmentedAssignment) {
-                dataFlowAnalyzer.enterCallArguments(functionCall, functionCall.arguments)
-                // In provideDelegate mode the explicitReceiver is already resolved
-                // E.g. we have val some by someDelegate
-                // At 1st stage of delegate inference we resolve someDelegate itself,
-                // at 2nd stage in provideDelegate mode we are trying to resolve someDelegate.provideDelegate(),
-                // and 'someDelegate' explicit receiver is resolved at 1st stage
-                // See also FirDeclarationsResolveTransformer.transformWrappedDelegateExpression
-                val withResolvedExplicitReceiver = if (provideDelegate) functionCall else transformExplicitReceiver(functionCall)
+
+                    val initialExplicitReceiver = functionCall.explicitReceiver
+                    val withTransformedArguments = if (!resolvingAugmentedAssignment) {
+                        dataFlowAnalyzer.enterCallArguments(functionCall, functionCall.arguments)
+                        val withResolvedExplicitReceiver =
+                            if (skipExplicitReceiverTransformation) functionCall else transformExplicitReceiver(functionCall)
                 withResolvedExplicitReceiver.also {
-                    it.replaceArgumentList(it.argumentList.transform(this, ResolutionMode.ContextDependent))
-                    dataFlowAnalyzer.exitCallArguments()
+                    context.withInferenceSession(
+                                if (context.inferenceSession is FirDelegatedPropertyInferenceSession) {
+                                    FirInferenceSession.DEFAULT
+                                } else context.inferenceSession
+                            ) {
+                                it.replaceArgumentList(it.argumentList.transform(this, ResolutionMode.ContextDependent))
+                                dataFlowAnalyzer.exitCallArguments()
+                            }
                 }
             } else {
                 functionCall
@@ -1235,18 +1241,20 @@
         annotationCall: FirAnnotationCall,
         data: ResolutionMode
     ): FirStatement = whileAnalysing(session, annotationCall) {
-        if (annotationCall.resolved) return annotationCall
-        annotationCall.transformAnnotationTypeRef(transformer, ResolutionMode.ContextIndependent)
-        annotationCall.replaceAnnotationResolvePhase(FirAnnotationResolvePhase.Types)
-        return context.forAnnotation {
-            withFirArrayOfCallTransformer {
-                dataFlowAnalyzer.enterAnnotation()
-                val result = callResolver.resolveAnnotationCall(annotationCall)
-                dataFlowAnalyzer.exitAnnotation()
-                if (result == null) return annotationCall
-                callCompleter.completeCall(result, ResolutionMode.ContextIndependent)
-                (result.argumentList as FirResolvedArgumentList).let { annotationCall.replaceArgumentMapping((it).toAnnotationArgumentMapping()) }
-                annotationCall
+        context.withInferenceSession(FirInferenceSession.DEFAULT) {
+            if (annotationCall.resolved) return annotationCall
+            annotationCall.transformAnnotationTypeRef(transformer, ResolutionMode.ContextIndependent)
+            annotationCall.replaceAnnotationResolvePhase(FirAnnotationResolvePhase.Types)
+            context.forAnnotation {
+                withFirArrayOfCallTransformer {
+                    dataFlowAnalyzer.enterAnnotation()
+                    val result = callResolver.resolveAnnotationCall(annotationCall)
+                    dataFlowAnalyzer.exitAnnotation()
+                    if (result == null) return annotationCall
+                    callCompleter.completeCall(result, ResolutionMode.ContextIndependent)
+                    (result.argumentList as FirResolvedArgumentList).let { annotationCall.replaceArgumentMapping((it).toAnnotationArgumentMapping()) }
+                    annotationCall
+                }
             }
         }
     }
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt
index 4f725e3..199a7e9 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/components/VariableFixationFinder.kt
@@ -27,6 +27,7 @@
         val fixedTypeVariables: Map<TypeConstructorMarker, KotlinTypeMarker>
         val postponedTypeVariables: List<TypeVariableMarker>
         val constraintsFromAllForkPoints: MutableList<Pair<IncorporationConstraintPosition, ForkPointData>>
+        val relevantTypeVariables: Set<TypeConstructorMarker>?
 
         fun isReified(variable: TypeVariableMarker): Boolean
     }
@@ -182,7 +183,10 @@
                 && !c.isNullabilityConstraint
 
     private fun Context.isProperType(type: KotlinTypeMarker): Boolean =
-        isProperTypeForFixation(type) { t -> !t.contains { notFixedTypeVariables.containsKey(it.typeConstructor()) } }
+        isProperTypeForFixation(type) { t -> !t.contains { isNotFixedRelevantVariable(it) } }
+
+    private fun Context.isNotFixedRelevantVariable(it: KotlinTypeMarker) =
+        (relevantTypeVariables == null || relevantTypeVariables!!.contains(it.typeConstructor())) && notFixedTypeVariables.containsKey(it.typeConstructor())
 
     private fun Context.isReified(variable: TypeConstructorMarker): Boolean =
         notFixedTypeVariables[variable]?.typeVariable?.let { isReified(it) } ?: false
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt
index a47f80a..60237cd 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt
@@ -44,8 +44,15 @@
     private val intersectionTypesCache: MutableMap<Collection<KotlinTypeMarker>, EmptyIntersectionTypeInfo?> = mutableMapOf()
     private var couldBeResolvedWithUnrestrictedBuilderInference: Boolean = false
 
+    override var relevantTypeVariables: MutableSet<TypeConstructorMarker>? = null
+
     override var atCompletionState: Boolean = false
 
+    fun clearCaches() {
+        properTypesCache.clear()
+        notProperTypesCache.clear()
+    }
+
     private enum class State {
         BUILDING,
         TRANSACTION,
@@ -317,6 +324,9 @@
                 it
 
             if (typeToCheck == null) return@contains false
+            if (relevantTypeVariables != null) {
+                return@contains relevantTypeVariables!!.contains(typeToCheck.typeConstructor())
+            }
 
             storage.allTypeVariables.containsKey(typeToCheck.typeConstructor())
         }