[K/JS, K/Wasm] Implement enumEntries top-level function ^KT-59712 Fixed
This commit is contained in:
@@ -15,10 +15,7 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.isLong
|
import org.jetbrains.kotlin.ir.types.isLong
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
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.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||||
@@ -142,6 +139,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
|
|
||||||
val enumValueOfIntrinsic = getInternalFunction("enumValueOfIntrinsic")
|
val enumValueOfIntrinsic = getInternalFunction("enumValueOfIntrinsic")
|
||||||
val enumValuesIntrinsic = getInternalFunction("enumValuesIntrinsic")
|
val enumValuesIntrinsic = getInternalFunction("enumValuesIntrinsic")
|
||||||
|
val enumEntriesIntrinsic = getFunctionInEnumPackage("enumEntriesIntrinsic")
|
||||||
|
|
||||||
|
|
||||||
// Other:
|
// Other:
|
||||||
@@ -396,6 +394,11 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
return context.symbolTable.descriptorExtension.referenceSimpleFunction(descriptor)
|
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) =
|
private fun getFunctionInKotlinPackage(name: String) =
|
||||||
context.symbolTable.descriptorExtension.referenceSimpleFunction(
|
context.symbolTable.descriptorExtension.referenceSimpleFunction(
|
||||||
context.getFunctions(kotlinPackageFqn.child(Name.identifier(name))).single()
|
context.getFunctions(kotlinPackageFqn.child(Name.identifier(name))).single()
|
||||||
|
|||||||
+5
@@ -45,12 +45,17 @@ object EnumIntrinsicsUtils {
|
|||||||
fun transformEnumValuesIntrinsic(call: IrFunctionAccessExpression) = transformEnumTopLevelIntrinsic(call) {
|
fun transformEnumValuesIntrinsic(call: IrFunctionAccessExpression) = transformEnumTopLevelIntrinsic(call) {
|
||||||
it.name == Name.identifier("values") && it.valueParameters.count() == 0
|
it.name == Name.identifier("values") && it.valueParameters.count() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun transformEnumEntriesIntrinsic(call: IrFunctionAccessExpression) = transformEnumTopLevelIntrinsic(call) {
|
||||||
|
it.name == Name.special("<get-entries>")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EnumIntrinsicsTransformer(private val context: JsIrBackendContext) : CallsTransformer {
|
class EnumIntrinsicsTransformer(private val context: JsIrBackendContext) : CallsTransformer {
|
||||||
override fun transformFunctionAccess(call: IrFunctionAccessExpression, doNotIntrinsify: Boolean) = when (call.symbol) {
|
override fun transformFunctionAccess(call: IrFunctionAccessExpression, doNotIntrinsify: Boolean) = when (call.symbol) {
|
||||||
context.intrinsics.enumValueOfIntrinsic -> EnumIntrinsicsUtils.transformEnumValueOfIntrinsic(call)
|
context.intrinsics.enumValueOfIntrinsic -> EnumIntrinsicsUtils.transformEnumValueOfIntrinsic(call)
|
||||||
context.intrinsics.enumValuesIntrinsic -> EnumIntrinsicsUtils.transformEnumValuesIntrinsic(call)
|
context.intrinsics.enumValuesIntrinsic -> EnumIntrinsicsUtils.transformEnumValuesIntrinsic(call)
|
||||||
|
context.intrinsics.enumEntriesIntrinsic -> EnumIntrinsicsUtils.transformEnumEntriesIntrinsic(call)
|
||||||
else -> call
|
else -> call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -29,11 +29,14 @@ internal class SaveInlineFunctionsBeforeInlining(context: JsIrBackendContext) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class JsInlineFunctionResolver(context: JsIrBackendContext) : DefaultInlineFunctionResolver(context) {
|
internal class JsInlineFunctionResolver(context: JsIrBackendContext) : DefaultInlineFunctionResolver(context) {
|
||||||
|
private val enumEntriesIntrinsic = context.intrinsics.enumEntriesIntrinsic
|
||||||
private val inlineFunctionsBeforeInlining = context.mapping.inlineFunctionsBeforeInlining
|
private val inlineFunctionsBeforeInlining = context.mapping.inlineFunctionsBeforeInlining
|
||||||
private val inlineFunctionsBeforeInliningSymbols = hashMapOf<IrFunction, IrFunctionSymbol>()
|
private val inlineFunctionsBeforeInliningSymbols = hashMapOf<IrFunction, IrFunctionSymbol>()
|
||||||
|
|
||||||
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
|
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
|
||||||
val function = super.getFunctionDeclaration(symbol)
|
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
|
val functionBeforeInlining = inlineFunctionsBeforeInlining[function] ?: return function
|
||||||
inlineFunctionsBeforeInliningSymbols[functionBeforeInlining] = function.symbol
|
inlineFunctionsBeforeInliningSymbols[functionBeforeInlining] = function.symbol
|
||||||
return functionBeforeInlining
|
return functionBeforeInlining
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ class WasmSymbols(
|
|||||||
|
|
||||||
val enumValueOfIntrinsic = getInternalFunction("enumValueOfIntrinsic")
|
val enumValueOfIntrinsic = getInternalFunction("enumValueOfIntrinsic")
|
||||||
val enumValuesIntrinsic = getInternalFunction("enumValuesIntrinsic")
|
val enumValuesIntrinsic = getInternalFunction("enumValuesIntrinsic")
|
||||||
|
val enumEntriesIntrinsic = getEnumsFunction("enumEntriesIntrinsic")
|
||||||
|
|
||||||
val coroutineEmptyContinuation: IrPropertySymbol = symbolTable.descriptorExtension.referenceProperty(
|
val coroutineEmptyContinuation: IrPropertySymbol = symbolTable.descriptorExtension.referenceProperty(
|
||||||
getProperty(FqName.fromSegments(listOf("kotlin", "wasm", "internal", "EmptyContinuation")))
|
getProperty(FqName.fromSegments(listOf("kotlin", "wasm", "internal", "EmptyContinuation")))
|
||||||
@@ -382,6 +383,8 @@ class WasmSymbols(
|
|||||||
|
|
||||||
private fun getInternalFunction(name: String) = getFunction(name, wasmInternalPackage)
|
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 getIrClass(fqName: FqName): IrClassSymbol = symbolTable.descriptorExtension.referenceClass(getClass(fqName))
|
||||||
private fun getInternalClass(name: String): IrClassSymbol = getIrClass(FqName("kotlin.wasm.internal.$name"))
|
private fun getInternalClass(name: String): IrClassSymbol = getIrClass(FqName("kotlin.wasm.internal.$name"))
|
||||||
fun getKFunctionType(type: IrType, list: List<IrType>): IrType {
|
fun getKFunctionType(type: IrType, list: List<IrType>): IrType {
|
||||||
|
|||||||
+2
@@ -182,6 +182,8 @@ class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass {
|
|||||||
return EnumIntrinsicsUtils.transformEnumValueOfIntrinsic(call)
|
return EnumIntrinsicsUtils.transformEnumValueOfIntrinsic(call)
|
||||||
symbols.enumValuesIntrinsic ->
|
symbols.enumValuesIntrinsic ->
|
||||||
return EnumIntrinsicsUtils.transformEnumValuesIntrinsic(call)
|
return EnumIntrinsicsUtils.transformEnumValuesIntrinsic(call)
|
||||||
|
symbols.enumEntriesIntrinsic ->
|
||||||
|
return EnumIntrinsicsUtils.transformEnumEntriesIntrinsic(call)
|
||||||
}
|
}
|
||||||
|
|
||||||
return call
|
return call
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.utils.DFS
|
|||||||
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
||||||
|
|
||||||
val kotlinPackageFqn = FqName.fromSegments(listOf("kotlin"))
|
val kotlinPackageFqn = FqName.fromSegments(listOf("kotlin"))
|
||||||
|
val kotlinEnumsPackageFqn = kotlinPackageFqn.child(Name.identifier("enums"))
|
||||||
private val kotlinReflectionPackageFqn = kotlinPackageFqn.child(Name.identifier("reflect"))
|
private val kotlinReflectionPackageFqn = kotlinPackageFqn.child(Name.identifier("reflect"))
|
||||||
private val kotlinCoroutinesPackageFqn = kotlinPackageFqn.child(Name.identifier("coroutines"))
|
private val kotlinCoroutinesPackageFqn = kotlinPackageFqn.child(Name.identifier("coroutines"))
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// !LANGUAGE: -EnumEntries
|
// !LANGUAGE: -EnumEntries
|
||||||
// IGNORE_BACKEND: JS
|
// IGNORE_BACKEND: JS_IR, JS_IR_ES6, WASM
|
||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
|
|
||||||
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
|
// !LANGUAGE: +EnumEntries
|
||||||
|
// IGNORE_BACKEND: JS
|
||||||
// KJS_WITH_FULL_RUNTIME
|
// KJS_WITH_FULL_RUNTIME
|
||||||
// EXPECTED_REACHABLE_NODES: 1555
|
// EXPECTED_REACHABLE_NODES: 1555
|
||||||
|
|
||||||
|
// TODO: Remove after enumEntries become public
|
||||||
|
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
|
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
import kotlin.enums.enumEntries
|
||||||
|
|
||||||
enum class EmptyEnum
|
enum class EmptyEnum
|
||||||
|
|
||||||
enum class A {
|
enum class A {
|
||||||
@@ -11,9 +19,13 @@ enum class A {
|
|||||||
c
|
c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
if (enumValues<EmptyEnum>().size != 0) return "enumValues<EmptyEnum>().size != 0"
|
if (enumValues<EmptyEnum>().size != 0) return "enumValues<EmptyEnum>().size != 0"
|
||||||
if (enumValues<A>().asList() != listOf(A.a, A.b, A.c)) return "Wrong enumValues<A>(): " + enumValues<A>().toString()
|
if (enumValues<A>().asList() != listOf(A.a, A.b, A.c)) return "Wrong enumValues<A>(): " + enumValues<A>().toString()
|
||||||
|
if (enumEntries<EmptyEnum>().size != 0) return "enumEntries<EmptyEnum>().size != 0"
|
||||||
|
if (enumEntries<A>() != listOf(A.a, A.b, A.c)) return "Wrong enumEntries<A>(): " + enumEntries<A>().toString()
|
||||||
|
if (enumEntries<A>() != enumEntries<A>()) return "Enum entries create a new EntriesList for each call"
|
||||||
if (enumValueOf<A>("b") != A.b) return "enumValueOf<A>('b') != A.b"
|
if (enumValueOf<A>("b") != A.b) return "enumValueOf<A>('b') != A.b"
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,10 @@ package kotlin.enums
|
|||||||
@SinceKotlin("1.8")
|
@SinceKotlin("1.8")
|
||||||
public sealed interface EnumEntries<E : Enum<E>>
|
public sealed interface EnumEntries<E : Enum<E>>
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
internal external fun <T: Enum<T>> enumEntriesIntrinsic(): EnumEntries<T>
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@SinceKotlin("1.8")
|
@SinceKotlin("1.8")
|
||||||
|
|||||||
@@ -8,10 +8,6 @@ package kotlin.enums
|
|||||||
@SinceKotlin("1.9")
|
@SinceKotlin("1.9")
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal actual inline fun <reified T : Enum<T>> enumEntriesIntrinsic(): EnumEntries<T> {
|
// 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")
|
||||||
* Implementation note: this body will be replaced with `throw NotImplementedException()` the moment
|
internal actual external inline fun <reified T : Enum<T>> enumEntriesIntrinsic(): EnumEntries<T>
|
||||||
* all backends starts intrinsifying this call.
|
|
||||||
*/
|
|
||||||
return enumEntries(enumValues<T>())
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user