diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 6c0698268fa..6798b1804e9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.config.ApiVersion; import org.jetbrains.kotlin.config.JVMAssertionsMode; import org.jetbrains.kotlin.config.LanguageFeature; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor; import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor; import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor; @@ -312,6 +313,8 @@ public class ExpressionCodegen extends KtVisitor impleme stackValue = suspendFunctionTypeWrapperIfNeeded(selector, stackValue); + stackValue = coerceAndBoxInlineClassIfNeeded(selector, stackValue); + RuntimeAssertionInfo runtimeAssertionInfo = null; if (selector instanceof KtExpression) { KtExpression expression = (KtExpression) selector; @@ -360,6 +363,53 @@ public class ExpressionCodegen extends KtVisitor impleme return stackValue; } + private StackValue coerceAndBoxInlineClassIfNeeded(KtElement selector, StackValue stackValue) { + ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(selector, bindingContext); + if (resolvedCall == null) return stackValue; + CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); + if (!(descriptor instanceof FunctionDescriptor)) return stackValue; + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + if (!functionDescriptor.isSuspend()) return stackValue; + + KotlinType unboxedInlineClass = CoroutineCodegenUtilKt + .originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(functionDescriptor, typeMapper); + + StackValue stackValueToWrap = stackValue; + KotlinType originalKotlinType; + if (unboxedInlineClass != null) { + originalKotlinType = unboxedInlineClass; + } else { + originalKotlinType = stackValueToWrap.kotlinType; + } + Type originalType; + if (unboxedInlineClass != null) { + originalType = typeMapper.mapType(unboxedInlineClass); + } else { + originalType = stackValueToWrap.type; + } + + stackValue = new StackValue(originalType, originalKotlinType) { + @Override + public void putSelector( + @NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v + ) { + if (((originalKotlinType != null && InlineClassesUtilsKt.isInlineClassType(originalKotlinType)) || + (kotlinType != null && InlineClassesUtilsKt.isInlineClassType(kotlinType))) + ) { + stackValueToWrap.put(v); + // Suspend functions always return Ljava/lang/Object;, so, before inline-class boxing/unboxing we need to generate CHECKCAST + StackValue.coerce(OBJECT_TYPE, originalType, v); + // Box/unbox inline class + StackValue.coerce(originalType, originalKotlinType, type, kotlinType, v); + } else { + // No inline class -> usual coerce is enough + stackValueToWrap.put(type, kotlinType, v); + } + } + }; + return stackValue; + } + public StackValue gen(KtElement expr) { StackValue tempVar = tempVariables.get(expr); return tempVar != null ? tempVar : genQualified(StackValue.none(), expr); @@ -1654,12 +1704,32 @@ public class ExpressionCodegen extends KtVisitor impleme Type returnType; KotlinType returnKotlinType; if (isNonLocalReturn) { - returnType = nonLocalReturn.returnType.getType(); - returnKotlinType = nonLocalReturn.returnType.getKotlinType(); + // This is inline lambda. Find inline-site and check, whether it is suspend functions returning unboxed inline class + CodegenContext inlineSiteContext = this.context.getFirstCrossInlineOrNonInlineContext(); + KotlinType originalInlineClass = null; + if (inlineSiteContext instanceof MethodContext) { + originalInlineClass = CoroutineCodegenUtilKt + .originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass( + ((MethodContext) inlineSiteContext).getFunctionDescriptor(), typeMapper); + } + if (originalInlineClass != null) { + returnType = typeMapper.mapType(originalInlineClass); + returnKotlinType = originalInlineClass; + } else { + returnType = nonLocalReturn.returnType.getType(); + returnKotlinType = nonLocalReturn.returnType.getKotlinType(); + } } else { - returnType = this.returnType; - returnKotlinType = typeMapper.getReturnValueType(this.context.getFunctionDescriptor()); + KotlinType originalInlineClass = CoroutineCodegenUtilKt + .originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(context.getFunctionDescriptor(), typeMapper); + if (originalInlineClass != null) { + returnType = typeMapper.mapType(originalInlineClass); + returnKotlinType = originalInlineClass; + } else { + returnType = this.returnType; + returnKotlinType = this.context.getFunctionDescriptor().getReturnType(); + } } StackValue valueToReturn = returnedExpression != null ? gen(returnedExpression) : StackValue.none(); @@ -1714,7 +1784,7 @@ public class ExpressionCodegen extends KtVisitor impleme return new NonLocalReturnInfo( new JvmKotlinType( typeMapper.mapReturnType(containingFunction), - typeMapper.getReturnValueType(containingFunction) + containingFunction.getReturnType() ), FIRST_FUN_LABEL ); @@ -1746,16 +1816,24 @@ public class ExpressionCodegen extends KtVisitor impleme boolean isVoidCoroutineLambda = originalSuspendLambdaDescriptor != null && TypeSignatureMappingKt.hasVoidReturnType(originalSuspendLambdaDescriptor); + KotlinType originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass = + CoroutineCodegenUtilKt.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass( + context.getFunctionDescriptor(), typeMapper); + // If generating body for named block-bodied function or Unit-typed coroutine lambda, generate it as sequence of statements Type typeForExpression = isBlockedNamedFunction || isVoidCoroutineLambda ? Type.VOID_TYPE - : returnType; + : originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass != null + ? typeMapper.mapType(originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass) + : returnType; KotlinType kotlinTypeForExpression = isBlockedNamedFunction || isVoidCoroutineLambda ? null - : typeMapper.getReturnValueType(context.getFunctionDescriptor()); + : originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass != null + ? originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass + : context.getFunctionDescriptor().getReturnType(); gen(expr, typeForExpression, kotlinTypeForExpression); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 5867c852901..21bcfedd7d7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -1060,7 +1060,7 @@ public class FunctionCodegen { // or all return types are supertypes of inline class (and can't be inline classes). for (DescriptorBasedFunctionHandleForJvm handle : bridge.getOriginalFunctions()) { - return state.getTypeMapper().getReturnValueType(handle.getDescriptor()); + return handle.getDescriptor().getReturnType(); } if (state.getClassBuilderMode().mightBeIncorrectCode) { @@ -1457,7 +1457,7 @@ public class FunctionCodegen { } } - KotlinType returnValueType = state.getTypeMapper().getReturnValueType(descriptor); + KotlinType returnValueType = descriptor.getReturnType(); StackValue.coerce(delegateTo.getReturnType(), returnValueType, bridge.getReturnType(), bridgeReturnType, iv); iv.areturn(bridge.getReturnType()); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt index 70913f148aa..df02e38d3cd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.inline.addFakeContinuationMarker import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.* @@ -32,15 +33,14 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE -import org.jetbrains.kotlin.types.ErrorUtils -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.KotlinTypeFactory -import org.jetbrains.kotlin.types.TypeConstructorSubstitution +import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.asTypeProjection +import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.org.objectweb.asm.Label @@ -453,6 +453,33 @@ fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingCon fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext, state: GenerationState) = getOriginalSuspendFunctionView(bindingContext, state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)) +// For each suspend function, we have a corresponding JVM view function that has an extra continuation parameter, +// and, more importantly, returns 'kotlin.Any' (so that it can return as a reference value or a special COROUTINE_SUSPENDED object). +// This also causes boxing of primitives and inline class values. +// If we have a function returning an inline class value that is mapped to a reference type, we want to avoid boxing. +// However, we have to do that consistently both on declaration site and on call site. +fun FunctionDescriptor.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(typeMapper: KotlinTypeMapper): KotlinType? { + if (!isSuspend) return null + // Suspend lambdas cannot return unboxed inline class + if (this is AnonymousFunctionDescriptor) return null + val originalDescriptor = unwrapInitialDescriptorForSuspendFunction().original + val originalReturnType = originalDescriptor.returnType ?: return null + if (!originalReturnType.isInlineClassType()) return null + // Force boxing for primitives + if (AsmUtil.isPrimitive(typeMapper.mapType(originalReturnType))) return null + // Force boxing for nullable inline class types with nullable underlying type + if (originalReturnType.isMarkedNullable && originalReturnType.isNullableUnderlyingType()) return null + // Force boxing if the function overrides function with return type Any + if (originalDescriptor.overriddenDescriptors.any { + (it.original.returnType?.isMarkedNullable == true && it.original.returnType?.isNullableUnderlyingType() == true) || + it.original.returnType?.makeNotNullable() != originalReturnType.makeNotNullable() + }) return null + // TODO: Do not box `Result` + if (originalReturnType.constructor.declarationDescriptor?.fqNameSafe == StandardNames.RESULT_FQ_NAME) return null + // Don't box other inline classes + return originalReturnType +} + fun InstructionAdapter.loadCoroutineSuspendedMarker(languageVersionSettings: LanguageVersionSettings) { invokestatic( languageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName().internalName, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt index 43cb5c49e4d..f51fb70581d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt @@ -16,9 +16,7 @@ import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.isStaticMethod import org.jetbrains.kotlin.codegen.JvmCodegenUtil.* import org.jetbrains.kotlin.codegen.binding.CodegenBinding.* -import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView -import org.jetbrains.kotlin.codegen.coroutines.isSuspendFunctionNotSuspensionView -import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction +import org.jetbrains.kotlin.codegen.coroutines.* import org.jetbrains.kotlin.codegen.inline.FictitiousArrayConstructor import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter @@ -356,43 +354,6 @@ class KotlinTypeMapper @JvmOverloads constructor( } } - fun getReturnValueType(functionDescriptor: FunctionDescriptor): KotlinType = - getActualReturnTypeForSuspendFunctionWithInlineClassReturnTypeHack(functionDescriptor) - ?: functionDescriptor.returnType!! - - private fun getActualReturnTypeForSuspendFunctionWithInlineClassReturnTypeHack(functionDescriptor: FunctionDescriptor): KotlinType? { - // For each suspend function, we have a corresponding JVM view function that has an extra continuation parameter, - // and, more importantly, returns 'kotlin.Any' (so that it can return as a reference value or a special COROUTINE_SUSPENDED object). - // This also causes boxing of primitives and inline class values. - // If we have a function returning an inline class value that is mapped to a reference type, we want to avoid boxing. - // However, we have to do that consistently both on declaration site and on call site. - - if (!functionDescriptor.isSuspend) return null - - val originalSuspendFunction = functionDescriptor.unwrapInitialDescriptorForSuspendFunction() - val originalReturnType = originalSuspendFunction.returnType!! - - if (!originalReturnType.isInlineClassType()) return null - - // Force boxing for primitives - if (AsmUtil.isPrimitive(mapType(originalReturnType))) { - return functionDescriptor.builtIns.nullableAnyType - } - - // Force boxing for nullable inline class types with nullable underlying type - if (originalReturnType.isMarkedNullable && originalReturnType.isNullableUnderlyingType()) { - return functionDescriptor.builtIns.nullableAnyType - } - - // Force boxing for Result type, otherwise, the coroutines machinery will break - if (originalReturnType.constructor.declarationDescriptor?.fqNameSafe == RESULT_FQ_NAME) { - return functionDescriptor.builtIns.nullableAnyType - } - - // Don't box other inline classes - return originalReturnType - } - @JvmOverloads fun mapToCallableMethod( descriptor: FunctionDescriptor, @@ -464,7 +425,7 @@ class KotlinTypeMapper @JvmOverloads constructor( invokeOpcode = INVOKESTATIC val originalDescriptor = descriptor.original signature = mapSignatureSkipGeneric(originalDescriptor, OwnerKind.DEFAULT_IMPLS) - returnKotlinType = getReturnValueType(originalDescriptor) + returnKotlinType = originalDescriptor.returnType if (descriptor is AccessorForCallableDescriptor<*> && descriptor.calleeDescriptor.isCompiledToJvmDefault(jvmDefaultMode)) { owner = mapClass(functionParent) isInterfaceMember = true @@ -515,7 +476,11 @@ class KotlinTypeMapper @JvmOverloads constructor( skipGenericSignature = true, hasSpecialBridge = false ) - returnKotlinType = getReturnValueType(functionToCall) + + returnKotlinType = + (if (functionToCall.isSuspend && + functionToCall.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(this) == null + ) functionDescriptor.builtIns.nullableAnyType else functionToCall.returnType) val receiver = if (currentIsInterface && !originalIsInterface || functionParent is FunctionClassDescriptor) declarationOwner @@ -528,7 +493,7 @@ class KotlinTypeMapper @JvmOverloads constructor( } else { val originalDescriptor = functionDescriptor.original signature = mapSignatureSkipGeneric(originalDescriptor) - returnKotlinType = getReturnValueType(originalDescriptor) + returnKotlinType = originalDescriptor.returnType owner = mapOwner(functionDescriptor) ownerForDefaultImpl = owner baseMethodDescriptor = functionDescriptor diff --git a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt new file mode 100644 index 00000000000..af083646c90 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt @@ -0,0 +1,26 @@ +// IGNORE_BACKEND: JVM_IR + +inline class ICString(val x: String) + +suspend fun suspendICString(): ICString = ICString("") +suspend fun suspendAny(): Any = ICString("") +suspend fun suspendGeneric(x: T): T = x + +fun useICString(x: ICString) {} +fun useAny(x: Any) {} + +suspend fun test() { + useICString(suspendICString()) + useICString(suspendGeneric(ICString(""))) + useAny(suspendAny()) + useAny(suspendICString()) +} + +// -- 1 in 'suspendAny(): Any = ICString("")' +// -- 1 in 'useAny(suspendICString())' +// -- 1 in 'suspendGeneric(ICString(""))' +// 3 INVOKESTATIC ICString\.box-impl + +// -- 1 in 'useICString(suspendGeneric(ICString(""))) +// -- 1 in 'equals-impl' for ICString +// 2 INVOKEVIRTUAL ICString\.unbox-impl \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/returnResult.kt b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt similarity index 80% rename from compiler/testData/codegen/bytecodeText/coroutines/returnResult.kt rename to compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt index 5b803c38449..03001bc61be 100644 --- a/compiler/testData/codegen/bytecodeText/coroutines/returnResult.kt +++ b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt @@ -1,3 +1,5 @@ +// IGNORE_BACKEND: JVM_IR + @Suppress("RESULT_CLASS_IN_RETURN_TYPE") suspend fun signInFlowStepFirst(): Result = Result.success(Unit) @@ -6,4 +8,4 @@ inline class OurAny(val a: Any) suspend fun returnsUnboxed(): OurAny = OurAny("OK") // 1 INVOKESTATIC kotlin/Result.box-impl -// 0 INVOKESTATIC kotlin/OurAny.box-impl \ No newline at end of file +// 0 INVOKESTATIC OurAny.box-impl \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnStringOverride.kt b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnStringOverride.kt new file mode 100644 index 00000000000..f5e518f3458 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnStringOverride.kt @@ -0,0 +1,11 @@ +inline class IC(val s: String) + +interface I { + suspend fun returnAny(): Any +} + +class C : I { + override suspend fun returnAny(): IC = IC("OK") +} + +// 1 INVOKESTATIC IC.box-impl diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index f258bba0e47..82fe6c2a2f4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1426,11 +1426,6 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/coroutines/nonLocalReturn.kt"); } - @TestMetadata("returnResult.kt") - public void testReturnResult() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/coroutines/returnResult.kt"); - } - @TestMetadata("returnUnitInLambda.kt") public void testReturnUnitInLambda_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/bytecodeText/coroutines/returnUnitInLambda.kt", "kotlin.coroutines.experimental"); @@ -1586,6 +1581,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { public void testNoInlineClassBoxingInSuspendFunReturn_InlineAny() throws Exception { runTest("compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_InlineAny.kt"); } + + @TestMetadata("noInlineClassBoxingInSuspendFunReturn_String.kt") + public void testNoInlineClassBoxingInSuspendFunReturn_String() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt"); + } + + @TestMetadata("returnResult.kt") + public void testReturnResult() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt"); + } + + @TestMetadata("returnStringOverride.kt") + public void testReturnStringOverride() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnStringOverride.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index 595608cd582..bc5b4de34f2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -1436,11 +1436,6 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/coroutines/nonLocalReturn.kt"); } - @TestMetadata("returnResult.kt") - public void testReturnResult() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/coroutines/returnResult.kt"); - } - @TestMetadata("returnUnitInLambda.kt") public void testReturnUnitInLambda_1_3() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/bytecodeText/coroutines/returnUnitInLambda.kt", "kotlin.coroutines"); @@ -1591,6 +1586,21 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { public void testNoInlineClassBoxingInSuspendFunReturn_InlineAny() throws Exception { runTest("compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_InlineAny.kt"); } + + @TestMetadata("noInlineClassBoxingInSuspendFunReturn_String.kt") + public void testNoInlineClassBoxingInSuspendFunReturn_String() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/noInlineClassBoxingInSuspendFunReturn_String.kt"); + } + + @TestMetadata("returnResult.kt") + public void testReturnResult() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnResult.kt"); + } + + @TestMetadata("returnStringOverride.kt") + public void testReturnStringOverride() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/coroutines/inlineClasses/returnStringOverride.kt"); + } } @TestMetadata("compiler/testData/codegen/bytecodeText/coroutines/intLikeVarSpilling")