diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 0a605fbe4d5..e89c87e4f6f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1510,8 +1510,16 @@ public class ExpressionCodegen extends KtVisitor impleme return Unit.INSTANCE; } - Type returnType = isNonLocalReturn ? nonLocalReturn.returnType : this.returnType; - KotlinType returnKotlinType = isNonLocalReturn ? null : this.context.getFunctionDescriptor().getReturnType(); + Type returnType; + KotlinType returnKotlinType; + if (isNonLocalReturn) { + returnType = nonLocalReturn.returnType.getType(); + returnKotlinType = nonLocalReturn.returnType.getKotlinType(); + } + else { + returnType = this.returnType; + returnKotlinType = this.context.getFunctionDescriptor().getReturnType(); + } StackValue valueToReturn = returnedExpression != null ? gen(returnedExpression) : StackValue.none(); putStackValue(returnedExpression, returnType, returnKotlinType, valueToReturn); @@ -1558,7 +1566,10 @@ public class ExpressionCodegen extends KtVisitor impleme FunctionDescriptor containingFunction = BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst(); //FIRST_FUN_LABEL to prevent clashing with existing labels - return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), FIRST_FUN_LABEL); + return new NonLocalReturnInfo( + new JvmKotlinType(typeMapper.mapReturnType(containingFunction), containingFunction.getReturnType()), + FIRST_FUN_LABEL + ); } else { //local return null; @@ -1570,7 +1581,11 @@ public class ExpressionCodegen extends KtVisitor impleme DeclarationDescriptor elementDescriptor = typeMapper.getBindingContext().get(DECLARATION_TO_DESCRIPTOR, element); assert element != null : "Expression should be not null " + expression.getText(); assert elementDescriptor != null : "Descriptor should be not null: " + element.getText(); - return new NonLocalReturnInfo(typeMapper.mapReturnType((CallableDescriptor) elementDescriptor), expression.getLabelName()); + CallableDescriptor function = (CallableDescriptor) elementDescriptor; + return new NonLocalReturnInfo( + new JvmKotlinType(typeMapper.mapReturnType(function), function.getReturnType()), + expression.getLabelName() + ); } } return null; @@ -4574,11 +4589,11 @@ The "returned" value of try expression with no finally is either the last expres private static class NonLocalReturnInfo { - private final Type returnType; + private final JvmKotlinType returnType; private final String labelName; - private NonLocalReturnInfo(@NotNull Type type, @NotNull String name) { + private NonLocalReturnInfo(@NotNull JvmKotlinType type, @NotNull String name) { returnType = type; labelName = name; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 0df69645c44..4fa567510f0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -450,7 +450,7 @@ public abstract class StackValue { if (isFromTypeUnboxed && !isToTypeUnboxed) { boxInlineClass(fromKotlinType, v); } - else if (!isFromTypeUnboxed) { + else if (!isFromTypeUnboxed && isToTypeUnboxed) { unboxInlineClass(fromType, fromKotlinType, v); } } diff --git a/compiler/testData/codegen/box/inlineClasses/checkBoxingForNonLocalAndLabeledReturns.kt b/compiler/testData/codegen/box/inlineClasses/checkBoxingForNonLocalAndLabeledReturns.kt new file mode 100644 index 00000000000..e070320bcda --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/checkBoxingForNonLocalAndLabeledReturns.kt @@ -0,0 +1,29 @@ +// !LANGUAGE: +InlineClasses + +inline class ULong(val l: Long) + +fun nonLocal(): ULong? { + val u1 = ULong(1) + + run { + return u1 // box + } + + ULong(-1) +} + +fun foo(): Boolean = true + +fun labeled(): ULong? { + val u = ULong(2) + return run { + if (foo()) return@run u + ULong(-1) // box + } +} + +fun box(): String { + if (nonLocal()!!.l != 1L) return "fail" + if (labeled()!!.l != 2L) return "fail" + return "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt new file mode 100644 index 00000000000..d3e7558495c --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt @@ -0,0 +1,29 @@ +// !LANGUAGE: +InlineClasses + +inline class ULong(val l: Long) + +fun nonLocal(): ULong? { + val u = ULong(0) + + run { + return u // box + } + + TODO() +} + +fun foo(): Boolean = true + +fun labeled(): ULong? { + val u = ULong(0) + return run { + if (foo()) return@run u + u // box + } +} + +// 2 INVOKESTATIC ULong\$Erased.box +// 0 INVOKEVIRTUAL ULong.unbox + +// 0 valueOf +// 0 intValue \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index ec9125e4121..40a51c865a4 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -10419,6 +10419,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("checkBoxingForNonLocalAndLabeledReturns.kt") + public void testCheckBoxingForNonLocalAndLabeledReturns() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkBoxingForNonLocalAndLabeledReturns.kt"); + doTest(fileName); + } + @TestMetadata("checkBoxingFromReturnTypeForInlineClasses.kt") public void testCheckBoxingFromReturnTypeForInlineClasses() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkBoxingFromReturnTypeForInlineClasses.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index ed679a7f113..eb1229ca97e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10419,6 +10419,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("checkBoxingForNonLocalAndLabeledReturns.kt") + public void testCheckBoxingForNonLocalAndLabeledReturns() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkBoxingForNonLocalAndLabeledReturns.kt"); + doTest(fileName); + } + @TestMetadata("checkBoxingFromReturnTypeForInlineClasses.kt") public void testCheckBoxingFromReturnTypeForInlineClasses() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkBoxingFromReturnTypeForInlineClasses.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 15979155ea2..7a2666f15b3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1944,6 +1944,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt") + public void testBoxingForNonLocalAndLabeledReturnsOfInlineClasses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxingForNonLocalAndLabeledReturnsOfInlineClasses.kt"); + doTest(fileName); + } + @TestMetadata("callMemberMethodsInsideInlineClass.kt") public void testCallMemberMethodsInsideInlineClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/callMemberMethodsInsideInlineClass.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index b5741c4023f..2e8ffce4900 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10419,6 +10419,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("checkBoxingForNonLocalAndLabeledReturns.kt") + public void testCheckBoxingForNonLocalAndLabeledReturns() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkBoxingForNonLocalAndLabeledReturns.kt"); + doTest(fileName); + } + @TestMetadata("checkBoxingFromReturnTypeForInlineClasses.kt") public void testCheckBoxingFromReturnTypeForInlineClasses() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkBoxingFromReturnTypeForInlineClasses.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 4e4f2deb8f4..58b83f3ffc6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -11403,6 +11403,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("checkBoxingForNonLocalAndLabeledReturns.kt") + public void testCheckBoxingForNonLocalAndLabeledReturns() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkBoxingForNonLocalAndLabeledReturns.kt"); + doTest(fileName); + } + @TestMetadata("checkBoxingFromReturnTypeForInlineClasses.kt") public void testCheckBoxingFromReturnTypeForInlineClasses() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/checkBoxingFromReturnTypeForInlineClasses.kt");