Fix bridge methods generation when inline class types are used
This commit is contained in:
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy
|
|||||||
import org.jetbrains.kotlin.codegen.coroutines.SuspendInlineFunctionGenerationStrategy;
|
import org.jetbrains.kotlin.codegen.coroutines.SuspendInlineFunctionGenerationStrategy;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
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.codegen.state.TypeMapperUtilsKt;
|
||||||
import org.jetbrains.kotlin.config.JvmDefaultMode;
|
import org.jetbrains.kotlin.config.JvmDefaultMode;
|
||||||
import org.jetbrains.kotlin.config.JvmTarget;
|
import org.jetbrains.kotlin.config.JvmTarget;
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||||
@@ -615,7 +616,7 @@ public class FunctionCodegen {
|
|||||||
KotlinTypeMapper typeMapper = parentCodegen.typeMapper;
|
KotlinTypeMapper typeMapper = parentCodegen.typeMapper;
|
||||||
if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, typeMapper::mapAsmMethod)) {
|
if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, typeMapper::mapAsmMethod)) {
|
||||||
generateTypeCheckBarrierIfNeeded(
|
generateTypeCheckBarrierIfNeeded(
|
||||||
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), /* delegateParameterTypes = */null);
|
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), null, typeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
Label methodEnd;
|
Label methodEnd;
|
||||||
@@ -1422,16 +1423,23 @@ public class FunctionCodegen {
|
|||||||
Type[] argTypes = bridge.getArgumentTypes();
|
Type[] argTypes = bridge.getArgumentTypes();
|
||||||
Type[] originalArgTypes = delegateTo.getArgumentTypes();
|
Type[] originalArgTypes = delegateTo.getArgumentTypes();
|
||||||
|
|
||||||
|
List<ParameterDescriptor> allKotlinParameters = new ArrayList<>(argTypes.length);
|
||||||
|
if (descriptor.getExtensionReceiverParameter() != null) allKotlinParameters.add(descriptor.getExtensionReceiverParameter());
|
||||||
|
allKotlinParameters.addAll(descriptor.getValueParameters());
|
||||||
|
|
||||||
|
boolean safeToUseKotlinTypes = allKotlinParameters.size() == argTypes.length;
|
||||||
|
|
||||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||||
MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
|
MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
|
||||||
|
|
||||||
if (delegateTo.getArgumentTypes().length > 0 && isSpecialBridge) {
|
if (delegateTo.getArgumentTypes().length > 0 && isSpecialBridge) {
|
||||||
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes());
|
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes(), typeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
iv.load(0, OBJECT_TYPE);
|
iv.load(0, OBJECT_TYPE);
|
||||||
for (int i = 0, reg = 1; i < argTypes.length; i++) {
|
for (int i = 0, reg = 1; i < argTypes.length; i++) {
|
||||||
StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
|
KotlinType kotlinType = safeToUseKotlinTypes ? allKotlinParameters.get(i).getType() : null;
|
||||||
|
StackValue.local(reg, argTypes[i], kotlinType).put(originalArgTypes[i], kotlinType, iv);
|
||||||
//noinspection AssignmentToForLoopParameter
|
//noinspection AssignmentToForLoopParameter
|
||||||
reg += argTypes[i].getSize();
|
reg += argTypes[i].getSize();
|
||||||
}
|
}
|
||||||
@@ -1451,7 +1459,8 @@ public class FunctionCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
|
KotlinType returnType = descriptor.getReturnType();
|
||||||
|
StackValue.coerce(delegateTo.getReturnType(), returnType, bridge.getReturnType(), returnType, iv);
|
||||||
iv.areturn(bridge.getReturnType());
|
iv.areturn(bridge.getReturnType());
|
||||||
|
|
||||||
endVisit(mv, "bridge method", origin);
|
endVisit(mv, "bridge method", origin);
|
||||||
@@ -1461,7 +1470,8 @@ public class FunctionCodegen {
|
|||||||
@NotNull InstructionAdapter iv,
|
@NotNull InstructionAdapter iv,
|
||||||
@NotNull FunctionDescriptor descriptor,
|
@NotNull FunctionDescriptor descriptor,
|
||||||
@NotNull Type returnType,
|
@NotNull Type returnType,
|
||||||
@Nullable Type[] delegateParameterTypes
|
@Nullable Type[] delegateParameterTypes,
|
||||||
|
@NotNull KotlinTypeMapper typeMapper
|
||||||
) {
|
) {
|
||||||
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription typeSafeBarrierDescription =
|
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription typeSafeBarrierDescription =
|
||||||
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
|
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
|
||||||
@@ -1489,7 +1499,13 @@ public class FunctionCodegen {
|
|||||||
iv.ifnull(defaultBranch);
|
iv.ifnull(defaultBranch);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CodegenUtilKt.generateIsCheck(iv, kotlinType, boxType(delegateParameterTypes[i]));
|
Type targetBoxedType;
|
||||||
|
if (InlineClassesUtilsKt.isInlineClassType(kotlinType)) {
|
||||||
|
targetBoxedType = typeMapper.mapTypeAsDeclaration(kotlinType);
|
||||||
|
} else {
|
||||||
|
targetBoxedType = boxType(delegateParameterTypes[i]);
|
||||||
|
}
|
||||||
|
CodegenUtilKt.generateIsCheck(iv, kotlinType, targetBoxedType);
|
||||||
iv.ifeq(defaultBranch);
|
iv.ifeq(defaultBranch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+34
@@ -0,0 +1,34 @@
|
|||||||
|
// !LANGUAGE: +InlineClasses
|
||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
|
|
||||||
|
inline class InlinedComparable(val x: Int) : Comparable<InlinedComparable> {
|
||||||
|
override fun compareTo(other: InlinedComparable): Int {
|
||||||
|
return x.compareTo(other.x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> generic(c: Comparable<T>, element: T) = c.compareTo(element)
|
||||||
|
|
||||||
|
interface Base<T> {
|
||||||
|
fun Base<T>.foo(a: Base<T>, b: T): Base<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
inline class InlinedBase(val x: Int) : Base<InlinedBase> {
|
||||||
|
override fun Base<InlinedBase>.foo(a: Base<InlinedBase>, b: InlinedBase): Base<InlinedBase> {
|
||||||
|
return if (a is InlinedBase) InlinedBase(a.x + b.x) else this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun double(): InlinedBase {
|
||||||
|
return this.foo(this, this) as InlinedBase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = InlinedComparable(42)
|
||||||
|
if (generic(a, a) != 0) return "Fail 1"
|
||||||
|
|
||||||
|
val b = InlinedBase(3)
|
||||||
|
if (b.double().x != 6) return "Fail 2"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+6
@@ -13,6 +13,10 @@ inline class MyUIntArray(private val storage: IntArray) : Collection<MyUInt> {
|
|||||||
override fun isEmpty(): Boolean = TODO()
|
override fun isEmpty(): Boolean = TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> checkBoxed(c: Collection<T>, element: T): Boolean {
|
||||||
|
return c.contains(element) && c.containsAll(listOf(element))
|
||||||
|
}
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val uints = MyUIntArray(intArrayOf(0, 1, 42))
|
val uints = MyUIntArray(intArrayOf(0, 1, 42))
|
||||||
|
|
||||||
@@ -21,5 +25,7 @@ fun box(): String {
|
|||||||
val ints = listOf(MyUInt(1), MyUInt(0))
|
val ints = listOf(MyUInt(1), MyUInt(0))
|
||||||
if (!uints.containsAll(ints)) return "Fail 2"
|
if (!uints.containsAll(ints)) return "Fail 2"
|
||||||
|
|
||||||
|
if (!checkBoxed(uints, MyUInt(0))) return "Fail 3"
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
+3
-4
@@ -8,7 +8,7 @@ inline class UIntArray(private val intArray: IntArray) {
|
|||||||
|
|
||||||
inline class UIntIterator(private val intIterator: IntIterator) : Iterator<UInt> {
|
inline class UIntIterator(private val intIterator: IntIterator) : Iterator<UInt> {
|
||||||
override fun next(): UInt {
|
override fun next(): UInt {
|
||||||
return UInt(intIterator.next())
|
return UInt(intIterator.next()) // box inside bridge that returns java/lang/Object
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
override fun hasNext(): Boolean {
|
||||||
@@ -27,7 +27,7 @@ fun test() {
|
|||||||
|
|
||||||
fun takeUInt(u: UInt) {}
|
fun takeUInt(u: UInt) {}
|
||||||
|
|
||||||
// 0 INVOKESTATIC UInt\$Erased.box
|
// 1 INVOKESTATIC UInt\$Erased.box
|
||||||
// 0 INVOKEVIRTUAL UInt.unbox
|
// 0 INVOKEVIRTUAL UInt.unbox
|
||||||
|
|
||||||
// 0 INVOKEVIRTUAL UIntIterator.iterator
|
// 0 INVOKEVIRTUAL UIntIterator.iterator
|
||||||
@@ -35,5 +35,4 @@ fun takeUInt(u: UInt) {}
|
|||||||
|
|
||||||
// 0 intValue
|
// 0 intValue
|
||||||
|
|
||||||
// inside wrong bridge
|
// 0 valueOf
|
||||||
// 1 valueOf
|
|
||||||
Generated
+5
@@ -11169,6 +11169,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
|
||||||
|
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
||||||
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
||||||
|
|||||||
+5
@@ -11169,6 +11169,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
|
||||||
|
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
||||||
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
||||||
|
|||||||
+5
@@ -11169,6 +11169,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
|
||||||
|
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
||||||
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
||||||
|
|||||||
@@ -38,4 +38,4 @@ fun KotlinType.isNullableUnderlyingType(): Boolean {
|
|||||||
val underlyingType = unsubstitutedUnderlyingType() ?: return false
|
val underlyingType = unsubstitutedUnderlyingType() ?: return false
|
||||||
|
|
||||||
return TypeUtils.isNullableType(underlyingType)
|
return TypeUtils.isNullableType(underlyingType)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -10834,6 +10834,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
|
||||||
|
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
||||||
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
||||||
|
|||||||
+5
@@ -9712,6 +9712,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("bridgesWhenInlineClassImplementsGenericInterface.kt")
|
||||||
|
public void testBridgesWhenInlineClassImplementsGenericInterface() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/inlineClasses/bridgesWhenInlineClassImplementsGenericInterface.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
@TestMetadata("callComputablePropertyInsideInlineClass.kt")
|
||||||
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
public void testCallComputablePropertyInsideInlineClass() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
runTest("compiler/testData/codegen/box/inlineClasses/callComputablePropertyInsideInlineClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user