From 4fa2fa6c26d2a9b9fdc36438b5aee23882cf78a3 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Thu, 28 Oct 2021 20:05:49 +0300 Subject: [PATCH] [JS IR] Export name and ordinal for enum classes ^KT-37916 fixed ^KT-44494 fixed --- .../backend/js/export/ExportModelGenerator.kt | 23 +++++++++++++++---- .../transformers/irToJs/JsClassGenerator.kt | 12 ++++++---- .../testData/box/export/exportEnumClass.kt | 6 +++++ .../declarations/declarations.d.ts | 2 ++ .../declarations/declarations__main.js | 4 ++++ .../declarations/declarations__main.ts | 5 ++++ 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt index 34fbe6cf07a..7fd590d3a24 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelGenerator.kt @@ -108,7 +108,7 @@ class ExportModelGenerator( // TODO: Report a frontend error if (accessor.extensionReceiverParameter != null) return null - if (accessor.isFakeOverride) { + if (accessor.isFakeOverride && !accessor.isEnumFakeOverriddenDeclaration(context)) { return null } } @@ -446,14 +446,15 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont if (context?.additionalExportedDeclarations?.contains(declaration) == true) return true - if (declaration is IrSimpleFunction) { + if (declaration is IrOverridableDeclaration<*>) { val overriddenNonEmpty = declaration .overriddenSymbols .isNotEmpty() if (overriddenNonEmpty) { return declaration.isOverriddenExported(context) || - declaration.isMethodOfAny() // Handle names for special functions + (declaration as? IrSimpleFunction)?.isMethodOfAny() == true // Handle names for special functions + || declaration.isEnumFakeOverriddenDeclaration(context) } } @@ -467,9 +468,21 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont } } -fun IrSimpleFunction.isOverriddenExported(context: JsIrBackendContext?): Boolean = +fun IrOverridableDeclaration<*>.isEnumFakeOverriddenDeclaration(context: JsIrBackendContext?): Boolean { + return context?.irBuiltIns?.enumClass?.let { enumClass -> + overriddenSymbols + .asSequence() + .map { it.owner } + .filterIsInstance() + .mapNotNull { it.parentClassOrNull } + .map { it.symbol } + .any { it == enumClass } + } == true +} + +fun IrOverridableDeclaration<*>.isOverriddenExported(context: JsIrBackendContext?): Boolean = overriddenSymbols - .any { shouldDeclarationBeExported(it.owner, context) } + .any { shouldDeclarationBeExported(it.owner as IrDeclarationWithName, context) } fun IrDeclaration.isExported(context: JsIrBackendContext?): Boolean { val candidate = getExportCandidate(this) ?: return false diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt index c518aa378a9..b0f080c9654 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.backend.js.export.isEnumFakeOverriddenDeclaration import org.jetbrains.kotlin.ir.backend.js.export.isExported import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported import org.jetbrains.kotlin.ir.backend.js.utils.* @@ -108,7 +109,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo if (!property.visibility.isPublicAPI) continue - if (property.isFakeOverride) + if (property.isFakeOverride && !property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext)) continue fun IrSimpleFunction.propertyAccessorForwarder( @@ -140,15 +141,16 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo // so we need regenerate `defineProperty` with setter. val noOverriddenGetter = property.getter?.overriddenSymbols?.isEmpty() == true - val overriddenExportedGetter = property.getter?.overriddenSymbols?.isNotEmpty() == true && - property.getter?.isOverriddenExported(context.staticContext.backendContext) == true + val overriddenExportedGetter = (property.getter?.overriddenSymbols?.isNotEmpty() == true && + property.getter?.isOverriddenExported(context.staticContext.backendContext) == true) val noOverriddenExportedSetter = property.setter?.isOverriddenExported(context.staticContext.backendContext) == false - val needOverrideBySetter = overriddenExportedGetter && noOverriddenExportedSetter + val needsOverride = (overriddenExportedGetter && noOverriddenExportedSetter) || + property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext) if (irClass.isExported(context.staticContext.backendContext) && - (noOverriddenGetter || needOverrideBySetter) || + (noOverriddenGetter || needsOverride) || property.getter?.overridesExternal() == true || property.getJsName() != null ) { diff --git a/js/js.translator/testData/box/export/exportEnumClass.kt b/js/js.translator/testData/box/export/exportEnumClass.kt index e64a219355d..d66c439819d 100644 --- a/js/js.translator/testData/box/export/exportEnumClass.kt +++ b/js/js.translator/testData/box/export/exportEnumClass.kt @@ -74,5 +74,11 @@ function box() { if (this["export_enum_class"].Foo.values().indexOf(this["export_enum_class"].Foo.A) === -1) return "fail20" if (this["export_enum_class"].Foo.values().indexOf(this["export_enum_class"].Foo.B) === -1) return "fail21" + if (this["export_enum_class"].Foo.A.name !== "A") return "fail22" + if (this["export_enum_class"].Foo.B.name !== "B") return "fail23" + + if (this["export_enum_class"].Foo.A.ordinal !== 0) return "fail24" + if (this["export_enum_class"].Foo.B.ordinal !== 1) return "fail23" + return "OK" } \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/declarations/declarations.d.ts b/js/js.translator/testData/typescript-export/declarations/declarations.d.ts index 0325e6eb5ae..7bd18d20eac 100644 --- a/js/js.translator/testData/typescript-export/declarations/declarations.d.ts +++ b/js/js.translator/testData/typescript-export/declarations/declarations.d.ts @@ -108,6 +108,8 @@ declare namespace JS_TESTS { bay(): string; static values(): Array; static valueOf(value: string): foo.TestEnumClass; + readonly name: string; + readonly ordinal: number; } namespace TestEnumClass { class Nested { diff --git a/js/js.translator/testData/typescript-export/declarations/declarations__main.js b/js/js.translator/testData/typescript-export/declarations/declarations__main.js index 9c978af6d3b..31ac4271d34 100644 --- a/js/js.translator/testData/typescript-export/declarations/declarations__main.js +++ b/js/js.translator/testData/typescript-export/declarations/declarations__main.js @@ -107,6 +107,10 @@ function box() { assert(TestEnumClass.valueOf("B") === TestEnumClass.B); assert(TestEnumClass.values().indexOf(TestEnumClass.A) != -1); assert(TestEnumClass.values().indexOf(TestEnumClass.B) != -1); + assert(TestEnumClass.A.name === "A"); + assert(TestEnumClass.B.name === "B"); + assert(TestEnumClass.A.ordinal === 0); + assert(TestEnumClass.B.ordinal === 1); assert(new TestEnumClass.Nested().prop == "hello2"); return "OK"; } diff --git a/js/js.translator/testData/typescript-export/declarations/declarations__main.ts b/js/js.translator/testData/typescript-export/declarations/declarations__main.ts index abd89cf8616..36fc9ecdb32 100644 --- a/js/js.translator/testData/typescript-export/declarations/declarations__main.ts +++ b/js/js.translator/testData/typescript-export/declarations/declarations__main.ts @@ -126,6 +126,11 @@ function box(): string { assert(TestEnumClass.values().indexOf(TestEnumClass.A) != -1) assert(TestEnumClass.values().indexOf(TestEnumClass.B) != -1) + assert(TestEnumClass.A.name === "A") + assert(TestEnumClass.B.name === "B") + assert(TestEnumClass.A.ordinal === 0) + assert(TestEnumClass.B.ordinal === 1) + assert(new TestEnumClass.Nested().prop == "hello2") return "OK";