[FIR2IR] Coerce last operator in a loop to Unit

One of many fixes for https://youtrack.jetbrains.com/issue/KT-59781/K2-investigate-implicit-cast-generation-in-fir2ir-vs-psi2ir

Merge-request: KT-MR-12629
Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
Vladimir Sukharev
2023-10-19 09:53:46 +00:00
committed by Space Team
parent 5df8ac4d1a
commit 9b9ddb760a
13 changed files with 102 additions and 86 deletions
@@ -157,7 +157,7 @@ class Fir2IrImplicitCastInserter(
override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: IrElement): IrElement { override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: IrElement): IrElement {
val loop = data as IrDoWhileLoop val loop = data as IrDoWhileLoop
(loop.body as? IrContainerExpression)?.let { (loop.body as? IrContainerExpression)?.let {
loop.body = it.insertImplicitCasts() loop.body = it.insertImplicitCasts(coerceLastExpressionToUnit = true)
} }
return data return data
} }
@@ -165,7 +165,7 @@ class Fir2IrImplicitCastInserter(
override fun visitWhileLoop(whileLoop: FirWhileLoop, data: IrElement): IrElement { override fun visitWhileLoop(whileLoop: FirWhileLoop, data: IrElement): IrElement {
val loop = data as IrWhileLoop val loop = data as IrWhileLoop
(loop.body as? IrContainerExpression)?.let { (loop.body as? IrContainerExpression)?.let {
loop.body = it.insertImplicitCasts() loop.body = it.insertImplicitCasts(coerceLastExpressionToUnit = true)
} }
return data return data
} }
@@ -339,7 +339,7 @@ class Fir2IrImplicitCastInserter(
) )
} }
private fun coerceToUnitIfNeeded(original: IrExpression, irBuiltIns: IrBuiltIns): IrExpression { internal fun coerceToUnitIfNeeded(original: IrExpression, irBuiltIns: IrBuiltIns): IrExpression {
val valueType = original.type val valueType = original.type
return if (valueType.isUnit() || valueType.isNothing()) return if (valueType.isUnit() || valueType.isNothing())
original original
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrErrorClassImpl import org.jetbrains.kotlin.ir.types.impl.IrErrorClassImpl
import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
import org.jetbrains.kotlin.ir.util.coerceToUnit
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultConstructor import org.jetbrains.kotlin.ir.util.defaultConstructor
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -1295,7 +1296,10 @@ class Fir2IrVisitor(
loopMap[doWhileLoop] = this loopMap[doWhileLoop] = this
label = doWhileLoop.label?.name label = doWhileLoop.label?.name
body = runUnless(doWhileLoop.block is FirEmptyExpressionBlock) { body = runUnless(doWhileLoop.block is FirEmptyExpressionBlock) {
doWhileLoop.block.convertToIrExpressionOrBlock(origin) Fir2IrImplicitCastInserter.coerceToUnitIfNeeded(
doWhileLoop.block.convertToIrExpressionOrBlock(origin),
irBuiltIns
)
} }
condition = convertToIrExpression(doWhileLoop.condition) condition = convertToIrExpression(doWhileLoop.condition)
loopMap.remove(doWhileLoop) loopMap.remove(doWhileLoop)
@@ -1360,7 +1364,10 @@ class Fir2IrVisitor(
) )
} }
} else { } else {
firLoopBody.convertToIrExpressionOrBlock(origin) Fir2IrImplicitCastInserter.coerceToUnitIfNeeded(
firLoopBody.convertToIrExpressionOrBlock(origin),
irBuiltIns
)
} }
} }
loopMap.remove(whileLoop) loopMap.remove(whileLoop)
@@ -84,6 +84,7 @@ FILE fqName:<root> fileName:/noSymbolForIntRangeIterator.kt
VAR FOR_LOOP_VARIABLE name:j type:kotlin.Int [val] VAR FOR_LOOP_VARIABLE name:j type:kotlin.Int [val]
CALL 'public final fun next (): kotlin.Int declared in kotlin.collections.IntIterator' type=kotlin.Int origin=FOR_LOOP_NEXT CALL 'public final fun next (): kotlin.Int declared in kotlin.collections.IntIterator' type=kotlin.Int origin=FOR_LOOP_NEXT
$this: GET_VAR 'val tmp_2: kotlin.collections.IntIterator declared in <root>.test.localFunc.<anonymous>' type=kotlin.collections.IntIterator origin=null $this: GET_VAR 'val tmp_2: kotlin.collections.IntIterator declared in <root>.test.localFunc.<anonymous>' type=kotlin.collections.IntIterator origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=java.lang.StringBuilder origin=null BLOCK type=java.lang.StringBuilder origin=null
CALL 'public final fun appendLine (value: kotlin.String?): java.lang.StringBuilder declared in kotlin.text' type=java.lang.StringBuilder origin=null CALL 'public final fun appendLine (value: kotlin.String?): java.lang.StringBuilder declared in kotlin.text' type=java.lang.StringBuilder origin=null
$receiver: GET_VAR '$this$buildString: java.lang.StringBuilder declared in <root>.test.localFunc.<anonymous>' type=java.lang.StringBuilder origin=null $receiver: GET_VAR '$this$buildString: java.lang.StringBuilder declared in <root>.test.localFunc.<anonymous>' type=java.lang.StringBuilder origin=null
@@ -111,6 +111,7 @@ FILE fqName:<root> fileName:/breakContinueInLoopHeader.kt
BLOCK type=kotlin.Unit origin=null BLOCK type=kotlin.Unit origin=null
DO_WHILE label=Inner origin=DO_WHILE_LOOP DO_WHILE label=Inner origin=DO_WHILE_LOOP
body: COMPOSITE type=kotlin.Unit origin=null body: COMPOSITE type=kotlin.Unit origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=kotlin.Int origin=null BLOCK type=kotlin.Int origin=null
SET_VAR 'var j: kotlin.Int declared in <root>.test5' type=kotlin.Unit origin=PREFIX_INCR SET_VAR 'var j: kotlin.Int declared in <root>.test5' type=kotlin.Unit origin=PREFIX_INCR
CALL 'public final fun inc (): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=null CALL 'public final fun inc (): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=null
@@ -69,7 +69,7 @@ fun test5() {
{ // BLOCK { // BLOCK
j = j.inc() j = j.inc()
j j
} } /*~> Unit */
// } while (when { // } while (when {
greaterOrEqual(arg0 = j, arg1 = 3) -> false greaterOrEqual(arg0 = j, arg1 = 3) -> false
else -> break@Inner else -> break@Inner
@@ -11,7 +11,8 @@ FILE fqName:<root> fileName:/whileDoWhile.kt
condition: CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT condition: CALL 'public final fun less (arg0: kotlin.Int, arg1: kotlin.Int): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=LT
arg0: GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null arg0: GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null
arg1: CONST Int type=kotlin.Int value=5 arg1: CONST Int type=kotlin.Int value=5
body: BLOCK type=kotlin.Int origin=POSTFIX_INCR body: TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=kotlin.Int origin=POSTFIX_INCR
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val] VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null
SET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Unit origin=POSTFIX_INCR SET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Unit origin=POSTFIX_INCR
@@ -23,6 +24,7 @@ FILE fqName:<root> fileName:/whileDoWhile.kt
arg0: GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null arg0: GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null
arg1: CONST Int type=kotlin.Int value=10 arg1: CONST Int type=kotlin.Int value=10
body: BLOCK type=kotlin.Unit origin=null body: BLOCK type=kotlin.Unit origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=kotlin.Int origin=POSTFIX_INCR BLOCK type=kotlin.Int origin=POSTFIX_INCR
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val] VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null
@@ -43,7 +45,8 @@ FILE fqName:<root> fileName:/whileDoWhile.kt
arg1: CONST Int type=kotlin.Int value=7 arg1: CONST Int type=kotlin.Int value=7
BLOCK type=kotlin.Unit origin=null BLOCK type=kotlin.Unit origin=null
DO_WHILE label=null origin=DO_WHILE_LOOP DO_WHILE label=null origin=DO_WHILE_LOOP
body: BLOCK type=kotlin.Int origin=POSTFIX_INCR body: TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=kotlin.Int origin=POSTFIX_INCR
VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Int [val] VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.Int [val]
GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null
SET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Unit origin=POSTFIX_INCR SET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Unit origin=POSTFIX_INCR
@@ -56,6 +59,7 @@ FILE fqName:<root> fileName:/whileDoWhile.kt
BLOCK type=kotlin.Unit origin=null BLOCK type=kotlin.Unit origin=null
DO_WHILE label=null origin=DO_WHILE_LOOP DO_WHILE label=null origin=DO_WHILE_LOOP
body: COMPOSITE type=kotlin.Unit origin=null body: COMPOSITE type=kotlin.Unit origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=kotlin.Int origin=POSTFIX_INCR BLOCK type=kotlin.Int origin=POSTFIX_INCR
VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Int [val] VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.Int [val]
GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null GET_VAR 'var x: kotlin.Int declared in <root>.test' type=kotlin.Int origin=null
@@ -5,13 +5,13 @@ fun test() {
val tmp_0: Int = x val tmp_0: Int = x
x = tmp_0.inc() x = tmp_0.inc()
tmp_0 tmp_0
} } /*~> Unit */
while (less(arg0 = x, arg1 = 10)) { // BLOCK while (less(arg0 = x, arg1 = 10)) { // BLOCK
{ // BLOCK { // BLOCK
val tmp_1: Int = x val tmp_1: Int = x
x = tmp_1.inc() x = tmp_1.inc()
tmp_1 tmp_1
} } /*~> Unit */
} }
{ // BLOCK { // BLOCK
do while (less(arg0 = x, arg1 = 0)) do while (less(arg0 = x, arg1 = 0))
@@ -25,7 +25,7 @@ fun test() {
val tmp_2: Int = x val tmp_2: Int = x
x = tmp_2.inc() x = tmp_2.inc()
tmp_2 tmp_2
} while (less(arg0 = x, arg1 = 15)) } /*~> Unit */ while (less(arg0 = x, arg1 = 15))
} }
{ // BLOCK { // BLOCK
do// COMPOSITE { do// COMPOSITE {
@@ -33,7 +33,7 @@ fun test() {
val tmp_3: Int = x val tmp_3: Int = x
x = tmp_3.inc() x = tmp_3.inc()
tmp_3 tmp_3
} } /*~> Unit */
// } while (less(arg0 = x, arg1 = 20)) // } while (less(arg0 = x, arg1 = 20))
} }
} }
@@ -545,6 +545,7 @@ FILE fqName:<root> fileName:/ArrayMap.kt
BLOCK type=kotlin.Unit origin=null BLOCK type=kotlin.Unit origin=null
DO_WHILE label=null origin=DO_WHILE_LOOP DO_WHILE label=null origin=DO_WHILE_LOOP
body: COMPOSITE type=kotlin.Unit origin=null body: COMPOSITE type=kotlin.Unit origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=kotlin.Int origin=POSTFIX_INCR BLOCK type=kotlin.Int origin=POSTFIX_INCR
VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val] VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.Int [val]
CALL 'private final fun <get-index> (): kotlin.Int declared in <root>.ArrayMapImpl.iterator.<no name provided>' type=kotlin.Int origin=GET_PROPERTY CALL 'private final fun <get-index> (): kotlin.Int declared in <root>.ArrayMapImpl.iterator.<no name provided>' type=kotlin.Int origin=GET_PROPERTY
@@ -235,7 +235,7 @@ internal class ArrayMapImpl<T : Any> : ArrayMap<T> {
val tmp_1: Int = <this>.<get-index>() val tmp_1: Int = <this>.<get-index>()
<this>.<set-index>(<set-?> = tmp_1.inc()) <this>.<set-index>(<set-?> = tmp_1.inc())
tmp_1 tmp_1
} } /*~> Unit */
// } while (when { // } while (when {
less(arg0 = <this>.<get-index>(), arg1 = <this>.<get-data>().<get-size>()) -> EQEQ(arg0 = <this>.<get-data>().get(index = <this>.<get-index>()), arg1 = null) less(arg0 = <this>.<get-index>(), arg1 = <this>.<get-data>().<get-size>()) -> EQEQ(arg0 = <this>.<get-data>().get(index = <this>.<get-index>()), arg1 = null)
else -> false else -> false
@@ -187,6 +187,7 @@ FILE fqName:<root> fileName:/DeepCopyIrTree.kt
VAR name:otherTypeParameter type:<root>.IrTypeParameter [val] VAR name:otherTypeParameter type:<root>.IrTypeParameter [val]
CALL 'public final fun component2 (): B of kotlin.Pair declared in kotlin.Pair' type=<root>.IrTypeParameter origin=COMPONENT_N(index=2) CALL 'public final fun component2 (): B of kotlin.Pair declared in kotlin.Pair' type=<root>.IrTypeParameter origin=COMPONENT_N(index=2)
$this: GET_VAR 'val tmp_1: kotlin.Pair<<root>.IrTypeParameter, <root>.IrTypeParameter> declared in <root>.DeepCopyIrTreeWithSymbols.copyTypeParametersFrom.<anonymous>' type=kotlin.Pair<<root>.IrTypeParameter, <root>.IrTypeParameter> origin=null $this: GET_VAR 'val tmp_1: kotlin.Pair<<root>.IrTypeParameter, <root>.IrTypeParameter> declared in <root>.DeepCopyIrTreeWithSymbols.copyTypeParametersFrom.<anonymous>' type=kotlin.Pair<<root>.IrTypeParameter, <root>.IrTypeParameter> origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=kotlin.collections.MutableList<<root>.IrType> origin=null BLOCK type=kotlin.collections.MutableList<<root>.IrType> origin=null
CALL 'public final fun mapTo <T, R, C> (destination: C of kotlin.collections.mapTo, transform: kotlin.Function1<T of kotlin.collections.mapTo, R of kotlin.collections.mapTo>): C of kotlin.collections.mapTo declared in kotlin.collections' type=kotlin.collections.MutableList<<root>.IrType> origin=null CALL 'public final fun mapTo <T, R, C> (destination: C of kotlin.collections.mapTo, transform: kotlin.Function1<T of kotlin.collections.mapTo, R of kotlin.collections.mapTo>): C of kotlin.collections.mapTo declared in kotlin.collections' type=kotlin.collections.MutableList<<root>.IrType> origin=null
<T>: <root>.IrType <T>: <root>.IrType
@@ -64,7 +64,7 @@ class DeepCopyIrTreeWithSymbols {
return <this>.<get-typeRemapper>().remapType(type = it) return <this>.<get-typeRemapper>().remapType(type = it)
} }
) )
} } /*~> Unit */
} }
} }
} }
@@ -26,6 +26,7 @@ FILE fqName:<root> fileName:/coercionInLoop.kt
STRING_CONCATENATION type=kotlin.String STRING_CONCATENATION type=kotlin.String
CONST String type=kotlin.String value="Fail " CONST String type=kotlin.String value="Fail "
GET_VAR 'var i: kotlin.Int declared in <root>.box' type=kotlin.Int origin=null GET_VAR 'var i: kotlin.Int declared in <root>.box' type=kotlin.Int origin=null
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
BLOCK type=kotlin.Int origin=POSTFIX_INCR BLOCK type=kotlin.Int origin=POSTFIX_INCR
VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val] VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val]
GET_VAR 'var i: kotlin.Int declared in <root>.box' type=kotlin.Int origin=null GET_VAR 'var i: kotlin.Int declared in <root>.box' type=kotlin.Int origin=null
@@ -10,7 +10,7 @@ fun box(): String {
val tmp_0: Int = i val tmp_0: Int = i
i = tmp_0.inc() i = tmp_0.inc()
tmp_0 tmp_0
} } /*~> Unit */
} }
return "OK" return "OK"
} }