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:
committed by
Space Team
parent
79fa2b6db0
commit
69059362b8
+3
-3
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// IGNORE_BACKEND_K2: WASM
|
||||
// ^ KT-59800 K2 + Wasm: test failure after changing `finally` block generation
|
||||
|
||||
fun test1() : Boolean {
|
||||
try {
|
||||
|
||||
Vendored
+9
@@ -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,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
|
||||
fun test1() {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
Generated
+6
@@ -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 {
|
||||
|
||||
Generated
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user