From 948714e7e5708663808856bf6c6733248fae4470 Mon Sep 17 00:00:00 2001 From: "Evgeniy.Zhelenskiy" Date: Thu, 9 Mar 2023 22:13:38 +0100 Subject: [PATCH] [IR] Fix delegating MFVC constructors Signed-off-by: Evgeniy.Zhelenskiy #KT-1179 --- ...LightTreeBlackBoxCodegenTestGenerated.java | 6 ++ .../FirPsiBlackBoxCodegenTestGenerated.java | 6 ++ .../lower/JvmMultiFieldValueClassLowering.kt | 13 ++-- .../valueClasses/delegatingConstructors.kt | 36 ++++++++++ .../valueClasses/delegatingConstructors.txt | 70 +++++++++++++++++++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++ 6 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/codegen/box/valueClasses/delegatingConstructors.kt create mode 100644 compiler/testData/codegen/box/valueClasses/delegatingConstructors.txt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index 54994af3982..60ac102242c 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -51725,6 +51725,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/valueClasses/delegating.kt"); } + @Test + @TestMetadata("delegatingConstructors.kt") + public void testDelegatingConstructors() throws Exception { + runTest("compiler/testData/codegen/box/valueClasses/delegatingConstructors.kt"); + } + @Test @TestMetadata("equality.kt") public void testEquality() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index 94a98e70eea..5df46e5f2a8 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -51725,6 +51725,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/valueClasses/delegating.kt"); } + @Test + @TestMetadata("delegatingConstructors.kt") + public void testDelegatingConstructors() throws Exception { + runTest("compiler/testData/codegen/box/valueClasses/delegatingConstructors.kt"); + } + @Test @TestMetadata("equality.kt") public void testEquality() throws Exception { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt index 608ab6cd81f..164a1e1f238 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt @@ -462,14 +462,14 @@ internal class JvmMultiFieldValueClassLowering( override fun visitClass(declaration: IrClass): IrStatement = declaration override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { - if (expression.symbol.owner.constructedClass != constructor.constructedClass) { // Delegating constructor to Object - require(expression.symbol.owner.constructedClass == context.irBuiltIns.anyClass.owner) { - "Expected delegating constructor to the MFVC primary constructor or Any constructor but got: ${expression.symbol.owner.render()}" + val delegatedConstructor = expression.symbol.owner + if (delegatedConstructor.constructedClass != constructor.constructedClass) { // Delegating constructor to Object + require(delegatedConstructor.constructedClass == context.irBuiltIns.anyClass.owner) { + "Expected delegating constructor to the MFVC primary constructor or Any constructor but got: ${delegatedConstructor.render()}" } return irBlock { } } - val oldPrimaryConstructor = replacements.getRootMfvcNode(constructor.constructedClass).oldPrimaryConstructor - thisVar.initializer = irCall(oldPrimaryConstructor).apply { + thisVar.initializer = irCall(delegatedConstructor).apply { copyTypeAndValueArgumentsFrom(expression) } return irBlock {} @@ -1334,7 +1334,8 @@ internal class JvmMultiFieldValueClassLowering( constructor.origin != JvmLoweredDeclarationOrigin.STATIC_MULTI_FIELD_VALUE_CLASS_CONSTRUCTOR ) { val oldArguments = List(expression.valueArgumentsCount) { - expression.getValueArgument(it) ?: error("Default arguments for MFVC primary constructors are not yet supported") + expression.getValueArgument(it) + ?: error("Default arguments for MFVC primary constructors are not yet supported:\n${expression.dump()}") } require(rootNode.subnodes.size == oldArguments.size) { "Old ${constructor.render()} must have ${rootNode.subnodes.size} arguments but got ${oldArguments.size}" diff --git a/compiler/testData/codegen/box/valueClasses/delegatingConstructors.kt b/compiler/testData/codegen/box/valueClasses/delegatingConstructors.kt new file mode 100644 index 00000000000..ecca6c9aaac --- /dev/null +++ b/compiler/testData/codegen/box/valueClasses/delegatingConstructors.kt @@ -0,0 +1,36 @@ +// WITH_STDLIB +// TARGET_BACKEND: JVM_IR +// LANGUAGE: +ValueClasses +// CHECK_BYTECODE_LISTING +// FIR_IDENTICAL + +data class A(val w: Float) + +@JvmInline +value class B(val a: A, val b: A) { + + constructor(aW: Float, aX: Float, aY: Float, aZ: Float, + bW: Float, bX: Float, bY: Float, bZ: Float) : this(A(aW), A(bW)) + + constructor() : this(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f) +} + +data class C(val a: B, val b: B) { + + constructor(aW: B, aX: B, aY: B, aZ: B, + bW: B, bX: B, bY: B, bZ: B) : this(aW, bW) + + constructor() : this(B(), B()) +} + +fun box(): String { + require(B().a == A(0.0f)) + require(B().b == A(4.0f)) + + require(C().a.a == A(0.0f)) + require(C().a.b == A(4.0f)) + require(C().b.a == A(0.0f)) + require(C().b.b == A(4.0f)) + + return "OK" +} diff --git a/compiler/testData/codegen/box/valueClasses/delegatingConstructors.txt b/compiler/testData/codegen/box/valueClasses/delegatingConstructors.txt new file mode 100644 index 00000000000..a6e700aaf09 --- /dev/null +++ b/compiler/testData/codegen/box/valueClasses/delegatingConstructors.txt @@ -0,0 +1,70 @@ +@kotlin.Metadata +public final class A { + // source: 'delegatingConstructors.kt' + private final field w: float + public method (p0: float): void + public final method component1(): float + public synthetic static method copy$default(p0: A, p1: float, p2: int, p3: java.lang.Object): A + public final @org.jetbrains.annotations.NotNull method copy(p0: float): A + public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean + public final method getW(): float + public method hashCode(): int + public @org.jetbrains.annotations.NotNull method toString(): java.lang.String +} + +@kotlin.jvm.JvmInline +@kotlin.Metadata +public final class B { + // source: 'delegatingConstructors.kt' + private final @org.jetbrains.annotations.NotNull field a: A + private final @org.jetbrains.annotations.NotNull field b: A + private synthetic method (p0: A, p1: A): void + public synthetic final static method box-impl(p0: A, p1: A): B + public final static @org.jetbrains.annotations.NotNull method constructor-impl(): B + public final static method constructor-impl(@org.jetbrains.annotations.NotNull p0: A, @org.jetbrains.annotations.NotNull p1: A): void + public final static @org.jetbrains.annotations.NotNull method constructor-impl(p0: float, p1: float, p2: float, p3: float, p4: float, p5: float, p6: float, p7: float): B + public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean + public static method equals-impl(p0: A, p1: A, p2: java.lang.Object): boolean + public final static method equals-impl0(p0: A, p1: A, p2: A, p3: A): boolean + public final @org.jetbrains.annotations.NotNull method getA(): A + public final @org.jetbrains.annotations.NotNull method getB(): A + public method hashCode(): int + public static method hashCode-impl(p0: A, p1: A): int + public @org.jetbrains.annotations.NotNull method toString(): java.lang.String + public static method toString-impl(p0: A, p1: A): java.lang.String + public synthetic final method unbox-impl-a(): A + public synthetic final method unbox-impl-b(): A +} + +@kotlin.Metadata +public final class C { + // source: 'delegatingConstructors.kt' + private final @org.jetbrains.annotations.NotNull field a-a: A + private final @org.jetbrains.annotations.NotNull field a-b: A + private final @org.jetbrains.annotations.NotNull field b-a: A + private final @org.jetbrains.annotations.NotNull field b-b: A + public method (): void + private method (p0: A, p1: A, p2: A, p3: A): void + private method (p0: A, p1: A, p2: A, p3: A, p4: A, p5: A, p6: A, p7: A, p8: A, p9: A, p10: A, p11: A, p12: A, p13: A, p14: A, p15: A): void + public synthetic method (p0: A, p1: A, p2: A, p3: A, p4: A, p5: A, p6: A, p7: A, p8: A, p9: A, p10: A, p11: A, p12: A, p13: A, p14: A, p15: A, p16: kotlin.jvm.internal.DefaultConstructorMarker): void + public synthetic method (p0: A, p1: A, p2: A, p3: A, p4: kotlin.jvm.internal.DefaultConstructorMarker): void + public final @org.jetbrains.annotations.NotNull method component1(): B + public final @org.jetbrains.annotations.NotNull method component2(): B + public synthetic static method copy-qXRmaf0$default(p0: C, p1: A, p2: A, p3: A, p4: A, p5: int, p6: java.lang.Object): C + public final @org.jetbrains.annotations.NotNull method copy-qXRmaf0(@org.jetbrains.annotations.NotNull p0: A, @org.jetbrains.annotations.NotNull p1: A, @org.jetbrains.annotations.NotNull p2: A, @org.jetbrains.annotations.NotNull p3: A): C + public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean + public final @org.jetbrains.annotations.NotNull method getA(): B + public synthetic final method getA-a(): A + public synthetic final method getA-b(): A + public final @org.jetbrains.annotations.NotNull method getB(): B + public synthetic final method getB-a(): A + public synthetic final method getB-b(): A + public method hashCode(): int + public @org.jetbrains.annotations.NotNull method toString(): java.lang.String +} + +@kotlin.Metadata +public final class DelegatingConstructorsKt { + // source: 'delegatingConstructors.kt' + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index fe2de93c9ea..c5a3161c0b0 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -51725,6 +51725,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/valueClasses/delegating.kt"); } + @Test + @TestMetadata("delegatingConstructors.kt") + public void testDelegatingConstructors() throws Exception { + runTest("compiler/testData/codegen/box/valueClasses/delegatingConstructors.kt"); + } + @Test @TestMetadata("equality.kt") public void testEquality() throws Exception {