[JS IR] Export name and ordinal for enum classes

^KT-37916 fixed
^KT-44494 fixed
This commit is contained in:
Ilya Goncharov
2021-10-28 20:05:49 +03:00
committed by Space
parent a31a6c5117
commit 4fa2fa6c26
6 changed files with 42 additions and 10 deletions
@@ -108,7 +108,7 @@ class ExportModelGenerator(
// TODO: Report a frontend error // TODO: Report a frontend error
if (accessor.extensionReceiverParameter != null) if (accessor.extensionReceiverParameter != null)
return null return null
if (accessor.isFakeOverride) { if (accessor.isFakeOverride && !accessor.isEnumFakeOverriddenDeclaration(context)) {
return null return null
} }
} }
@@ -446,14 +446,15 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont
if (context?.additionalExportedDeclarations?.contains(declaration) == true) if (context?.additionalExportedDeclarations?.contains(declaration) == true)
return true return true
if (declaration is IrSimpleFunction) { if (declaration is IrOverridableDeclaration<*>) {
val overriddenNonEmpty = declaration val overriddenNonEmpty = declaration
.overriddenSymbols .overriddenSymbols
.isNotEmpty() .isNotEmpty()
if (overriddenNonEmpty) { if (overriddenNonEmpty) {
return declaration.isOverriddenExported(context) || 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<IrDeclaration>()
.mapNotNull { it.parentClassOrNull }
.map { it.symbol }
.any { it == enumClass }
} == true
}
fun IrOverridableDeclaration<*>.isOverriddenExported(context: JsIrBackendContext?): Boolean =
overriddenSymbols overriddenSymbols
.any { shouldDeclarationBeExported(it.owner, context) } .any { shouldDeclarationBeExported(it.owner as IrDeclarationWithName, context) }
fun IrDeclaration.isExported(context: JsIrBackendContext?): Boolean { fun IrDeclaration.isExported(context: JsIrBackendContext?): Boolean {
val candidate = getExportCandidate(this) ?: return false val candidate = getExportCandidate(this) ?: return false
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality 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.isExported
import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported
import org.jetbrains.kotlin.ir.backend.js.utils.* 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) if (!property.visibility.isPublicAPI)
continue continue
if (property.isFakeOverride) if (property.isFakeOverride && !property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext))
continue continue
fun IrSimpleFunction.propertyAccessorForwarder( fun IrSimpleFunction.propertyAccessorForwarder(
@@ -140,15 +141,16 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
// so we need regenerate `defineProperty` with setter. // so we need regenerate `defineProperty` with setter.
val noOverriddenGetter = property.getter?.overriddenSymbols?.isEmpty() == true val noOverriddenGetter = property.getter?.overriddenSymbols?.isEmpty() == true
val overriddenExportedGetter = property.getter?.overriddenSymbols?.isNotEmpty() == true && val overriddenExportedGetter = (property.getter?.overriddenSymbols?.isNotEmpty() == true &&
property.getter?.isOverriddenExported(context.staticContext.backendContext) == true property.getter?.isOverriddenExported(context.staticContext.backendContext) == true)
val noOverriddenExportedSetter = property.setter?.isOverriddenExported(context.staticContext.backendContext) == false 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) && if (irClass.isExported(context.staticContext.backendContext) &&
(noOverriddenGetter || needOverrideBySetter) || (noOverriddenGetter || needsOverride) ||
property.getter?.overridesExternal() == true || property.getter?.overridesExternal() == true ||
property.getJsName() != null property.getJsName() != null
) { ) {
@@ -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.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.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" return "OK"
} }
@@ -108,6 +108,8 @@ declare namespace JS_TESTS {
bay(): string; bay(): string;
static values(): Array<foo.TestEnumClass>; static values(): Array<foo.TestEnumClass>;
static valueOf(value: string): foo.TestEnumClass; static valueOf(value: string): foo.TestEnumClass;
readonly name: string;
readonly ordinal: number;
} }
namespace TestEnumClass { namespace TestEnumClass {
class Nested { class Nested {
@@ -107,6 +107,10 @@ function box() {
assert(TestEnumClass.valueOf("B") === TestEnumClass.B); assert(TestEnumClass.valueOf("B") === TestEnumClass.B);
assert(TestEnumClass.values().indexOf(TestEnumClass.A) != -1); assert(TestEnumClass.values().indexOf(TestEnumClass.A) != -1);
assert(TestEnumClass.values().indexOf(TestEnumClass.B) != -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"); assert(new TestEnumClass.Nested().prop == "hello2");
return "OK"; return "OK";
} }
@@ -126,6 +126,11 @@ function box(): string {
assert(TestEnumClass.values().indexOf(TestEnumClass.A) != -1) assert(TestEnumClass.values().indexOf(TestEnumClass.A) != -1)
assert(TestEnumClass.values().indexOf(TestEnumClass.B) != -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") assert(new TestEnumClass.Nested().prop == "hello2")
return "OK"; return "OK";