[Raw FIR] Build if - else if - else as two nested whens

This is necessary for inference to work like in K1 because we only
add equality constraints from expected types on top-level `when`, not
on nested ones.

#KT-65882
This commit is contained in:
Kirill Rakhman
2024-02-29 14:56:10 +01:00
committed by Space Team
parent 888c1defa0
commit b4413776ab
12 changed files with 390 additions and 338 deletions
@@ -1335,42 +1335,28 @@ class LightTreeRawFirExpressionBuilder(
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitIfExpression
*/
private fun convertIfExpression(ifExpression: LighterASTNode): FirExpression {
var components = parseIfExpression(ifExpression)
return buildWhenExpression {
source = ifExpression.toFirSourceElement()
whenBranches@ while (true) {
with(components) {
val trueBranch = convertLoopBody(thenBlock)
branches += buildWhenBranch {
source = firCondition?.source
condition = firCondition ?: buildErrorExpression(
null,
ConeSyntaxDiagnostic("If statement should have condition")
)
result = trueBranch
}
with(parseIfExpression(ifExpression)) {
val trueBranch = convertLoopBody(thenBlock)
branches += buildWhenBranch {
source = firCondition?.source
condition = firCondition ?: buildErrorExpression(
null,
ConeSyntaxDiagnostic("If statement should have condition")
)
result = trueBranch
}
if (components.elseBlock == null) break@whenBranches
var cascadeIf = false
components.elseBlock?.forEachChildren {
if (it.tokenType == IF) {
cascadeIf = true
components = parseIfExpression(it)
}
}
if (!cascadeIf) {
with(components) {
val elseBranch = convertLoopOrIfBody(elseBlock)
if (elseBranch != null) {
branches += buildWhenBranch {
source = elseBlock?.toFirSourceElement()
condition = buildElseIfTrueCondition()
result = elseBranch
}
if (elseBlock != null) {
val elseBranch = convertLoopOrIfBody(elseBlock)
if (elseBranch != null) {
branches += buildWhenBranch {
source = elseBlock.toFirSourceElement()
condition = buildElseIfTrueCondition()
result = elseBranch
}
}
break@whenBranches
}
}
usedAsExpression = ifExpression.usedAsExpression
@@ -2555,26 +2555,18 @@ open class PsiRawFirBuilder(
return buildWhenExpression {
source = expression.toFirSourceElement()
var ktLastIf: KtIfExpression = expression
whenBranches@ while (true) {
val ktCondition = ktLastIf.condition
branches += buildWhenBranch {
source = ktCondition?.toFirSourceElement(KtFakeSourceElementKind.WhenCondition)
condition = ktCondition.toFirExpression("If statement should have condition")
result = ktLastIf.then.toFirBlock()
}
val ktCondition = expression.condition
branches += buildWhenBranch {
source = ktCondition?.toFirSourceElement(KtFakeSourceElementKind.WhenCondition)
condition = ktCondition.toFirExpression("If statement should have condition")
result = expression.then.toFirBlock()
}
when (val ktElse = ktLastIf.`else`) {
null -> break@whenBranches
is KtIfExpression -> ktLastIf = ktElse
else -> {
branches += buildWhenBranch {
source = ktLastIf.elseKeyword?.toKtPsiSourceElement()
condition = buildElseIfTrueCondition()
result = ktLastIf.`else`.toFirBlock()
}
break@whenBranches
}
if (expression.`else` != null) {
branches += buildWhenBranch {
source = expression.elseKeyword?.toKtPsiSourceElement()
condition = buildElseIfTrueCondition()
result = expression.`else`.toFirBlock()
}
}
@@ -4,17 +4,22 @@ FILE: cascadeIf.kt
first# -> {
^foo IntegerLiteral(4)
}
second# -> {
lval x: <implicit> = IntegerLiteral(3)
^foo x#.plus#(IntegerLiteral(2))
}
else -> {
when () {
third# -> {
^foo IntegerLiteral(0)
second# -> {
lval x: <implicit> = IntegerLiteral(3)
^foo x#.plus#(IntegerLiteral(2))
}
else -> {
^foo IntegerLiteral(-1)
when () {
third# -> {
^foo IntegerLiteral(0)
}
else -> {
^foo IntegerLiteral(-1)
}
}
}
}