diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsCommonBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsCommonBackendContext.kt index e5aa1a7d741..ab35fdbeffc 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsCommonBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsCommonBackendContext.kt @@ -20,10 +20,7 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.util.SymbolTable -import org.jetbrains.kotlin.ir.util.getPropertyGetter -import org.jetbrains.kotlin.ir.util.getPropertySetter -import org.jetbrains.kotlin.ir.util.isOverridableOrOverrides +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -157,4 +154,4 @@ interface JsCommonInlineClassesUtils : InlineClassesUtils { * An intrinsic for obtaining the underlying value from an instance of an inline class. */ val unboxIntrinsic: IrSimpleFunctionSymbol -} +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt index 2a3695f8db9..976172f5ae2 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction @@ -16,6 +17,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.isLong import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.findDeclaration +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.kotlinPackageFqn import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -321,6 +323,16 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC val jsFunAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("JsFun")) val jsNameAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("JsName")) + val jsExportAnnotationSymbol by lazy { + context.symbolTable.referenceClass(context.getJsInternalClass("JsExport")) + } + + val jsExportIgnoreAnnotationSymbol by lazy { + jsExportAnnotationSymbol.owner + .findDeclaration { it.fqNameWhenAvailable == FqName("kotlin.js.JsExport.Ignore") } + ?.symbol ?: error("can't find kotlin.js.JsExport.Ignore annotation") + } + val jsImplicitExportAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("JsImplicitExport")) // TODO move CharSequence-related stiff to IntrinsifyCallsLowering diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 080db9f0936..ad2f8f53f89 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt @@ -338,6 +338,12 @@ private val enumEntryCreateGetInstancesFunsLoweringPhase = makeDeclarationTransf prerequisite = setOf(enumClassConstructorLoweringPhase) ) +private val enumClassPreventExportOfNonExportedMembersLowering = makeDeclarationTransformerPhase( + ::EnumClassPreventExportOfNonExportedMembersLowering, + name = "EnumClassPreventExportOfNonExportedMembersLowering", + description = "Exclude non-exportable enum members such as `Enum.entries`", +) + private val enumSyntheticFunsLoweringPhase = makeDeclarationTransformerPhase( { EnumSyntheticFunctionsAndPropertiesLowering(it, supportRawFunctionReference = true) }, name = "EnumSyntheticFunctionsAndPropertiesLowering", @@ -345,7 +351,8 @@ private val enumSyntheticFunsLoweringPhase = makeDeclarationTransformerPhase( prerequisite = setOf( enumClassConstructorLoweringPhase, enumClassCreateInitializerLoweringPhase, - enumEntryCreateGetInstancesFunsLoweringPhase + enumEntryCreateGetInstancesFunsLoweringPhase, + enumClassPreventExportOfNonExportedMembersLowering ) ) @@ -865,6 +872,7 @@ val loweringList = listOf( enumEntryInstancesBodyLoweringPhase, enumClassCreateInitializerLoweringPhase, enumEntryCreateGetInstancesFunsLoweringPhase, + enumClassPreventExportOfNonExportedMembersLowering, enumSyntheticFunsLoweringPhase, enumUsageLoweringPhase, externalEnumUsageLoweringPhase, 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 a45c6d1b5c4..af7997c20ab 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 @@ -153,7 +153,8 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac isField = parentClass?.isInterface == true, irGetter = property.getter, irSetter = property.setter, - isOptional = isOptional + isOptional = isOptional, + isStatic = (property.getter ?: property.setter)?.isStaticMethodOfClass == true, ) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt index daae0641d0c..383de9a2de6 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.name.Name object JsIrBuilder { @@ -45,6 +46,36 @@ object JsIrBuilder { } } + fun buildConstructorCall( + target: IrConstructorSymbol, + type: IrType? = null, + typeArguments: List? = null, + constructorTypeArguments: List? = null, + origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT + ): IrConstructorCall { + val owner = target.owner + val parent = owner.parentAsClass + return IrConstructorCallImpl( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + type ?: owner.returnType, + target, + typeArgumentsCount = parent.typeParameters.size, + valueArgumentsCount = owner.valueParameters.size, + constructorTypeArgumentsCount = owner.typeParameters.size, + origin = origin + ).apply { + typeArguments?.let { + assert(typeArguments.size == typeArgumentsCount) + it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) } + } + constructorTypeArguments?.let { + assert(constructorTypeArguments.size == constructorTypeArgumentsCount) + it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) } + } + } + } + fun buildReturn(targetSymbol: IrFunctionSymbol, value: IrExpression, type: IrType) = IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, targetSymbol, value) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt index 63abc98510b..4d641321d5c 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/EnumClassLowering.kt @@ -17,7 +17,9 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.DescriptorVisibilities.PRIVATE import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin +import org.jetbrains.kotlin.ir.backend.js.export.isExported import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.addField @@ -57,6 +59,26 @@ private fun createEntryAccessorName(enumName: String, enumEntry: IrEnumEntry) = private fun IrEnumEntry.getType(irClass: IrClass) = (correspondingClass ?: irClass).defaultType +class EnumClassPreventExportOfNonExportedMembersLowering(val context: JsIrBackendContext) : DeclarationTransformer { + override fun transformFlat(declaration: IrDeclaration): List? { + if (declaration !is IrSimpleFunction || declaration.parentEnumClassOrNull?.isExported(context) != true) return null + + val syntheticGetterBody = declaration.body as? IrSyntheticBody ?: return null + + if (syntheticGetterBody.kind == IrSyntheticBodyKind.ENUM_ENTRIES) { + declaration.correspondingPropertySymbol?.owner?.let { + it.annotations += generateJsExportIgnoreCall() + } + } + + return null + } + + private fun generateJsExportIgnoreCall(): IrConstructorCall { + return JsIrBuilder.buildConstructorCall(context.intrinsics.jsExportIgnoreAnnotationSymbol.owner.primaryConstructor!!.symbol) + } +} + // Should be applied recursively class EnumClassConstructorLowering(val context: JsCommonBackendContext) : DeclarationTransformer { @@ -470,7 +492,6 @@ class EnumSyntheticFunctionsAndPropertiesLowering( ) : DeclarationTransformer { private val IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun private val IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun - private val IrClass.enumArrayType get() = context.irBuiltIns.arrayClass.typeWith(defaultType) override fun transformFlat(declaration: IrDeclaration): List? { if (declaration is IrConstructor && declaration.isPrimary && declaration.parentEnumClassOrNull != null && diff --git a/js/js.translator/testData/box/esModules/export/exportEnumClass.kt b/js/js.translator/testData/box/esModules/export/exportEnumClass.kt index ede64461b34..2c62d743353 100644 --- a/js/js.translator/testData/box/esModules/export/exportEnumClass.kt +++ b/js/js.translator/testData/box/esModules/export/exportEnumClass.kt @@ -1,3 +1,4 @@ +// !LANGUAGE: +EnumEntries // DONT_TARGET_EXACT_BACKEND: JS // ES_MODULES @@ -99,5 +100,7 @@ export function box() { if (OuterClass.NestedEnum.A.ordinal !== 0) return "fail29" if (OuterClass.NestedEnum.B.ordinal !== 1) return "fail30" + if (Foo.entries !== undefined) return "fail31" + return "OK" } \ No newline at end of file diff --git a/js/js.translator/testData/box/esModules/export/exportFileWithEnumClass.kt b/js/js.translator/testData/box/esModules/export/exportFileWithEnumClass.kt index 4995b85dbbc..881ca8d5e24 100644 --- a/js/js.translator/testData/box/esModules/export/exportFileWithEnumClass.kt +++ b/js/js.translator/testData/box/esModules/export/exportFileWithEnumClass.kt @@ -1,3 +1,4 @@ +// !LANGUAGE: +EnumEntries // DONT_TARGET_EXACT_BACKEND: JS // ES_MODULES @@ -96,5 +97,7 @@ export function box() { if (OuterClass.NestedEnum.A.ordinal !== 0) return "fail29" if (OuterClass.NestedEnum.B.ordinal !== 1) return "fail30" + if (Foo.entries !== undefined) return "fail31" + return "OK" } \ No newline at end of file diff --git a/js/js.translator/testData/box/export/exportEnumClass.kt b/js/js.translator/testData/box/export/exportEnumClass.kt index 593c06b6b4b..2505b540783 100644 --- a/js/js.translator/testData/box/export/exportEnumClass.kt +++ b/js/js.translator/testData/box/export/exportEnumClass.kt @@ -1,3 +1,4 @@ +// !LANGUAGE: +EnumEntries // IGNORE_BACKEND: JS // RUN_PLAIN_BOX_FUNCTION // INFER_MAIN_MODULE @@ -96,5 +97,7 @@ function box() { if (this["export_enum_class"].OuterClass.NestedEnum.A.ordinal !== 0) return "fail29" if (this["export_enum_class"].OuterClass.NestedEnum.B.ordinal !== 1) return "fail30" + if (this["export_enum_class"].Foo.entries !== undefined) return "fail31" + return "OK" } \ No newline at end of file diff --git a/js/js.translator/testData/box/export/exportFileWithEnumClass.kt b/js/js.translator/testData/box/export/exportFileWithEnumClass.kt index f880db453e3..c25d9a58b4e 100644 --- a/js/js.translator/testData/box/export/exportFileWithEnumClass.kt +++ b/js/js.translator/testData/box/export/exportFileWithEnumClass.kt @@ -1,3 +1,4 @@ +// !LANGUAGE: +EnumEntries // IGNORE_BACKEND: JS // RUN_PLAIN_BOX_FUNCTION // INFER_MAIN_MODULE @@ -94,5 +95,7 @@ function box() { if (this["export_enum_class"].OuterClass.NestedEnum.A.ordinal !== 0) return "fail29" if (this["export_enum_class"].OuterClass.NestedEnum.B.ordinal !== 1) return "fail30" + if (this["export_enum_class"].Foo.entries !== undefined) return "fail31" + return "OK" } \ No newline at end of file