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 2c2193496b6..dd1efe4bef0 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 @@ -15,10 +15,7 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.symbols.IrClassSymbol 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.ir.util.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.findSingleFunction @@ -142,6 +139,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC val enumValueOfIntrinsic = getInternalFunction("enumValueOfIntrinsic") val enumValuesIntrinsic = getInternalFunction("enumValuesIntrinsic") + val enumEntriesIntrinsic = getFunctionInEnumPackage("enumEntriesIntrinsic") // Other: @@ -396,6 +394,11 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC return context.symbolTable.descriptorExtension.referenceSimpleFunction(descriptor) } + private fun getFunctionInEnumPackage(name: String) = + context.symbolTable.descriptorExtension.referenceSimpleFunction( + context.getFunctions(kotlinEnumsPackageFqn.child(Name.identifier(name))).single() + ) + private fun getFunctionInKotlinPackage(name: String) = context.symbolTable.descriptorExtension.referenceSimpleFunction( context.getFunctions(kotlinPackageFqn.child(Name.identifier(name))).single() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EnumIntrinsicsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EnumIntrinsicsTransformer.kt index 771d772e5db..42abb64b4cf 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EnumIntrinsicsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/calls/EnumIntrinsicsTransformer.kt @@ -45,12 +45,17 @@ object EnumIntrinsicsUtils { fun transformEnumValuesIntrinsic(call: IrFunctionAccessExpression) = transformEnumTopLevelIntrinsic(call) { it.name == Name.identifier("values") && it.valueParameters.count() == 0 } + + fun transformEnumEntriesIntrinsic(call: IrFunctionAccessExpression) = transformEnumTopLevelIntrinsic(call) { + it.name == Name.special("") + } } class EnumIntrinsicsTransformer(private val context: JsIrBackendContext) : CallsTransformer { override fun transformFunctionAccess(call: IrFunctionAccessExpression, doNotIntrinsify: Boolean) = when (call.symbol) { context.intrinsics.enumValueOfIntrinsic -> EnumIntrinsicsUtils.transformEnumValueOfIntrinsic(call) context.intrinsics.enumValuesIntrinsic -> EnumIntrinsicsUtils.transformEnumValuesIntrinsic(call) + context.intrinsics.enumEntriesIntrinsic -> EnumIntrinsicsUtils.transformEnumEntriesIntrinsic(call) else -> call } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/SaveInlineFunctionsBeforeInlining.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/SaveInlineFunctionsBeforeInlining.kt index a8e9189d743..c06bddb00e7 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/SaveInlineFunctionsBeforeInlining.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/inline/SaveInlineFunctionsBeforeInlining.kt @@ -29,11 +29,14 @@ internal class SaveInlineFunctionsBeforeInlining(context: JsIrBackendContext) : } internal class JsInlineFunctionResolver(context: JsIrBackendContext) : DefaultInlineFunctionResolver(context) { + private val enumEntriesIntrinsic = context.intrinsics.enumEntriesIntrinsic private val inlineFunctionsBeforeInlining = context.mapping.inlineFunctionsBeforeInlining private val inlineFunctionsBeforeInliningSymbols = hashMapOf() override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction { val function = super.getFunctionDeclaration(symbol) + // TODO: After the expect fun enumEntriesIntrinsic become non-inline function, the code will be removed + if (function.symbol == enumEntriesIntrinsic) return function.apply { body = null } val functionBeforeInlining = inlineFunctionsBeforeInlining[function] ?: return function inlineFunctionsBeforeInliningSymbols[functionBeforeInlining] = function.symbol return functionBeforeInlining diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt index 3b8a55992aa..7265512ea4b 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmSymbols.kt @@ -118,6 +118,7 @@ class WasmSymbols( val enumValueOfIntrinsic = getInternalFunction("enumValueOfIntrinsic") val enumValuesIntrinsic = getInternalFunction("enumValuesIntrinsic") + val enumEntriesIntrinsic = getEnumsFunction("enumEntriesIntrinsic") val coroutineEmptyContinuation: IrPropertySymbol = symbolTable.descriptorExtension.referenceProperty( getProperty(FqName.fromSegments(listOf("kotlin", "wasm", "internal", "EmptyContinuation"))) @@ -382,6 +383,8 @@ class WasmSymbols( private fun getInternalFunction(name: String) = getFunction(name, wasmInternalPackage) + private fun getEnumsFunction(name: String) = getFunction(name, enumsInternalPackage) + private fun getIrClass(fqName: FqName): IrClassSymbol = symbolTable.descriptorExtension.referenceClass(getClass(fqName)) private fun getInternalClass(name: String): IrClassSymbol = getIrClass(FqName("kotlin.wasm.internal.$name")) fun getKFunctionType(type: IrType, list: List): IrType { diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt index 6f2a6651950..25bd2b36114 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt @@ -182,6 +182,8 @@ class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass { return EnumIntrinsicsUtils.transformEnumValueOfIntrinsic(call) symbols.enumValuesIntrinsic -> return EnumIntrinsicsUtils.transformEnumValuesIntrinsic(call) + symbols.enumEntriesIntrinsic -> + return EnumIntrinsicsUtils.transformEnumEntriesIntrinsic(call) } return call diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt index 8cc8cec19af..7b1ec82fcc7 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.memoryOptimizedMap val kotlinPackageFqn = FqName.fromSegments(listOf("kotlin")) +val kotlinEnumsPackageFqn = kotlinPackageFqn.child(Name.identifier("enums")) private val kotlinReflectionPackageFqn = kotlinPackageFqn.child(Name.identifier("reflect")) private val kotlinCoroutinesPackageFqn = kotlinPackageFqn.child(Name.identifier("coroutines")) diff --git a/compiler/testData/codegen/box/enum/enumEntriesIntrinsicWithoutFeature.kt b/compiler/testData/codegen/box/enum/enumEntriesIntrinsicWithoutFeature.kt index 5a86683724a..083b2a1f681 100644 --- a/compiler/testData/codegen/box/enum/enumEntriesIntrinsicWithoutFeature.kt +++ b/compiler/testData/codegen/box/enum/enumEntriesIntrinsicWithoutFeature.kt @@ -1,5 +1,5 @@ // !LANGUAGE: -EnumEntries -// IGNORE_BACKEND: JS +// IGNORE_BACKEND: JS_IR, JS_IR_ES6, WASM // WITH_STDLIB @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") diff --git a/js/js.translator/testData/box/enum/standardFunctions.kt b/js/js.translator/testData/box/enum/standardFunctions.kt index e11d0bbfd2a..0f91a318d2c 100644 --- a/js/js.translator/testData/box/enum/standardFunctions.kt +++ b/js/js.translator/testData/box/enum/standardFunctions.kt @@ -1,7 +1,15 @@ +// !LANGUAGE: +EnumEntries +// IGNORE_BACKEND: JS // KJS_WITH_FULL_RUNTIME // EXPECTED_REACHABLE_NODES: 1555 + +// TODO: Remove after enumEntries become public +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") + package foo +import kotlin.enums.enumEntries + enum class EmptyEnum enum class A { @@ -11,9 +19,13 @@ enum class A { c } +@OptIn(ExperimentalStdlibApi::class) fun box(): String { if (enumValues().size != 0) return "enumValues().size != 0" if (enumValues().asList() != listOf(A.a, A.b, A.c)) return "Wrong enumValues(): " + enumValues().toString() + if (enumEntries().size != 0) return "enumEntries().size != 0" + if (enumEntries() != listOf(A.a, A.b, A.c)) return "Wrong enumEntries(): " + enumEntries().toString() + if (enumEntries() != enumEntries()) return "Enum entries create a new EntriesList for each call" if (enumValueOf("b") != A.b) return "enumValueOf('b') != A.b" return "OK" } \ No newline at end of file diff --git a/libraries/stdlib/js-ir-minimal-for-test/src/minimalEnumEntries.kt b/libraries/stdlib/js-ir-minimal-for-test/src/minimalEnumEntries.kt index 0abf41705ee..01877cb106b 100644 --- a/libraries/stdlib/js-ir-minimal-for-test/src/minimalEnumEntries.kt +++ b/libraries/stdlib/js-ir-minimal-for-test/src/minimalEnumEntries.kt @@ -9,6 +9,10 @@ package kotlin.enums @SinceKotlin("1.8") public sealed interface EnumEntries> +@PublishedApi +@ExperimentalStdlibApi +internal external fun > enumEntriesIntrinsic(): EnumEntries + @PublishedApi @ExperimentalStdlibApi @SinceKotlin("1.8") diff --git a/libraries/stdlib/wasm/src/kotlin/enums/EnumEntriesWasm.kt b/libraries/stdlib/wasm/src/kotlin/enums/EnumEntriesWasm.kt index 5b9ed35e62a..63580ed1a3e 100644 --- a/libraries/stdlib/wasm/src/kotlin/enums/EnumEntriesWasm.kt +++ b/libraries/stdlib/wasm/src/kotlin/enums/EnumEntriesWasm.kt @@ -8,10 +8,6 @@ package kotlin.enums @SinceKotlin("1.9") @ExperimentalStdlibApi @PublishedApi -internal actual inline fun > enumEntriesIntrinsic(): EnumEntries { - /* - * Implementation note: this body will be replaced with `throw NotImplementedException()` the moment - * all backends starts intrinsifying this call. - */ - return enumEntries(enumValues()) -} \ No newline at end of file +// TODO: After the expect fun enumEntriesIntrinsic become non-inline function, the suppress and external keyword should be removed +@Suppress("INLINE_EXTERNAL_DECLARATION", "WRONG_JS_INTEROP_TYPE") +internal actual external inline fun > enumEntriesIntrinsic(): EnumEntries \ No newline at end of file