[FIR IDE] Use correct extension receiver FIR expression in completion
`getOrBuildFir` does not record `FirCheckedSafeCallSubject` expression, and it would be impossible to get them anyway since there are no PSI corresponding to "not null receiver" in expressions like `foo?.bar` - there is only `foo`, which is considered nullable by FIR `FirCheckedSafeCallSubject` wrapper has non-null type during resolve, and it becomes very important in `KtFirCompletionCandidateChecker`. If we loose the wrapper, then it would be impossible to call extensions on nullable types using `?.` syntax ^KTIJ-21021 Fixed
This commit is contained in:
+20
-1
@@ -24,13 +24,16 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.receiverType
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtSafeQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
|
||||
|
||||
internal class KtFirCompletionCandidateChecker(
|
||||
analysisSession: KtFirAnalysisSession,
|
||||
@@ -58,7 +61,7 @@ internal class KtFirCompletionCandidateChecker(
|
||||
possibleExplicitReceiver: KtExpression?,
|
||||
): KtExtensionApplicabilityResult {
|
||||
val file = originalFile.getOrBuildFirFile(firResolveState)
|
||||
val explicitReceiverExpression = possibleExplicitReceiver?.getOrBuildFirOfType<FirExpression>(firResolveState)
|
||||
val explicitReceiverExpression = possibleExplicitReceiver?.getMatchingFirExpressionForCallReceiver()
|
||||
val resolver = SingleCandidateResolver(firResolveState.rootModuleSession, file)
|
||||
val implicitReceivers = getImplicitReceivers(originalFile, nameExpression)
|
||||
for (implicitReceiverValue in implicitReceivers) {
|
||||
@@ -96,4 +99,20 @@ internal class KtFirCompletionCandidateChecker(
|
||||
yieldAll(towerDataContext.implicitReceiverStack)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It is not enough to just call the `getOrBuildFirOfType` on [this] receiver expression, because for calls
|
||||
* like `foo?.bar()` the receiver is additionally wrapped into `FirCheckedSafeCallSubject`, which is important
|
||||
* for type-checks during resolve.
|
||||
*
|
||||
* @receiver PSI receiver expression in some qualified expression (e.g. `foo` in `foo?.bar()`, `a` in `a.b`)
|
||||
* @return A FIR expression which most precisely represents the receiver for the corresponding FIR call.
|
||||
*/
|
||||
private fun KtExpression.getMatchingFirExpressionForCallReceiver(): FirExpression {
|
||||
val psiWholeCall = this.getQualifiedExpressionForReceiver()
|
||||
if (psiWholeCall !is KtSafeQualifiedExpression) return this.getOrBuildFirOfType<FirExpression>(firResolveState)
|
||||
|
||||
val firSafeCall = psiWholeCall.getOrBuildFirOfType<FirSafeCallExpression>(firResolveState)
|
||||
return firSafeCall.checkedSubjectRef.value
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user