From 4e4511bba2c7d46adc5eb182ad13bce324e6aefa Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Wed, 17 Aug 2022 15:37:16 +0200 Subject: [PATCH] FIR2IR: convert enums with non-primary default ctor correctly see added test for example --- .../fir/backend/Fir2IrClassifierStorage.kt | 12 ------------ .../kotlin/fir/backend/Fir2IrConverter.kt | 3 ++- .../kotlin/fir/backend/Fir2IrVisitor.kt | 19 ++++++++++++++++++- .../FirBlackBoxCodegenTestGenerated.java | 6 ++++++ .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 3 +++ .../enum/defaultCtor/noPrimaryConstructor.kt | 16 ++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++++++ .../LightAnalysisModeTestGenerated.java | 5 +++++ .../js/test/JsCodegenBoxTestGenerated.java | 6 ++++++ .../test/ir/IrJsCodegenBoxTestGenerated.java | 6 ++++++ .../IrCodegenBoxWasmTestGenerated.java | 5 +++++ .../NativeCodegenBoxTestGenerated.java | 6 ++++++ 13 files changed, 85 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt index 35a22d948d7..1c13f8f0fef 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt @@ -27,13 +27,11 @@ import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrEnumConstructorCallImpl import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.util.IdSignature -import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.StandardClassIds @@ -528,7 +526,6 @@ class Fir2IrClassifierStorage( startOffset, endOffset, origin, symbol, enumEntry.name ).apply { declarationStorage.enterScope(this) - val irType = enumEntry.returnTypeRef.toIrType() if (irParent != null) { this.parent = irParent } @@ -541,15 +538,6 @@ class Fir2IrClassifierStorage( } // Otherwise, this is a default-ish enum entry whose initializer would be a delegating constructor call, // which will be translated via visitor later. - } else if (irParent != null && origin == IrDeclarationOrigin.DEFINED) { - val constructor = irParent.constructors.first() - this.initializerExpression = factory.createExpressionBody( - IrEnumConstructorCallImpl( - startOffset, endOffset, irType, constructor.symbol, - valueArgumentsCount = constructor.valueParameters.size, - typeArgumentsCount = constructor.typeParameters.size - ) - ) } declarationStorage.leaveScope(this) } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index 592d1bd0dda..44fc8a02ec5 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -234,6 +234,7 @@ class Fir2IrConverter( if (irConstructor != null) { irClass.declarations += irConstructor } + // At least on enum entry creation we may need a default constructor, so ctors should be converted first for (declaration in syntheticPropertiesLast(allDeclarations)) { val irDeclaration = processMemberDeclaration(declaration, regularClass, irClass) ?: continue irClass.declarations += irDeclaration @@ -294,7 +295,7 @@ class Fir2IrConverter( // Sort declarations so that all non-synthetic declarations are before synthetic ones. // This is needed because converting synthetic fields for implementation delegation needs to know // existing declarations in the class to avoid adding redundant delegated members. - private fun syntheticPropertiesLast(declarations: List): Iterable { + private fun syntheticPropertiesLast(declarations: Iterable): Iterable { return declarations.sortedBy { it !is FirField && it.isSynthetic } } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index f7e6a72b819..654a7c56f5d 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -47,6 +47,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.ir.util.defaultConstructor import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.parentClassOrNull import org.jetbrains.kotlin.lexer.KtTokens @@ -116,6 +117,8 @@ class Fir2IrVisitor( annotationGenerator.generate(irEnumEntry, enumEntry) val correspondingClass = irEnumEntry.correspondingClass val initializer = enumEntry.initializer + val irType = enumEntry.returnTypeRef.toIrType() + val irParentEnumClass = irEnumEntry.parent as? IrClass // If the enum entry has its own members, we need to introduce a synthetic class. if (correspondingClass != null) { declarationStorage.enterScope(irEnumEntry) @@ -129,7 +132,7 @@ class Fir2IrVisitor( val constructor = correspondingClass.constructors.first() irEnumEntry.initializerExpression = irFactory.createExpressionBody( IrEnumConstructorCallImpl( - startOffset, endOffset, enumEntry.returnTypeRef.toIrType(), + startOffset, endOffset, irType, constructor.symbol, typeArgumentsCount = constructor.typeParameters.size, valueArgumentsCount = constructor.valueParameters.size @@ -148,6 +151,20 @@ class Fir2IrVisitor( ) } } + } else if (irParentEnumClass != null && initializer == null) { + // a default-ish enum entry whose initializer would be a delegating constructor call + val constructor = + irParentEnumClass.defaultConstructor ?: error("Assuming that default constructor should exist and be converted at this point") + enumEntry.convertWithOffsets { startOffset, endOffset -> + irEnumEntry.initializerExpression = irFactory.createExpressionBody( + IrEnumConstructorCallImpl( + startOffset, endOffset, irType, constructor.symbol, + valueArgumentsCount = constructor.valueParameters.size, + typeArgumentsCount = constructor.typeParameters.size + ) + ) + irEnumEntry + } } return irEnumEntry } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index d7622dff9dd..316a559a91d 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -16956,6 +16956,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/enum/defaultCtor/entryClassConstructorWithVarargs.kt"); } + @Test + @TestMetadata("noPrimaryConstructor.kt") + public void testNoPrimaryConstructor() throws Exception { + runTest("compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt"); + } + @Test @TestMetadata("secondaryConstructorWithDefaultArguments.kt") public void testSecondaryConstructorWithDefaultArguments() throws Exception { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index a8814209b99..6b822edad26 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -213,6 +213,9 @@ val IrClassSymbol.functions: Sequence val IrClass.constructors: Sequence get() = declarations.asSequence().filterIsInstance() +val IrClass.defaultConstructor: IrConstructor? + get() = constructors.firstOrNull { ctor -> ctor.valueParameters.all { it.defaultValue != null } } + val IrClassSymbol.constructors: Sequence get() = owner.constructors.map { it.symbol } diff --git a/compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt b/compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt new file mode 100644 index 00000000000..cd17a57dd7a --- /dev/null +++ b/compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt @@ -0,0 +1,16 @@ + +enum class Test { + A(0), + B; + + val n: Int + + constructor(n: Int) { this.n = n } + constructor() : this(0) +} + +fun box(): String = + if (Test.A.n == Test.B.n) + "OK" + else + "Fail" \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index efdb26dd599..266e7b2b95f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -16674,6 +16674,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/enum/defaultCtor/entryClassConstructorWithVarargs.kt"); } + @Test + @TestMetadata("noPrimaryConstructor.kt") + public void testNoPrimaryConstructor() throws Exception { + runTest("compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt"); + } + @Test @TestMetadata("secondaryConstructorWithDefaultArguments.kt") public void testSecondaryConstructorWithDefaultArguments() throws Exception { 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 a8830a63124..af4b618fbbf 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 @@ -16956,6 +16956,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/enum/defaultCtor/entryClassConstructorWithVarargs.kt"); } + @Test + @TestMetadata("noPrimaryConstructor.kt") + public void testNoPrimaryConstructor() throws Exception { + runTest("compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt"); + } + @Test @TestMetadata("secondaryConstructorWithDefaultArguments.kt") public void testSecondaryConstructorWithDefaultArguments() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 054f5febeec..bf16f7eed00 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -13761,6 +13761,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/enum/defaultCtor/entryClassConstructorWithVarargs.kt"); } + @TestMetadata("noPrimaryConstructor.kt") + public void testNoPrimaryConstructor() throws Exception { + runTest("compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt"); + } + @TestMetadata("secondaryConstructorWithDefaultArguments.kt") public void testSecondaryConstructorWithDefaultArguments() throws Exception { runTest("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index 6bf5b0432ea..4ae1124ed82 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -12860,6 +12860,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/enum/defaultCtor/entryClassConstructorWithVarargs.kt"); } + @Test + @TestMetadata("noPrimaryConstructor.kt") + public void testNoPrimaryConstructor() throws Exception { + runTest("compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt"); + } + @Test @TestMetadata("secondaryConstructorWithDefaultArguments.kt") public void testSecondaryConstructorWithDefaultArguments() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index 1baba40f1bf..26837728438 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -12956,6 +12956,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/enum/defaultCtor/entryClassConstructorWithVarargs.kt"); } + @Test + @TestMetadata("noPrimaryConstructor.kt") + public void testNoPrimaryConstructor() throws Exception { + runTest("compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt"); + } + @Test @TestMetadata("secondaryConstructorWithDefaultArguments.kt") public void testSecondaryConstructorWithDefaultArguments() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 6c2f33b1a87..6a1b804df6e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -11486,6 +11486,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/enum/defaultCtor/entryClassConstructorWithVarargs.kt"); } + @TestMetadata("noPrimaryConstructor.kt") + public void testNoPrimaryConstructor() throws Exception { + runTest("compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt"); + } + @TestMetadata("secondaryConstructorWithDefaultArguments.kt") public void testSecondaryConstructorWithDefaultArguments() throws Exception { runTest("compiler/testData/codegen/box/enum/defaultCtor/secondaryConstructorWithDefaultArguments.kt"); diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index 9e69a4ba89d..95458507c4d 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -13968,6 +13968,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest runTest("compiler/testData/codegen/box/enum/defaultCtor/entryClassConstructorWithVarargs.kt"); } + @Test + @TestMetadata("noPrimaryConstructor.kt") + public void testNoPrimaryConstructor() throws Exception { + runTest("compiler/testData/codegen/box/enum/defaultCtor/noPrimaryConstructor.kt"); + } + @Test @TestMetadata("secondaryConstructorWithDefaultArguments.kt") public void testSecondaryConstructorWithDefaultArguments() throws Exception {