[LL FIR] rebind returnTarget for delegate accessors during psi2fir

It is safe to rebind returnTarget to the original declaration during
psi2fir as it doesn't affect the resolution. We already have the same
logic for regular functions/property accessors.
This change is crucial in the context of parallel implicit type
resolution because it affects CFG builder in a bad way in the case
of on-air resolution

^KT-56551
This commit is contained in:
Dmitrii Gridin
2023-12-05 14:53:21 +01:00
committed by Space Team
parent c59ea8bd2a
commit e0c931f69d
4 changed files with 31 additions and 15 deletions
@@ -292,15 +292,6 @@ private fun rebindReturnExpression(returnExpression: FirStatement, newTarget: Fi
withFirEntry("expression", returnExpression) withFirEntry("expression", returnExpression)
} }
val target = returnExpression.target
requireWithAttachment(target.labeledElement == oldTarget, { "Unexpected return target" }) {
withFirSymbolEntry("newTarget", newTarget.propertySymbol)
withFirSymbolEntry("oldTarget", oldTarget.propertySymbol)
withFirEntry("target", target.labeledElement)
}
target.bind(newTarget)
val functionCall = returnExpression.result val functionCall = returnExpression.result
rebindFunctionCall(functionCall, newTarget, oldTarget) rebindFunctionCall(functionCall, newTarget, oldTarget)
} }
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.codeFragment import org.jetbrains.kotlin.analysis.low.level.api.fir.util.codeFragment
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
@@ -32,6 +31,7 @@ import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.psi import org.jetbrains.kotlin.psi
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
internal class RawFirNonLocalDeclarationBuilder private constructor( internal class RawFirNonLocalDeclarationBuilder private constructor(
session: FirSession, session: FirSession,
@@ -103,8 +103,26 @@ internal class RawFirNonLocalDeclarationBuilder private constructor(
} }
override fun bindFunctionTarget(target: FirFunctionTarget, function: FirFunction) { override fun bindFunctionTarget(target: FirFunctionTarget, function: FirFunction) {
val rewrittenTarget = functionsToRebind?.firstOrNull { it.realPsi == function.realPsi } ?: function super.bindFunctionTarget(target, computeRebindTarget(function) ?: function)
super.bindFunctionTarget(target, rewrittenTarget) }
/**
* @return [FirFunction] if another function should be used instead of [function] for [FirFunctionTarget]
*
* @see bindFunctionTarget
* @see functionsToRebind
*/
private fun computeRebindTarget(function: FirFunction): FirFunction? {
if (functionsToRebind.isNullOrEmpty()) return null
val realPsi = function.realPsi
if (realPsi != null) {
return functionsToRebind.firstOrNull { it.realPsi == realPsi }
}
val accessor = function as? FirPropertyAccessor ?: return null
val accessorPsi = accessor.psi ?: return null
return functionsToRebind.firstOrNull { it is FirPropertyAccessor && it.isGetter == accessor.isGetter && it.psi == accessorPsi }
} }
override fun addCapturedTypeParameters( override fun addCapturedTypeParameters(
@@ -59,7 +59,10 @@ open class PsiRawFirBuilder(
val baseScopeProvider: FirScopeProvider, val baseScopeProvider: FirScopeProvider,
bodyBuildingMode: BodyBuildingMode = BodyBuildingMode.NORMAL, bodyBuildingMode: BodyBuildingMode = BodyBuildingMode.NORMAL,
) : AbstractRawFirBuilder<PsiElement>(session) { ) : AbstractRawFirBuilder<PsiElement>(session) {
protected open fun bindFunctionTarget(target: FirFunctionTarget, function: FirFunction) = target.bind(function) protected open fun bindFunctionTarget(target: FirFunctionTarget, function: FirFunction) {
target.bind(function)
}
protected open fun FirFunctionBuilder.additionalFunctionInit() {} protected open fun FirFunctionBuilder.additionalFunctionInit() {}
protected open fun FirPropertyBuilder.additionalPropertyInit() {} protected open fun FirPropertyBuilder.additionalPropertyInit() {}
protected open fun FirPropertyAccessorBuilder.additionalPropertyAccessorInit() {} protected open fun FirPropertyAccessorBuilder.additionalPropertyAccessorInit() {}
@@ -2080,6 +2083,7 @@ open class PsiRawFirBuilder(
isExtension = receiverTypeReference != null, isExtension = receiverTypeReference != null,
lazyDelegateExpression = lazyDelegateExpression, lazyDelegateExpression = lazyDelegateExpression,
lazyBodyForGeneratedAccessors = lazyBody, lazyBodyForGeneratedAccessors = lazyBody,
::bindFunctionTarget,
) )
} }
} }
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.contracts.FirLegacyRawContractDescription
import org.jetbrains.kotlin.fir.contracts.builder.buildLegacyRawContractDescription import org.jetbrains.kotlin.fir.contracts.builder.buildLegacyRawContractDescription
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirReceiverParameter import org.jetbrains.kotlin.fir.declarations.FirReceiverParameter
import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.builder.*
@@ -334,6 +335,7 @@ fun <T> FirPropertyBuilder.generateAccessorsByDelegate(
isExtension: Boolean, isExtension: Boolean,
lazyDelegateExpression: FirLazyExpression? = null, lazyDelegateExpression: FirLazyExpression? = null,
lazyBodyForGeneratedAccessors: FirLazyBlock? = null, lazyBodyForGeneratedAccessors: FirLazyBlock? = null,
bindFunction: (target: FirFunctionTarget, function: FirFunction) -> Unit = FirFunctionTarget::bind,
) { ) {
if (delegateBuilder == null) return if (delegateBuilder == null) return
val delegateFieldSymbol = FirDelegateFieldSymbol(symbol.callableId).also { val delegateFieldSymbol = FirDelegateFieldSymbol(symbol.callableId).also {
@@ -481,10 +483,11 @@ fun <T> FirPropertyBuilder.generateAccessorsByDelegate(
} }
propertySymbol = this@generateAccessorsByDelegate.symbol propertySymbol = this@generateAccessorsByDelegate.symbol
}.also { }.also {
returnTarget.bind(it) bindFunction(returnTarget, it)
it.initContainingClassAttr(context) it.initContainingClassAttr(context)
} }
} }
if (isVar && (setter == null || setter is FirDefaultPropertyAccessor)) { if (isVar && (setter == null || setter is FirDefaultPropertyAccessor)) {
val annotations = setter?.annotations val annotations = setter?.annotations
val returnTarget = FirFunctionTarget(null, isLambda = false) val returnTarget = FirFunctionTarget(null, isLambda = false)
@@ -549,7 +552,7 @@ fun <T> FirPropertyBuilder.generateAccessorsByDelegate(
} }
propertySymbol = this@generateAccessorsByDelegate.symbol propertySymbol = this@generateAccessorsByDelegate.symbol
}.also { }.also {
returnTarget.bind(it) bindFunction(returnTarget, it)
it.initContainingClassAttr(context) it.initContainingClassAttr(context)
} }
} }