Don't remap inline function args requiring inline class boxing/unboxing
Same as for primitives: inline lambda expects to see a boxed value, so, even if an argument is a local variable, it can't be remapped, because it contains unboxed representation.
This commit is contained in:
@@ -487,6 +487,33 @@ public abstract class StackValue {
|
||||
coerce(fromType, toType, v);
|
||||
}
|
||||
|
||||
public static boolean requiresInlineClassBoxingOrUnboxing(
|
||||
@NotNull Type fromType,
|
||||
@Nullable KotlinType fromKotlinType,
|
||||
@NotNull Type toType,
|
||||
@Nullable KotlinType toKotlinType
|
||||
) {
|
||||
// NB see also coerceInlineClasses below
|
||||
|
||||
if (fromKotlinType == null || toKotlinType == null) return false;
|
||||
|
||||
boolean isFromTypeInlineClass = InlineClassesUtilsKt.isInlineClassType(fromKotlinType);
|
||||
boolean isToTypeInlineClass = InlineClassesUtilsKt.isInlineClassType(toKotlinType);
|
||||
|
||||
if (!isFromTypeInlineClass && !isToTypeInlineClass) return false;
|
||||
|
||||
boolean isFromTypeUnboxed = isFromTypeInlineClass && isUnboxedInlineClass(fromKotlinType, fromType);
|
||||
boolean isToTypeUnboxed = isToTypeInlineClass && isUnboxedInlineClass(toKotlinType, toType);
|
||||
|
||||
if (isFromTypeInlineClass && isToTypeInlineClass) {
|
||||
return isFromTypeUnboxed != isToTypeUnboxed;
|
||||
}
|
||||
else {
|
||||
return isFromTypeInlineClass /* && !isToTypeInlineClass */ && isFromTypeUnboxed ||
|
||||
isToTypeInlineClass /* && !isFromTypeInlineClass */ && isToTypeUnboxed;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean coerceInlineClasses(
|
||||
@NotNull Type fromType,
|
||||
@Nullable KotlinType fromKotlinType,
|
||||
@@ -494,6 +521,8 @@ public abstract class StackValue {
|
||||
@Nullable KotlinType toKotlinType,
|
||||
@NotNull InstructionAdapter v
|
||||
) {
|
||||
// NB see also requiresInlineClassBoxingOrUnboxing above
|
||||
|
||||
if (fromKotlinType == null || toKotlinType == null) return false;
|
||||
|
||||
boolean isFromTypeInlineClass = InlineClassesUtilsKt.isInlineClassType(fromKotlinType);
|
||||
|
||||
@@ -326,13 +326,14 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
) {
|
||||
val isDefaultParameter = kind === ValueKind.DEFAULT_PARAMETER
|
||||
val jvmType = jvmKotlinType.type
|
||||
if (!isDefaultParameter && shouldPutGeneralValue(jvmType, stackValue)) {
|
||||
stackValue.put(jvmType, jvmKotlinType.kotlinType, codegen.v)
|
||||
val kotlinType = jvmKotlinType.kotlinType
|
||||
if (!isDefaultParameter && shouldPutGeneralValue(jvmType, kotlinType, stackValue)) {
|
||||
stackValue.put(jvmType, kotlinType, codegen.v)
|
||||
}
|
||||
|
||||
if (!asFunctionInline && Type.VOID_TYPE !== jvmType) {
|
||||
//TODO remap only inlinable closure => otherwise we could get a lot of problem
|
||||
val couldBeRemapped = !shouldPutGeneralValue(jvmType, stackValue) && kind !== ValueKind.DEFAULT_PARAMETER
|
||||
val couldBeRemapped = !shouldPutGeneralValue(jvmType, kotlinType, stackValue) && kind !== ValueKind.DEFAULT_PARAMETER
|
||||
val remappedValue = if (couldBeRemapped) stackValue else null
|
||||
|
||||
val info: ParameterInfo
|
||||
@@ -603,11 +604,17 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
|
||||
/*descriptor is null for captured vars*/
|
||||
private fun shouldPutGeneralValue(type: Type, stackValue: StackValue): Boolean {
|
||||
private fun shouldPutGeneralValue(type: Type, kotlinType: KotlinType?, stackValue: StackValue): Boolean {
|
||||
//remap only inline functions (and maybe non primitives)
|
||||
//TODO - clean asserion and remapping logic
|
||||
//TODO - clean assertion and remapping logic
|
||||
|
||||
// don't remap boxing/unboxing primitives
|
||||
if (isPrimitive(type) != isPrimitive(stackValue.type)) {
|
||||
//don't remap boxing/unboxing primitives - lost identity and perfomance
|
||||
return true
|
||||
}
|
||||
|
||||
// don't remap boxing/unboxing inline classes
|
||||
if (StackValue.requiresInlineClassBoxingOrUnboxing(stackValue.type, stackValue.kotlinType, type, kotlinType)) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class Z(val int: Int)
|
||||
inline class L(val long: Long)
|
||||
inline class Str(val string: String)
|
||||
inline class Obj(val obj: Any)
|
||||
|
||||
inline fun <R> withDefaultZ(fn: (Z) -> R, x: Z = Z(42)) = fn(x)
|
||||
inline fun <R> withDefaultL(fn: (L) -> R, x: L = L(42L)) = fn(x)
|
||||
inline fun <R> withDefaultL2(x: L = L(42L), fn: (L) -> R) = fn(x)
|
||||
inline fun <R> withDefaultStr(fn: (Str) -> R, x: Str = Str("abc")) = fn(x)
|
||||
inline fun <R> withDefaultObj(fn: (Obj) -> R, x: Obj = Obj("abc")) = fn(x)
|
||||
inline fun <R> withDefaultObj2(x: Obj = Obj("abc"), fn: (Obj) -> R) = fn(x)
|
||||
|
||||
fun testWithDefaultZ() = withDefaultZ({ Z(it.int + 1) })
|
||||
fun testWithDefaultL() = withDefaultL({ L(it.long + 1L) })
|
||||
fun testWithDefaultL2() = withDefaultL2(fn = { L(it.long + 1L) })
|
||||
fun testWithDefaultStr() = withDefaultStr({ Str(it.string + "1") })
|
||||
fun testWithDefaultObj() = withDefaultObj({ Obj(it.obj.toString() + "1") })
|
||||
fun testWithDefaultObj2() = withDefaultObj2(fn = { Obj(it.obj.toString() + "1") })
|
||||
|
||||
fun box(): String {
|
||||
if (testWithDefaultZ().int != 43) throw AssertionError()
|
||||
if (testWithDefaultL().long != 43L) throw AssertionError()
|
||||
if (testWithDefaultL2().long != 43L) throw AssertionError()
|
||||
if (testWithDefaultStr().string != "abc1") throw AssertionError()
|
||||
if (testWithDefaultObj().obj != "abc1") throw AssertionError()
|
||||
if (testWithDefaultObj2().obj != "abc1") throw AssertionError()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class Z(val int: Int)
|
||||
inline class L(val long: Long)
|
||||
inline class Str(val string: String)
|
||||
inline class Obj(val obj: Any)
|
||||
|
||||
inline fun <R> s1Z(x: Z, fn: (Int, Z) -> R) = fn(1, x)
|
||||
inline fun <R> s1L(x: L, fn: (Int, L) -> R) = fn(1, x)
|
||||
inline fun <R> s1Str(x: Str, fn: (Int, Str) -> R) = fn(1, x)
|
||||
inline fun <R> s1Obj(x: Obj, fn: (Int, Obj) -> R) = fn(1, x)
|
||||
|
||||
fun testS1Z(a: Z) = s1Z(a) { i, xx -> Z(xx.int + i) }
|
||||
fun testS1L(a: L) = s1L(a) { i, xx -> L(xx.long + i.toLong()) }
|
||||
fun testS1Str(a: Str) = s1Str(a) { i, xx -> Str(xx.string + i.toString()) }
|
||||
fun testS1Obj(a: Obj) = s1Obj(a) { i, xx -> Obj(xx.obj.toString() + i.toString()) }
|
||||
|
||||
fun box(): String {
|
||||
if (testS1Z(Z(42)).int != 43) throw AssertionError()
|
||||
if (testS1L(L(42L)).long != 43L) throw AssertionError()
|
||||
if (testS1Str(Str("abc")).string != "abc1") throw AssertionError()
|
||||
if (testS1Obj(Obj("abc")).obj != "abc1") throw AssertionError()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
|
||||
inline class Str(val string: String)
|
||||
inline class Obj(val obj: Any)
|
||||
|
||||
inline fun <T, R> s0(x: T, fn: (Int, T) -> R) = fn(0, x)
|
||||
|
||||
inline fun <T, R> weirdMix(x: T, fn: (Int, T, Long, T) -> R) = fn(0, x, 0L, x)
|
||||
|
||||
fun testS0Str(x: Str) = s0(x) { _, xx -> Str(xx.string + "123") }
|
||||
fun testS0Any(x: Obj) = s0(x) { _, xx -> Obj(xx.obj.toString() + "123") }
|
||||
|
||||
fun testWeirdMixStr(x: Str) = weirdMix(x) { _, xx, _, _ -> Str(xx.string + "123") }
|
||||
fun testWeirdMixAny(x: Obj) = weirdMix(x) { _, xx, _, _ -> Obj(xx.obj.toString() + "123") }
|
||||
|
||||
fun box(): String {
|
||||
if (testS0Str(Str("abc")).string != "abc123") throw AssertionError()
|
||||
if (testS0Any(Obj("abc")).obj != "abc123") throw AssertionError()
|
||||
|
||||
if (testWeirdMixStr(Str("abc")).string != "abc123") throw AssertionError()
|
||||
if (testWeirdMixAny(Obj("abc")).obj != "abc123") throw AssertionError()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+15
@@ -11515,6 +11515,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultValueOfInlineClassTypeInInlineFun.kt")
|
||||
public void testDefaultValueOfInlineClassTypeInInlineFun() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultValueOfInlineClassTypeInInlineFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
@@ -11565,6 +11570,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesAsInlineFunParameters.kt")
|
||||
public void testInlineClassesAsInlineFunParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesAsInlineFunParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesCheckCast.kt")
|
||||
public void testInlineClassesCheckCast() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesCheckCast.kt");
|
||||
@@ -11575,6 +11585,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesRefTypesInInlineLambdaParameters.kt")
|
||||
public void testInlineClassesRefTypesInInlineLambdaParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesRefTypesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunctionInsideInlineClass.kt")
|
||||
public void testInlineFunctionInsideInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineFunctionInsideInlineClass.kt");
|
||||
|
||||
+15
@@ -11515,6 +11515,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultValueOfInlineClassTypeInInlineFun.kt")
|
||||
public void testDefaultValueOfInlineClassTypeInInlineFun() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultValueOfInlineClassTypeInInlineFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
@@ -11565,6 +11570,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesAsInlineFunParameters.kt")
|
||||
public void testInlineClassesAsInlineFunParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesAsInlineFunParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesCheckCast.kt")
|
||||
public void testInlineClassesCheckCast() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesCheckCast.kt");
|
||||
@@ -11575,6 +11585,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesRefTypesInInlineLambdaParameters.kt")
|
||||
public void testInlineClassesRefTypesInInlineLambdaParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesRefTypesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunctionInsideInlineClass.kt")
|
||||
public void testInlineFunctionInsideInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineFunctionInsideInlineClass.kt");
|
||||
|
||||
+15
@@ -11515,6 +11515,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultValueOfInlineClassTypeInInlineFun.kt")
|
||||
public void testDefaultValueOfInlineClassTypeInInlineFun() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultValueOfInlineClassTypeInInlineFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
@@ -11565,6 +11570,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesAsInlineFunParameters.kt")
|
||||
public void testInlineClassesAsInlineFunParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesAsInlineFunParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesCheckCast.kt")
|
||||
public void testInlineClassesCheckCast() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesCheckCast.kt");
|
||||
@@ -11575,6 +11585,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesRefTypesInInlineLambdaParameters.kt")
|
||||
public void testInlineClassesRefTypesInInlineLambdaParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesRefTypesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunctionInsideInlineClass.kt")
|
||||
public void testInlineFunctionInsideInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineFunctionInsideInlineClass.kt");
|
||||
|
||||
+15
@@ -10080,6 +10080,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultValueOfInlineClassTypeInInlineFun.kt")
|
||||
public void testDefaultValueOfInlineClassTypeInInlineFun() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultValueOfInlineClassTypeInInlineFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
@@ -10125,6 +10130,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesAsInlineFunParameters.kt")
|
||||
public void testInlineClassesAsInlineFunParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesAsInlineFunParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesCheckCast.kt")
|
||||
public void testInlineClassesCheckCast() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesCheckCast.kt");
|
||||
@@ -10135,6 +10145,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesRefTypesInInlineLambdaParameters.kt")
|
||||
public void testInlineClassesRefTypesInInlineLambdaParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesRefTypesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunctionInsideInlineClass.kt")
|
||||
public void testInlineFunctionInsideInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineFunctionInsideInlineClass.kt");
|
||||
|
||||
+15
@@ -11140,6 +11140,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultFunctionsFromAnyForInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("defaultValueOfInlineClassTypeInInlineFun.kt")
|
||||
public void testDefaultValueOfInlineClassTypeInInlineFun() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/defaultValueOfInlineClassTypeInInlineFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("elvisWithInlineClassAndNullConstant.kt")
|
||||
public void testElvisWithInlineClassAndNullConstant() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/elvisWithInlineClassAndNullConstant.kt");
|
||||
@@ -11185,6 +11190,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassWithCustomEquals.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesAsInlineFunParameters.kt")
|
||||
public void testInlineClassesAsInlineFunParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesAsInlineFunParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesCheckCast.kt")
|
||||
public void testInlineClassesCheckCast() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesCheckCast.kt");
|
||||
@@ -11195,6 +11205,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassesRefTypesInInlineLambdaParameters.kt")
|
||||
public void testInlineClassesRefTypesInInlineLambdaParameters() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineClassesRefTypesInInlineLambdaParameters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunctionInsideInlineClass.kt")
|
||||
public void testInlineFunctionInsideInlineClass() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/inlineClasses/inlineFunctionInsideInlineClass.kt");
|
||||
|
||||
Reference in New Issue
Block a user