Fix boxing for non-local and labeled returns with inline classes

This commit is contained in:
Mikhail Zarechenskiy
2018-02-09 07:13:55 +03:00
parent 80dd5c106e
commit 1d16d21dbb
9 changed files with 110 additions and 7 deletions
@@ -1510,8 +1510,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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;
}
@@ -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);
}
}
@@ -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"
}
@@ -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
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");