JVM_IR: box inline class values returned by suspend inline lambdas

The call site inside the inline function expects them to return a boxed
value, like FunctionN.invoke would.

 #KT-46915 Fixed
This commit is contained in:
pyos
2021-05-25 12:51:51 +02:00
committed by Ilmir Usmanov
parent 117fad2018
commit 33ddeffcfd
13 changed files with 164 additions and 2 deletions
@@ -4981,12 +4981,24 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@Test
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
import org.jetbrains.kotlin.codegen.IrExpressionLambda
import org.jetbrains.kotlin.codegen.JvmKotlinType
import org.jetbrains.kotlin.codegen.StackValue
@@ -215,11 +216,18 @@ class IrExpressionLambdaImpl(
val isSuspend = parameter.isInlineParameter() && parameter.type.isSuspendFunctionTypeOrSubtype()
capturedParamDesc(parameter.name.asString(), asmMethod.argumentTypes[startCapture + index], isSuspend)
}
// The parameter list should include the continuation if this is a suspend lambda. In the IR backend,
// the lambda is suspend iff the inline function's parameter is marked suspend, so FunctionN.invoke call
// inside the inline function already has a (real) continuation value as the last argument.
val freeParameters = function.explicitParameters.let { it.take(startCapture) + it.drop(endCapture) }
val freeAsmParameters = asmMethod.argumentTypes.let { it.take(startCapture) + it.drop(endCapture) }
invokeMethod = Method(asmMethod.name, asmMethod.returnType, freeAsmParameters.toTypedArray())
// The return type, on the other hand, should be the original type if this is a suspend lambda that returns
// an unboxed inline class value so that the inliner will box it (FunctionN.invoke should return a boxed value).
val unboxedReturnType = function.suspendFunctionOriginal().originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass()
val unboxedAsmReturnType = unboxedReturnType?.let(codegen.typeMapper::mapType)
invokeMethod = Method(asmMethod.name, unboxedAsmReturnType ?: asmMethod.returnType, freeAsmParameters.toTypedArray())
invokeMethodParameters = freeParameters.map { it.type.toIrBasedKotlinType() }
invokeMethodReturnType = function.returnType.toIrBasedKotlinType()
invokeMethodReturnType = (unboxedReturnType ?: function.returnType).toIrBasedKotlinType()
}
}
@@ -0,0 +1,20 @@
// WITH_RUNTIME
// WITH_COROUTINES
// IGNORE_BACKEND: JS_IR
// FILE: 1.kt
inline fun <T, R> (suspend () -> T).map(crossinline transform: suspend (T) -> R): suspend () -> R =
{ transform(this()) }
// FILE: 2.kt
import helpers.*
import kotlin.coroutines.*
inline class C(val value: Int)
fun box(): String {
var result = 0
suspend {
result = suspend { C(1) as C? }.map { it }()?.value ?: 2
}.startCoroutine(EmptyContinuation)
return if (result == 1) "OK" else "fail: $result"
}
@@ -0,0 +1,20 @@
// WITH_RUNTIME
// WITH_COROUTINES
// IGNORE_BACKEND: JS_IR
// FILE: 1.kt
inline fun <T, R> (suspend () -> T).map(crossinline transform: suspend (T) -> R): suspend () -> R =
{ transform(this()) }
// FILE: 2.kt
import helpers.*
import kotlin.coroutines.*
inline class C(val value: String)
fun box(): String {
var result = "fail"
suspend {
result = suspend { C("OK") }.map { it }().value
}.startCoroutine(EmptyContinuation)
return result
}
@@ -4981,12 +4981,24 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@Test
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@Test
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
@@ -4981,12 +4981,24 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@Test
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@Test
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
@@ -4981,12 +4981,24 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@Test
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
@@ -4981,12 +4981,24 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@Test
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
@@ -4981,12 +4981,24 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_IR_AGAINST_OLD, true);
}
@Test
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@Test
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
@@ -4981,12 +4981,24 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_MULTI_MODULE_OLD_AGAINST_IR, true);
}
@Test
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@Test
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@Test
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
@@ -3990,11 +3990,21 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt");
@@ -3990,11 +3990,21 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt");
@@ -3990,11 +3990,21 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineClass"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@TestMetadata("returnBoxedFromLambda.kt")
public void testReturnBoxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnBoxedFromLambda.kt");
}
@TestMetadata("returnUnboxedDirect.kt")
public void testReturnUnboxedDirect() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedDirect.kt");
}
@TestMetadata("returnUnboxedFromLambda.kt")
public void testReturnUnboxedFromLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedFromLambda.kt");
}
@TestMetadata("returnUnboxedResume.kt")
public void testReturnUnboxedResume() throws Exception {
runTest("compiler/testData/codegen/boxInline/suspend/inlineClass/returnUnboxedResume.kt");