JVM_IR: expect unboxed return value from suspend default stubs

#KT-47206 Fixed
This commit is contained in:
pyos
2021-06-10 09:51:48 +02:00
committed by TeamCityServer
parent 578fcf2ebf
commit cf660cf24a
12 changed files with 133 additions and 30 deletions
@@ -10484,6 +10484,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/createOverride.kt");
}
@Test
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/defaultStub.kt");
}
@Test
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
@@ -10776,6 +10782,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/createOverride.kt");
}
@Test
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/defaultStub.kt");
}
@Test
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
@@ -191,17 +191,14 @@ internal fun createFakeContinuation(context: JvmBackendContext): IrExpression =
)
internal fun IrFunction.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(): IrType? {
if (!isSuspend) return null
// Check whether we in fact return inline class
val unboxedReturnType = InlineClassAbi.unboxType(returnType.makeNotNull()) ?: return null
// Force boxing for primitives. NOTE: this also forbids unboxing a nullable inline class into a nullable primitive.
if (unboxedReturnType.isPrimitiveType()) return null
// Force boxing for nullable inline class types with nullable underlying type
if (returnType.isNullable() && unboxedReturnType.isNullable()) return null
// Force boxing if the function overrides function with different type modulo nullability ignoring type parameters
if ((this as? IrSimpleFunction)?.overridesReturningDifferentType(returnType) != false) return null
// Don't box other inline classes
return returnType
if (this !is IrSimpleFunction || !isSuspend) return null
// Unlike `suspendFunctionOriginal()`, this also maps `$default` stubs to the original function.
val original = attributeOwnerId as IrSimpleFunction
val unboxedReturnType = InlineClassAbi.unboxType(original.returnType) ?: return null
// 1. Can't unbox into a primitive, since suspend functions have to return a reference type.
// 2. Force boxing if the function overrides function with different type modulo nullability ignoring type parameters
if (unboxedReturnType.isPrimitiveType() || original.overridesReturningDifferentType(original.returnType)) return null
return original.returnType
}
private fun IrSimpleFunction.overridesReturningDifferentType(returnType: IrType): Boolean {
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
import org.jetbrains.kotlin.backend.jvm.lower.isMultifileBridge
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.*
@@ -488,8 +487,7 @@ class ExpressionCodegen(
callGenerator.genCall(callable, this, expression, isInsideCondition)
val unboxedInlineClassIrType =
callee.suspendFunctionOriginal().originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass()
val unboxedInlineClassIrType = callee.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass()
if (isSuspensionPoint != SuspensionPointKind.NEVER) {
addSuspendMarker(mv, isStartNotEnd = false, isSuspensionPoint == SuspensionPointKind.NOT_INLINE)
@@ -519,21 +517,15 @@ class ExpressionCodegen(
wrapJavaClassesIntoKClasses(mv)
MaterialValue(this, AsmTypes.K_CLASS_ARRAY_TYPE, expression.type)
}
unboxedInlineClassIrType != null && !irFunction.isNonBoxingSuspendDelegation() -> {
if (!irFunction.shouldContainSuspendMarkers()) {
// Since the coroutine transformer won't run, we need to do this manually.
mv.generateCoroutineSuspendedCheck(state.languageVersionSettings)
unboxedInlineClassIrType != null && !irFunction.isNonBoxingSuspendDelegation() ->
MaterialValue(this, unboxedInlineClassIrType.asmType, unboxedInlineClassIrType).apply {
if (!irFunction.shouldContainSuspendMarkers()) {
// Since the coroutine transformer won't run, we need to do this manually.
mv.generateCoroutineSuspendedCheck(state.languageVersionSettings)
}
mv.checkcast(type)
}
mv.checkcast(unboxedInlineClassIrType.asmType)
if (irFunction.isInvokeSuspendOfContinuation()) {
// TODO: why is simply materializing the value with type `Object` not enough? This branch shouldn't be needed.
StackValue.boxInlineClass(unboxedInlineClassIrType, mv, typeMapper)
MaterialValue(this, callable.asmMethod.returnType, callable.returnType)
} else {
MaterialValue(this, unboxedInlineClassIrType.asmType, unboxedInlineClassIrType)
}
}
expression.symbol.owner.resultIsActuallyAny(null) == true ->
callee.resultIsActuallyAny(null) == true ->
MaterialValue(this, callable.asmMethod.returnType, context.irBuiltIns.anyNType)
else ->
MaterialValue(this, callable.asmMethod.returnType, callable.returnType)
@@ -907,7 +899,7 @@ class ExpressionCodegen(
}
private fun IrFunction.returnAsmAndIrTypes(): Pair<Type, IrType> {
val unboxedInlineClass = suspendFunctionOriginal().originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass()
val unboxedInlineClass = originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass()
// In case of non-boxing delegation, the return type of the tail call was considered to be `Object`,
// so that's also what we'll return here to avoid casts/unboxings/etc.
if (unboxedInlineClass != null && !isNonBoxingSuspendDelegation()) {
@@ -179,7 +179,7 @@ class IrExpressionLambdaImpl(
val freeAsmParameters = asmMethod.argumentTypes.let { it.take(startCapture) + it.drop(endCapture) }
// 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 unboxedReturnType = function.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass()
val unboxedAsmReturnType = unboxedReturnType?.let(codegen.typeMapper::mapType)
invokeMethod = Method(asmMethod.name, unboxedAsmReturnType ?: asmMethod.returnType, freeAsmParameters.toTypedArray())
invokeMethodParameters = freeParameters.map { it.type.toIrBasedKotlinType() }
@@ -0,0 +1,21 @@
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
import kotlin.coroutines.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
inline class IC(val s: String)
suspend fun foo(x: String = "OK") = IC(x)
fun box(): String {
var res = ""
builder {
res = foo().s
}
return res
}
@@ -0,0 +1,17 @@
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
inline class IC(val s: String)
suspend fun foo(x: String = "OK") = suspendCoroutineUninterceptedOrReturn<IC> {
it.resume(IC(x))
COROUTINE_SUSPENDED
}
fun box(): String {
var res = ""
suspend { res = foo().s }.startCoroutine(Continuation(EmptyCoroutineContext) { it.getOrThrow() })
return res
}
@@ -10484,6 +10484,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/createOverride.kt");
}
@Test
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/defaultStub.kt");
}
@Test
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
@@ -10776,6 +10782,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/createOverride.kt");
}
@Test
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/defaultStub.kt");
}
@Test
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
@@ -10484,6 +10484,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/createOverride.kt");
}
@Test
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/defaultStub.kt");
}
@Test
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
@@ -10776,6 +10782,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/createOverride.kt");
}
@Test
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/defaultStub.kt");
}
@Test
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
@@ -8296,6 +8296,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/createOverride.kt");
}
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/defaultStub.kt");
}
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/genericOverrideSuspendFun.kt");
@@ -8544,6 +8549,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/createOverride.kt");
}
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/defaultStub.kt");
}
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/genericOverrideSuspendFun.kt");
@@ -7395,6 +7395,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/createOverride.kt");
}
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/defaultStub.kt");
}
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/genericOverrideSuspendFun.kt");
@@ -7638,6 +7643,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/createOverride.kt");
}
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/defaultStub.kt");
}
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/genericOverrideSuspendFun.kt");
@@ -6801,6 +6801,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/createOverride.kt");
}
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/defaultStub.kt");
}
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/genericOverrideSuspendFun.kt");
@@ -7044,6 +7049,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/createOverride.kt");
}
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/defaultStub.kt");
}
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/genericOverrideSuspendFun.kt");
@@ -6801,6 +6801,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/createOverride.kt");
}
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/defaultStub.kt");
}
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/direct/genericOverrideSuspendFun.kt");
@@ -7044,6 +7049,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/createOverride.kt");
}
@TestMetadata("defaultStub.kt")
public void testDefaultStub() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/defaultStub.kt");
}
@TestMetadata("genericOverrideSuspendFun.kt")
public void testGenericOverrideSuspendFun() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/inlineClasses/resume/genericOverrideSuspendFun.kt");