diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 3bd1e8f52d4..cf76d29a371 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1672,14 +1672,13 @@ public class ExpressionCodegen extends KtVisitor impleme if (descriptor instanceof PropertyDescriptor) { PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; - // `this` is represented as first parameter of function in erased inline class - boolean isThisOfErasedInlineClass = - contextKind() == OwnerKind.ERASED_INLINE_CLASS && + boolean isUnderlyingPropertyOfInlineClass = InlineClassesUtilsKt.isInlineClass(propertyDescriptor.getContainingDeclaration()) && JvmCodegenUtil.hasBackingField(propertyDescriptor, contextKind(), bindingContext); - if (isThisOfErasedInlineClass) { - Type underlyingRepresentationType = typeMapper.mapType(propertyDescriptor.getType()); - return StackValue.local(0, underlyingRepresentationType); + + if (isUnderlyingPropertyOfInlineClass) { + KotlinType propertyType = propertyDescriptor.getType(); + return StackValue.underlyingValueOfInlineClass(typeMapper.mapType(propertyType), propertyType, receiver); } Collection codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject()); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 103b538fd94..71e932ac3f4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -291,6 +291,14 @@ public abstract class StackValue { return new CollectionElement(collectionElementReceiver, type, kotlinType, getter, setter, codegen); } + public static UnderlyingValueOfInlineClass underlyingValueOfInlineClass( + @NotNull Type type, + @Nullable KotlinType kotlinType, + @NotNull StackValue receiver + ) { + return new UnderlyingValueOfInlineClass(type, kotlinType, receiver); + } + @NotNull public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic, @NotNull StackValue receiver) { return field(type, null, owner, name, isStatic, receiver, null); @@ -1004,6 +1012,24 @@ public abstract class StackValue { } } + public static class UnderlyingValueOfInlineClass extends StackValueWithSimpleReceiver { + + public UnderlyingValueOfInlineClass( + @NotNull Type type, + @Nullable KotlinType kotlinType, + @NotNull StackValue receiver + ) { + super(type, kotlinType, false, false, receiver, true); + } + + @Override + public void putSelector( + @NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v + ) { + coerceTo(type, kotlinType, v); + } + } + public static class CollectionElementReceiver extends StackValue { private final Callable callable; private final boolean isGetter; diff --git a/compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyInsideInlineClass.kt b/compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyInsideInlineClass.kt new file mode 100644 index 00000000000..4d468101cab --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyInsideInlineClass.kt @@ -0,0 +1,16 @@ +// !LANGUAGE: +InlineClasses + +inline class UInt(val value: Int) { + operator fun plus(other: UInt) = UInt(value + other.value) + fun otherValue(other: UInt) = other.value +} + +fun box(): String { + val a = UInt(10) + val b = UInt(20) + if (a.otherValue(b) != 20) return "fail 1" + + if ((a + b).value != 30) return "fail 2" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyOfInlineClass.kt b/compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyOfInlineClass.kt new file mode 100644 index 00000000000..be73e994822 --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyOfInlineClass.kt @@ -0,0 +1,16 @@ +// !LANGUAGE: +InlineClasses + +inline class UInt(val value: Int) + +fun box(): String { + val a = UInt(123) + if(a.value != 123) return "fail" + + val c = a.value.hashCode() + if (c.hashCode() != 123.hashCode()) return "fail" + + val b = UInt(100).value + a.value + if (b != 223) return "faile" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt new file mode 100644 index 00000000000..679931f4fa6 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt @@ -0,0 +1,17 @@ +// !LANGUAGE: +InlineClasses + +inline class UInt(val value: Int) + +fun test(u1: UInt, u2: UInt) { + val a = u1.value + + val b = u1.value.hashCode() // box int to call hashCode + val c = u1.value + u2.value +} + +// 0 INVOKESTATIC UInt\$Erased.getValue +// 0 INVOKESTATIC UInt\$Erased.box +// 0 INVOKEVIRTUAL UInt.unbox + +// 1 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 d7202423d55..2f958987049 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 @@ -10467,6 +10467,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("referToUnderlyingPropertyInsideInlineClass.kt") + public void testReferToUnderlyingPropertyInsideInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyInsideInlineClass.kt"); + doTest(fileName); + } + + @TestMetadata("referToUnderlyingPropertyOfInlineClass.kt") + public void testReferToUnderlyingPropertyOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("UIntArraySortExample.kt") public void testUIntArraySortExample() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 6aba9d4546f..69b97efbb53 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10467,6 +10467,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("referToUnderlyingPropertyInsideInlineClass.kt") + public void testReferToUnderlyingPropertyInsideInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyInsideInlineClass.kt"); + doTest(fileName); + } + + @TestMetadata("referToUnderlyingPropertyOfInlineClass.kt") + public void testReferToUnderlyingPropertyOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("UIntArraySortExample.kt") public void testUIntArraySortExample() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 0d3c7014626..341ccf2007a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1974,6 +1974,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("skipCallToUnderlyingValueOfInlineClass.kt") + public void testSkipCallToUnderlyingValueOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("uIntArrayIteratorWithoutBoxing.kt") public void testUIntArrayIteratorWithoutBoxing() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/uIntArrayIteratorWithoutBoxing.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index a5b07fcdaee..f4fe76e117a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10467,6 +10467,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } + @TestMetadata("referToUnderlyingPropertyInsideInlineClass.kt") + public void testReferToUnderlyingPropertyInsideInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyInsideInlineClass.kt"); + doTest(fileName); + } + + @TestMetadata("referToUnderlyingPropertyOfInlineClass.kt") + public void testReferToUnderlyingPropertyOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("UIntArraySortExample.kt") public void testUIntArraySortExample() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.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 b0384444ce8..869846d7dd1 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 @@ -11451,6 +11451,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } + @TestMetadata("referToUnderlyingPropertyInsideInlineClass.kt") + public void testReferToUnderlyingPropertyInsideInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyInsideInlineClass.kt"); + doTest(fileName); + } + + @TestMetadata("referToUnderlyingPropertyOfInlineClass.kt") + public void testReferToUnderlyingPropertyOfInlineClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/referToUnderlyingPropertyOfInlineClass.kt"); + doTest(fileName); + } + @TestMetadata("UIntArraySortExample.kt") public void testUIntArraySortExample() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/UIntArraySortExample.kt");