Flatten if chains also in LT FIR
This commit is contained in:
committed by
teamcity
parent
bb766a5235
commit
2ac2fa5353
+6
@@ -331,6 +331,12 @@ public class FirLazyBodiesCalculatorTestGenerated extends AbstractFirLazyBodiesC
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/calls.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cascadeIf.kt")
|
||||
public void testCascadeIf() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/cascadeIf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classReference.kt")
|
||||
public void testClassReference() throws Exception {
|
||||
|
||||
+51
-28
@@ -47,7 +47,6 @@ import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtNameReferenceExpressionElementType
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
@@ -1136,6 +1135,10 @@ class ExpressionsConverter(
|
||||
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.toFirBlock
|
||||
*/
|
||||
private fun convertLoopBody(body: LighterASTNode?): FirBlock {
|
||||
return convertLoopOrIfBody(body) ?: buildEmptyExpressionBlock()
|
||||
}
|
||||
|
||||
private fun convertLoopOrIfBody(body: LighterASTNode?): FirBlock? {
|
||||
var firBlock: FirBlock? = null
|
||||
var firStatement: FirStatement? = null
|
||||
body?.forEachChildren {
|
||||
@@ -1145,11 +1148,7 @@ class ExpressionsConverter(
|
||||
}
|
||||
}
|
||||
|
||||
return when {
|
||||
firStatement != null -> FirSingleExpressionBlock(firStatement!!)
|
||||
firBlock == null -> buildEmptyExpressionBlock()
|
||||
else -> firBlock!!
|
||||
}
|
||||
return firStatement?.let { FirSingleExpressionBlock(it) } ?: firBlock
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1217,6 +1216,51 @@ class ExpressionsConverter(
|
||||
* @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 = thenBlock?.toFirSourceElement()
|
||||
condition = firCondition ?: buildErrorExpression(
|
||||
null,
|
||||
ConeSimpleDiagnostic("If statement should have condition", DiagnosticKind.Syntax)
|
||||
)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
break@whenBranches
|
||||
}
|
||||
}
|
||||
usedAsExpression = ifExpression.usedAsExpression
|
||||
}
|
||||
}
|
||||
|
||||
private class IfNodeComponents(val firCondition: FirExpression?, val thenBlock: LighterASTNode?, val elseBlock: LighterASTNode?)
|
||||
|
||||
private fun parseIfExpression(ifExpression: LighterASTNode): IfNodeComponents {
|
||||
var firCondition: FirExpression? = null
|
||||
var thenBlock: LighterASTNode? = null
|
||||
var elseBlock: LighterASTNode? = null
|
||||
@@ -1227,28 +1271,7 @@ class ExpressionsConverter(
|
||||
ELSE -> elseBlock = it
|
||||
}
|
||||
}
|
||||
|
||||
return buildWhenExpression {
|
||||
source = ifExpression.toFirSourceElement()
|
||||
val trueBranch = convertLoopBody(thenBlock)
|
||||
branches += buildWhenBranch {
|
||||
source = thenBlock?.toFirSourceElement()
|
||||
condition = firCondition ?: buildErrorExpression(
|
||||
null,
|
||||
ConeSimpleDiagnostic("If statement should have condition", DiagnosticKind.Syntax)
|
||||
)
|
||||
result = trueBranch
|
||||
}
|
||||
if (elseBlock != null) {
|
||||
val elseBranch = convertLoopBody(elseBlock)
|
||||
branches += buildWhenBranch {
|
||||
source = elseBlock?.toFirSourceElement()
|
||||
condition = buildElseIfTrueCondition()
|
||||
result = elseBranch
|
||||
}
|
||||
}
|
||||
usedAsExpression = ifExpression.usedAsExpression
|
||||
}
|
||||
return IfNodeComponents(firCondition, thenBlock, elseBlock)
|
||||
}
|
||||
|
||||
private val LighterASTNode.usedAsExpression: Boolean
|
||||
|
||||
+5
@@ -308,6 +308,11 @@ public class LightTree2FirConverterTestCaseGenerated extends AbstractLightTree2F
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/calls.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("cascadeIf.kt")
|
||||
public void testCascadeIf() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/cascadeIf.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classReference.kt")
|
||||
public void testClassReference() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/classReference.kt");
|
||||
|
||||
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
@@ -1922,7 +1921,7 @@ open class RawFirBuilder(
|
||||
when (val ktElse = ktLastIf.`else`) {
|
||||
null -> break@whenBranches
|
||||
is KtIfExpression -> ktLastIf = ktElse
|
||||
else -> {
|
||||
else -> {
|
||||
branches += buildWhenBranch {
|
||||
source = ktLastIf.elseKeyword?.toKtPsiSourceElement()
|
||||
condition = buildElseIfTrueCondition()
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
fun foo(first: Boolean, second: Boolean, third: Boolean): Int {
|
||||
if (first) {
|
||||
return 4
|
||||
} else if (second) {
|
||||
val x = 3
|
||||
return x + 2
|
||||
} else {
|
||||
// Yet we don't flatten this 'if', it matches the current PSI2IR behavior
|
||||
if (third) {
|
||||
return 0
|
||||
} else return -1
|
||||
}
|
||||
}
|
||||
|
||||
fun example() {
|
||||
val a = if (true) true else false
|
||||
val b = if (true) else false
|
||||
val c = if (true) true
|
||||
val d = if (true) true else;
|
||||
val e = if (true) {} else false
|
||||
val f = if (true) true else {}
|
||||
|
||||
{
|
||||
if (true) true
|
||||
}();
|
||||
|
||||
{
|
||||
if (true) true else false
|
||||
}();
|
||||
|
||||
{
|
||||
if (true) {} else false
|
||||
}();
|
||||
|
||||
|
||||
{
|
||||
if (true) true else {}
|
||||
}()
|
||||
|
||||
fun t(): Boolean {
|
||||
return if (true) true
|
||||
}
|
||||
|
||||
return if (true) true else {}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
FILE: cascadeIf.kt
|
||||
public? final? fun foo(first: Boolean, second: Boolean, third: Boolean): Int { LAZY_BLOCK }
|
||||
public? final? fun example(): R|kotlin/Unit| { LAZY_BLOCK }
|
||||
@@ -0,0 +1,131 @@
|
||||
FILE: cascadeIf.kt
|
||||
public? final? fun foo(first: Boolean, second: Boolean, third: Boolean): Int {
|
||||
when () {
|
||||
first# -> {
|
||||
^foo IntegerLiteral(4)
|
||||
}
|
||||
second# -> {
|
||||
lval x: <implicit> = IntegerLiteral(3)
|
||||
^foo x#.plus#(IntegerLiteral(2))
|
||||
}
|
||||
else -> {
|
||||
when () {
|
||||
third# -> {
|
||||
^foo IntegerLiteral(0)
|
||||
}
|
||||
else -> {
|
||||
^foo IntegerLiteral(-1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public? final? fun example(): R|kotlin/Unit| {
|
||||
lval a: <implicit> = when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
else -> {
|
||||
Boolean(false)
|
||||
}
|
||||
}
|
||||
|
||||
lval b: <implicit> = when () {
|
||||
Boolean(true) -> {
|
||||
}
|
||||
else -> {
|
||||
Boolean(false)
|
||||
}
|
||||
}
|
||||
|
||||
lval c: <implicit> = when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
}
|
||||
|
||||
lval d: <implicit> = when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
}
|
||||
|
||||
lval e: <implicit> = when () {
|
||||
Boolean(true) -> {
|
||||
}
|
||||
else -> {
|
||||
Boolean(false)
|
||||
}
|
||||
}
|
||||
|
||||
lval f: <implicit> = when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
fun <implicit>.<anonymous>(): <implicit> <inline=Unknown> {
|
||||
when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.invoke#()
|
||||
fun <implicit>.<anonymous>(): <implicit> <inline=Unknown> {
|
||||
when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
else -> {
|
||||
Boolean(false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.invoke#()
|
||||
fun <implicit>.<anonymous>(): <implicit> <inline=Unknown> {
|
||||
when () {
|
||||
Boolean(true) -> {
|
||||
}
|
||||
else -> {
|
||||
Boolean(false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.invoke#()
|
||||
fun <implicit>.<anonymous>(): <implicit> <inline=Unknown> {
|
||||
when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.invoke#()
|
||||
local final? fun t(): Boolean {
|
||||
^t when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
^example when () {
|
||||
Boolean(true) -> {
|
||||
Boolean(true)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+5
@@ -308,6 +308,11 @@ public class RawFirBuilderLazyBodiesTestCaseGenerated extends AbstractRawFirBuil
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/calls.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("cascadeIf.kt")
|
||||
public void testCascadeIf() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/cascadeIf.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classReference.kt")
|
||||
public void testClassReference() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/classReference.kt");
|
||||
|
||||
+5
@@ -308,6 +308,11 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/calls.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("cascadeIf.kt")
|
||||
public void testCascadeIf() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/cascadeIf.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("classReference.kt")
|
||||
public void testClassReference() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/classReference.kt");
|
||||
|
||||
+3
-3
@@ -16,9 +16,9 @@
|
||||
fun case1() {
|
||||
val b = true
|
||||
val c = true
|
||||
val a = if (b) {
|
||||
val a = <!INVALID_IF_AS_EXPRESSION!>if<!> (b) {
|
||||
"first true"
|
||||
} else <!INVALID_IF_AS_EXPRESSION!>if<!> (c) {
|
||||
} else if (c) {
|
||||
"else if true"
|
||||
}
|
||||
}
|
||||
@@ -28,5 +28,5 @@ fun case1() {
|
||||
fun case2() {
|
||||
var b = true
|
||||
val c = true
|
||||
val a = if (b) 1 else if (c) 2 else ;
|
||||
val a = <!INVALID_IF_AS_EXPRESSION!>if<!> (b) 1 else if (c) 2 else ;
|
||||
}
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ fun case4() {
|
||||
|
||||
val x2 = <!INVALID_IF_AS_EXPRESSION!>if<!> (TODO()) true
|
||||
|
||||
val x0 = if (false) true else <!INVALID_IF_AS_EXPRESSION!>if<!> (throw Exception()) ;
|
||||
val x0 = <!INVALID_IF_AS_EXPRESSION!>if<!> (false) true else if (throw Exception()) ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@
|
||||
// TESTCASE NUMBER: 1
|
||||
|
||||
fun case1() {
|
||||
val y0else = if (false) true else ;
|
||||
val y0else = <!INVALID_IF_AS_EXPRESSION!>if<!> (false) true else ;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -14,7 +14,7 @@ fun case1() {
|
||||
* ISSUES: KT-35510
|
||||
*/
|
||||
fun case2(nothing: Nothing) {
|
||||
val n1else = if (nothing) true else;
|
||||
val n1else = <!INVALID_IF_AS_EXPRESSION!>if<!> (nothing) true else;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -35,5 +35,5 @@ fun case4(nothing: Nothing) {
|
||||
// TESTCASE NUMBER: 5
|
||||
|
||||
fun case5(nothing: Nothing) {
|
||||
val x = if (false) else if (nothing) { "foo"} else ;
|
||||
val x = <!INVALID_IF_AS_EXPRESSION!>if<!> (false) else if (nothing) { "foo"} else ;
|
||||
}
|
||||
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -UNUSED_PARAMETER -UNUSED_EXPRESSION
|
||||
// SKIP_TXT
|
||||
|
||||
/*
|
||||
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
|
||||
*
|
||||
* SPEC VERSION: 0.1-296
|
||||
* MAIN LINK: control--and-data-flow-analysis, control-flow-graph, expressions-1, conditional-expressions -> paragraph 1 -> sentence 2
|
||||
* NUMBER: 1
|
||||
* DESCRIPTION: check any if-statement in kotlin may be trivially turned into such an expression by replacing the missing branch with a kotlin.Unit object expression.
|
||||
* HELPERS: checkType
|
||||
*/
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
|
||||
fun case1() {
|
||||
val b = true
|
||||
if (!b) {
|
||||
println("this is statement")
|
||||
}
|
||||
val statement = <!INVALID_IF_AS_EXPRESSION!>if<!> (!b) { println("statement could not be assigned") }
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 2
|
||||
|
||||
fun case2() {
|
||||
val a = 1
|
||||
val b = 2
|
||||
if (a > b) a else ; //statement
|
||||
val expression: Any = if (a > b) a else ;
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -UNUSED_PARAMETER -UNUSED_EXPRESSION
|
||||
// SKIP_TXT
|
||||
|
||||
+6
@@ -331,6 +331,12 @@ public class FirVisualizerForRawFirDataGenerated extends AbstractFirVisualizerTe
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/calls.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cascadeIf.kt")
|
||||
public void testCascadeIf() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/cascadeIf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classReference.kt")
|
||||
public void testClassReference() throws Exception {
|
||||
|
||||
+6
@@ -331,6 +331,12 @@ public class PsiVisualizerForRawFirDataGenerated extends AbstractPsiVisualizerTe
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/calls.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cascadeIf.kt")
|
||||
public void testCascadeIf() throws Exception {
|
||||
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/expressions/cascadeIf.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classReference.kt")
|
||||
public void testClassReference() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user