Fix CCE when unboxed inline class receiver is passed to inline function
Initial problem is started in `capturedBoundReferenceReceiver` method where we assume that bound receiver is captured for usual call. Note that if method is inline then we don't pass actual name reference receiver, but pass special CAPTURED_RECEIVER_FIELD, which is then is used to find special instructions during inline and fold several instructions in `foldFieldAccessChainIfNeeded`. As a result, we got unboxed reference receiver for inline call, which caused CCE and to fix it we should box receiver one more time during inline #KT-28188 Fixed
This commit is contained in:
@@ -748,9 +748,16 @@ class PsiInlineCodegen(
|
|||||||
val receiverValue = getBoundCallableReferenceReceiver(argumentExpression)
|
val receiverValue = getBoundCallableReferenceReceiver(argumentExpression)
|
||||||
if (receiverValue != null) {
|
if (receiverValue != null) {
|
||||||
val receiver = codegen.generateReceiverValue(receiverValue, false)
|
val receiver = codegen.generateReceiverValue(receiverValue, false)
|
||||||
|
val receiverKotlinType = receiver.kotlinType
|
||||||
|
val boxedReceiver =
|
||||||
|
if (receiverKotlinType != null)
|
||||||
|
receiver.type.boxReceiverForBoundReference(receiverKotlinType, state)
|
||||||
|
else
|
||||||
|
receiver.type.boxReceiverForBoundReference()
|
||||||
|
|
||||||
putClosureParametersOnStack(
|
putClosureParametersOnStack(
|
||||||
lambdaInfo,
|
lambdaInfo,
|
||||||
StackValue.coercion(receiver, receiver.type.boxReceiverForBoundReference(), null)
|
StackValue.coercion(receiver, boxedReceiver, receiverKotlinType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
|||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.*
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.*
|
||||||
import org.jetbrains.kotlin.codegen.binding.MutableClosure
|
import org.jetbrains.kotlin.codegen.binding.MutableClosure
|
||||||
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor
|
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.psi.KtLambdaExpression
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||||
import org.jetbrains.org.objectweb.asm.ClassVisitor
|
import org.jetbrains.org.objectweb.asm.ClassVisitor
|
||||||
@@ -173,7 +175,11 @@ class DefaultLambda(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Type.boxReceiverForBoundReference() = AsmUtil.boxType(this)
|
fun Type.boxReceiverForBoundReference() =
|
||||||
|
AsmUtil.boxType(this)
|
||||||
|
|
||||||
|
fun Type.boxReceiverForBoundReference(kotlinType: KotlinType, state: GenerationState) =
|
||||||
|
AsmUtil.boxType(this, kotlinType, state)
|
||||||
|
|
||||||
abstract class ExpressionLambda(protected val typeMapper: KotlinTypeMapper, isCrossInline: Boolean) : LambdaInfo(isCrossInline) {
|
abstract class ExpressionLambda(protected val typeMapper: KotlinTypeMapper, isCrossInline: Boolean) : LambdaInfo(isCrossInline) {
|
||||||
|
|
||||||
|
|||||||
Vendored
+65
@@ -0,0 +1,65 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// IGNORE_BACKEND: JVM_IR
|
||||||
|
|
||||||
|
inline class IcInt(val i: Int) {
|
||||||
|
fun simple(): String = i.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline class IcLong(val l: Long) {
|
||||||
|
fun simple(): String = l.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline class IcAny(val a: Any?) {
|
||||||
|
fun simple(): String = a?.toString() ?: "null"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline class IcOverIc(val o: IcLong) {
|
||||||
|
fun simple(): String = o.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testUnboxed(i: IcInt, l: IcLong, a: IcAny, o: IcOverIc): String =
|
||||||
|
foo(i::simple) + foo(l::simple) + foo(a::simple) + foo(o::simple)
|
||||||
|
|
||||||
|
fun testBoxed(i: IcInt?, l: IcLong?, a: IcAny?, o: IcOverIc?): String =
|
||||||
|
foo(i!!::simple) + foo(l!!::simple) + foo(a!!::simple) + foo(o!!::simple)
|
||||||
|
|
||||||
|
fun testLocalVars(): String {
|
||||||
|
val i = IcInt(0)
|
||||||
|
val l = IcLong(1L)
|
||||||
|
val a = IcAny(2)
|
||||||
|
val o = IcOverIc(IcLong(3))
|
||||||
|
|
||||||
|
return foo(i::simple) + foo(l::simple) + foo(a::simple) + foo(o::simple)
|
||||||
|
}
|
||||||
|
|
||||||
|
val ip = IcInt(1)
|
||||||
|
val lp = IcLong(2L)
|
||||||
|
val ap = IcAny(3)
|
||||||
|
val op = IcOverIc(IcLong(4))
|
||||||
|
|
||||||
|
fun testGlobalProperties(): String =
|
||||||
|
foo(ip::simple) + foo(lp::simple) + foo(ap::simple) + foo(op::simple)
|
||||||
|
|
||||||
|
fun testCapturedVars(): String {
|
||||||
|
return IcInt(2).let { foo(it::simple) } +
|
||||||
|
IcLong(3).let { foo(it::simple) } +
|
||||||
|
IcAny(4).let { foo(it::simple) } +
|
||||||
|
IcOverIc(IcLong(5)).let { foo(it::simple) }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun foo(init: () -> String): String = init()
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val i = IcInt(3)
|
||||||
|
val l = IcLong(4)
|
||||||
|
val a = IcAny(5)
|
||||||
|
val o = IcOverIc(IcLong(6))
|
||||||
|
|
||||||
|
if (testUnboxed(i, l, a, o) != "345IcLong(l=6)") return "Fail 1"
|
||||||
|
if (testBoxed(i, l, a, o) != "345IcLong(l=6)") return "Fail 2"
|
||||||
|
if (testLocalVars() != "012IcLong(l=3)") return "Fail 3"
|
||||||
|
if (testGlobalProperties() != "123IcLong(l=4)") return "Fail 4"
|
||||||
|
if (testCapturedVars() != "234IcLong(l=5)") return "Fail 5"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+5
@@ -11665,6 +11665,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boundCallableReferencePassedToInlineFunction.kt")
|
||||||
|
public void testBoundCallableReferencePassedToInlineFunction() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/boundCallableReferencePassedToInlineFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
||||||
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
||||||
|
|||||||
+5
@@ -11665,6 +11665,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boundCallableReferencePassedToInlineFunction.kt")
|
||||||
|
public void testBoundCallableReferencePassedToInlineFunction() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/boundCallableReferencePassedToInlineFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
||||||
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
||||||
|
|||||||
+5
@@ -11670,6 +11670,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boundCallableReferencePassedToInlineFunction.kt")
|
||||||
|
public void testBoundCallableReferencePassedToInlineFunction() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/boundCallableReferencePassedToInlineFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
||||||
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
||||||
|
|||||||
+5
@@ -10095,6 +10095,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boundCallableReferencePassedToInlineFunction.kt")
|
||||||
|
public void testBoundCallableReferencePassedToInlineFunction() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/boundCallableReferencePassedToInlineFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
||||||
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
||||||
|
|||||||
+5
@@ -11140,6 +11140,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("boundCallableReferencePassedToInlineFunction.kt")
|
||||||
|
public void testBoundCallableReferencePassedToInlineFunction() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/boundCallableReferencePassedToInlineFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
@TestMetadata("boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt")
|
||||||
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
public void testBoxNullableValueOfInlineClassWithNonNullUnderlyingType() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxNullableValueOfInlineClassWithNonNullUnderlyingType.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user