Fir2Ir: generate 'finally' block always with Unit type

This is important for IR lowerings like PolymorphicSignatureLowering
which are very sensitive about the correct types of expressions and
placement of coercions to Unit (KT-59218).

A boolean parameter to `insertImplicitCasts` is not the best solution to
ensure that coercion to Unit is added. The best solution would be to fix
the TODO and generate coercion to the block's type for the last
statement. But that will affect many other places and will need to be
done separately => KT-59781.

Code in IrInterpreter is uncommented to fix the FIR test
`compiler/testData/ir/interpreter/exceptions/tryFinally.kt`; otherwise
evaluation of the function `returnTryFinally` there crashes with
"NoSuchElementException: ArrayDeque is empty". No idea why this test
didn't fail for K1 though, since the created IR is exactly the same.

For some unknown reason this breaks WASM backend with K2, but not with
K1 => KT-59800.
This commit is contained in:
Alexander Udalov
2023-06-29 17:59:50 +02:00
committed by Space Team
parent 79fa2b6db0
commit 69059362b8
23 changed files with 119 additions and 69 deletions
@@ -173,7 +173,7 @@ class Fir2IrImplicitCastInserter(
override fun visitTryExpression(tryExpression: FirTryExpression, data: IrElement): IrElement {
val irTry = data as IrTry
(irTry.finallyExpression as? IrContainerExpression)?.let {
irTry.finallyExpression = it.insertImplicitCasts()
irTry.finallyExpression = it.insertImplicitCasts(coerceLastExpressionToUnit = true)
}
return data
}
@@ -237,13 +237,13 @@ class Fir2IrImplicitCastInserter(
return implicitNotNullCast(this)
}
private fun IrContainerExpression.insertImplicitCasts(): IrContainerExpression {
private fun IrContainerExpression.insertImplicitCasts(coerceLastExpressionToUnit: Boolean = false): IrContainerExpression {
if (statements.isEmpty()) return this
val lastIndex = statements.lastIndex
statements.forEachIndexed { i, irStatement ->
if (irStatement !is IrErrorCallExpression && irStatement is IrExpression) {
if (i != lastIndex) {
if (i != lastIndex || coerceLastExpressionToUnit) {
statements[i] = coerceToUnitIfNeeded(irStatement, irBuiltIns)
}
// TODO: for the last statement, need to cast to the return type if mismatched
@@ -957,13 +957,13 @@ class Fir2IrVisitor(
return statements.convertToIrExpressionOrBlock(source, origin)
}
private fun FirBlock.convertToIrBlock(origin: IrStatementOrigin? = null): IrExpression {
return statements.convertToIrBlock(source, origin)
private fun FirBlock.convertToIrBlock(forceUnitType: Boolean): IrExpression {
return statements.convertToIrBlock(source, null, forceUnitType)
}
private fun List<FirStatement>.convertToIrExpressionOrBlock(
source: KtSourceElement?,
origin: IrStatementOrigin? = null
origin: IrStatementOrigin?
): IrExpression {
if (size == 1) {
val firStatement = single()
@@ -973,14 +973,15 @@ class Fir2IrVisitor(
return convertToIrExpression(firStatement)
}
}
return convertToIrBlock(source, origin)
return convertToIrBlock(source, origin, forceUnitType = origin?.isLoop == true)
}
private fun List<FirStatement>.convertToIrBlock(
source: KtSourceElement?,
origin: IrStatementOrigin? = null
origin: IrStatementOrigin?,
forceUnitType: Boolean,
): IrExpression {
val type = if (origin?.isLoop == true)
val type = if (forceUnitType)
irBuiltIns.unitType
else
(lastOrNull() as? FirExpression)?.typeRef?.toIrType() ?: irBuiltIns.unitType
@@ -1230,7 +1231,8 @@ class Fir2IrVisitor(
innerEndOffset,
irBuiltIns.unitType,
origin,
loopVariables + loopBodyStatements.drop(loopVariableIndex).convertToIrExpressionOrBlock(firLoopBody.source)
loopVariables +
loopBodyStatements.drop(loopVariableIndex).convertToIrExpressionOrBlock(firLoopBody.source, null)
)
}
} else {
@@ -1286,10 +1288,12 @@ class Fir2IrVisitor(
return tryExpression.convertWithOffsets { startOffset, endOffset ->
IrTryImpl(
startOffset, endOffset, tryExpression.typeRef.toIrType(),
tryExpression.tryBlock.convertToIrBlock(),
tryExpression.tryBlock.convertToIrBlock(forceUnitType = false),
tryExpression.catches.map { it.accept(this, data) as IrCatch },
tryExpression.finallyBlock?.convertToIrBlock()
tryExpression.finallyBlock?.convertToIrBlock(forceUnitType = true)
)
}.also {
tryExpression.accept(implicitCastInserter, it)
}
}
@@ -1298,7 +1302,7 @@ class Fir2IrVisitor(
val catchParameter = declarationStorage.createIrVariable(
catch.parameter, conversionScope.parentFromStack(), IrDeclarationOrigin.CATCH_PARAMETER
)
IrCatchImpl(startOffset, endOffset, catchParameter, catch.block.convertToIrBlock())
IrCatchImpl(startOffset, endOffset, catchParameter, catch.block.convertToIrBlock(forceUnitType = false))
}
}
@@ -10090,6 +10090,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -10090,6 +10090,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -414,8 +414,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val state = callStack.popState()
when (expression.operator) {
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
// do nothing
// callStack.pushState(getUnitState()) TODO find real use cases for this
callStack.pushState(getUnitState())
}
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
when {
+2
View File
@@ -1,3 +1,5 @@
// IGNORE_BACKEND_K2: WASM
// ^ KT-59800 K2 + Wasm: test failure after changing `finally` block generation
fun test1() : Boolean {
try {
@@ -0,0 +1,9 @@
fun check(value: Any?) {
if (value != Unit) throw AssertionError("Fail: $value")
}
fun box(): String {
val x = 10
check(try { } catch (e: Exception) { } finally { x })
return "OK"
}
@@ -1,27 +0,0 @@
FILE fqName:<root> fileName:/tryCatch.kt
FUN name:test1 visibility:public modality:FINAL <> () returnType:kotlin.Unit
BLOCK_BODY
TRY type=kotlin.Unit
try: BLOCK type=kotlin.Unit origin=null
CALL 'public final fun println (): kotlin.Unit declared in kotlin.io' type=kotlin.Unit origin=null
CATCH parameter=val e: kotlin.Throwable declared in <root>.test1
VAR CATCH_PARAMETER name:e type:kotlin.Throwable [val]
BLOCK type=kotlin.Unit origin=null
CALL 'public final fun println (): kotlin.Unit declared in kotlin.io' type=kotlin.Unit origin=null
finally: BLOCK type=kotlin.Unit origin=null
CALL 'public final fun println (): kotlin.Unit declared in kotlin.io' type=kotlin.Unit origin=null
FUN name:test2 visibility:public modality:FINAL <> () returnType:kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun test2 (): kotlin.Int declared in <root>'
TRY type=kotlin.Int
try: BLOCK type=kotlin.Int origin=null
CALL 'public final fun println (): kotlin.Unit declared in kotlin.io' type=kotlin.Unit origin=null
CONST Int type=kotlin.Int value=42
CATCH parameter=val e: kotlin.Throwable declared in <root>.test2
VAR CATCH_PARAMETER name:e type:kotlin.Throwable [val]
BLOCK type=kotlin.Int origin=null
CALL 'public final fun println (): kotlin.Unit declared in kotlin.io' type=kotlin.Unit origin=null
CONST Int type=kotlin.Int value=24
finally: BLOCK type=kotlin.Int origin=null
CALL 'public final fun println (): kotlin.Unit declared in kotlin.io' type=kotlin.Unit origin=null
CONST Int type=kotlin.Int value=555
@@ -1,27 +0,0 @@
fun test1() {
try { // BLOCK
println()
}
catch (e: Throwable){ // BLOCK
println()
}
finally { // BLOCK
println()
}
}
fun test2(): Int {
return try { // BLOCK
println()
42
}
catch (e: Throwable){ // BLOCK
println()
24
}
finally { // BLOCK
println()
555
}
}
+1
View File
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// WITH_STDLIB
fun test1() {
@@ -9832,6 +9832,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -10090,6 +10090,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -10090,6 +10090,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -7938,6 +7938,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryInsideCatch.kt");
@@ -6910,6 +6910,12 @@ public class FirJsCodegenBoxTestGenerated extends AbstractFirJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -6910,6 +6910,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -6910,6 +6910,12 @@ public class IrJsES6CodegenBoxTestGenerated extends AbstractIrJsES6CodegenBoxTes
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -7755,6 +7755,12 @@ public class FirNativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTe
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -7929,6 +7929,12 @@ public class FirNativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenB
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -7669,6 +7669,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -7756,6 +7756,12 @@ public class NativeCodegenBoxTestNoPLGenerated extends AbstractNativeCodegenBoxT
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -6886,6 +6886,12 @@ public class FirWasmCodegenBoxTestGenerated extends AbstractFirWasmCodegenBoxTes
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {
@@ -6886,6 +6886,12 @@ public class K1WasmCodegenBoxTestGenerated extends AbstractK1WasmCodegenBoxTest
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryCatchAfterWhileTrue.kt");
}
@Test
@TestMetadata("tryFinallyOfTypeUnit.kt")
public void testTryFinallyOfTypeUnit() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions/tryFinallyOfTypeUnit.kt");
}
@Test
@TestMetadata("tryInsideCatch.kt")
public void testTryInsideCatch() throws Exception {