[K/JS] Support KClass<*>.createInstance reflection method ^KT-58684 Fixed
This commit is contained in:
@@ -30,6 +30,9 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
// TODO: Should we drop operator intrinsics in favor of IrDynamicOperatorExpression?
|
||||
|
||||
// Modes
|
||||
val jsIsEs6 = getInternalFunction("jsIsEs6")
|
||||
|
||||
// Global variables
|
||||
val void = getInternalProperty("VOID")
|
||||
val globalThis = getInternalProperty("globalThis")
|
||||
|
||||
@@ -140,6 +140,12 @@ private val validateIrAfterLowering = makeCustomJsModulePhase(
|
||||
description = "Validate IR after lowering"
|
||||
).toModuleLowering()
|
||||
|
||||
private val collectClassDefaultConstructorsPhase = makeDeclarationTransformerPhase(
|
||||
::CollectClassDefaultConstructorsLowering,
|
||||
name = "CollectClassDefaultConstructorsLowering",
|
||||
description = "Collect classes default constructors to add it to metadata on code generating phase"
|
||||
)
|
||||
|
||||
private val preventExportOfSyntheticDeclarationsLowering = makeDeclarationTransformerPhase(
|
||||
::ExcludeSyntheticDeclarationsFromExportLowering,
|
||||
name = "ExcludeSyntheticDeclarationsFromExportLowering",
|
||||
@@ -898,6 +904,7 @@ val loweringList = listOf<Lowering>(
|
||||
initializersLoweringPhase,
|
||||
initializersCleanupLoweringPhase,
|
||||
kotlinNothingValueExceptionPhase,
|
||||
collectClassDefaultConstructorsPhase,
|
||||
// Common prefix ends
|
||||
enumWhenPhase,
|
||||
enumEntryInstancesLoweringPhase,
|
||||
|
||||
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import java.util.WeakHashMap
|
||||
|
||||
class JsMapping : DefaultMapping() {
|
||||
val classToItsDefaultConstructor = WeakHashMap<IrClass, IrConstructor>()
|
||||
|
||||
val esClassWhichNeedBoxParameters = DefaultDelegateFactory.newDeclarationToValueMapping<IrClass, Boolean>()
|
||||
val esClassToPossibilityForOptimization = DefaultDelegateFactory.newDeclarationToValueMapping<IrClass, MutableReference<Boolean>>()
|
||||
|
||||
|
||||
+14
-3
@@ -70,10 +70,14 @@ internal class JsUsefulDeclarationProcessor(
|
||||
referencedJsClassesFromExpressions += ref.owner
|
||||
}
|
||||
|
||||
context.reflectionSymbols.getKClass -> {
|
||||
addConstructedClass(expression.getTypeArgument(0)!!.classifierOrFail.owner as IrClass)
|
||||
}
|
||||
|
||||
context.intrinsics.jsObjectCreateSymbol -> {
|
||||
val classToCreate = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
|
||||
classToCreate.enqueue(data, "intrinsic: jsObjectCreateSymbol")
|
||||
constructedClasses += classToCreate
|
||||
addConstructedClass(classToCreate)
|
||||
}
|
||||
|
||||
context.intrinsics.jsCreateThisSymbol -> {
|
||||
@@ -88,7 +92,7 @@ internal class JsUsefulDeclarationProcessor(
|
||||
val classToCreate = classTypeToCreate.classifierOrFail.owner as IrClass
|
||||
|
||||
classToCreate.enqueue(data, "intrinsic: jsCreateThis")
|
||||
constructedClasses += classToCreate
|
||||
addConstructedClass(classToCreate)
|
||||
}
|
||||
|
||||
context.intrinsics.jsEquals -> {
|
||||
@@ -117,7 +121,14 @@ internal class JsUsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun addConstructedClass(irClass: IrClass) {
|
||||
super.addConstructedClass(irClass)
|
||||
|
||||
if (irClass.isClass) {
|
||||
context.findDefaultConstructorFor(irClass)?.enqueue(irClass, "intrinsic: KClass<*>.createInstance")
|
||||
}
|
||||
}
|
||||
|
||||
override fun processSuperTypes(irClass: IrClass) {
|
||||
@@ -178,7 +189,7 @@ internal class JsUsefulDeclarationProcessor(
|
||||
super.processSimpleFunction(irFunction)
|
||||
|
||||
if (irFunction.isEs6ConstructorReplacement) {
|
||||
constructedClasses += irFunction.dispatchReceiverParameter?.type?.classOrNull?.owner!!
|
||||
addConstructedClass(irFunction.dispatchReceiverParameter?.type?.classOrNull?.owner!!)
|
||||
}
|
||||
|
||||
if (irFunction.isReal && irFunction.body != null) {
|
||||
|
||||
+5
-1
@@ -139,6 +139,10 @@ abstract class UsefulDeclarationProcessor(
|
||||
|
||||
val usefulPolyfilledDeclarations = hashSetOf<IrDeclaration>()
|
||||
|
||||
protected open fun addConstructedClass(irClass: IrClass) {
|
||||
constructedClasses += irClass
|
||||
}
|
||||
|
||||
protected open fun processField(irField: IrField): Unit = Unit
|
||||
|
||||
protected open fun processClass(irClass: IrClass) {
|
||||
@@ -176,7 +180,7 @@ abstract class UsefulDeclarationProcessor(
|
||||
// Collect instantiated classes.
|
||||
irConstructor.constructedClass.let {
|
||||
it.enqueue(irConstructor, "constructed class")
|
||||
constructedClasses += it
|
||||
addConstructedClass(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -60,6 +60,12 @@ class UselessDeclarationsRemover(
|
||||
.flatMap { it.classOrNull?.collectUsedSuperTypes() ?: emptyList() }
|
||||
.distinct()
|
||||
.memoryOptimizedMap { it.defaultType }
|
||||
|
||||
// Remove default constructor if the class was never constructed
|
||||
val defaultConstructor = context.findDefaultConstructorFor(declaration)
|
||||
if (defaultConstructor != null && defaultConstructor !in usefulDeclarations) {
|
||||
context.mapping.classToItsDefaultConstructor.remove(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClassSymbol.collectUsedSuperTypes(): Set<IrClassSymbol> {
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.isClass
|
||||
|
||||
class CollectClassDefaultConstructorsLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrClass && declaration.couldContainDefaultConstructor()) {
|
||||
context.mapping.classToItsDefaultConstructor[declaration] = declaration.defaultConstructor ?: return null
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun IrClass.couldContainDefaultConstructor(): Boolean {
|
||||
return isClass && !isValue && !isExpect && modality != Modality.ABSTRACT && modality != Modality.SEALED
|
||||
}
|
||||
|
||||
private val IrClass.defaultConstructor: IrConstructor?
|
||||
get() = constructors.singleOrNull { it.visibility == DescriptorVisibilities.PUBLIC && it.isDefaultConstructor() }
|
||||
|
||||
private fun IrFunction.isDefaultConstructor(): Boolean {
|
||||
return valueParameters.isEmpty() || valueParameters.all { it.defaultValue != null }
|
||||
}
|
||||
}
|
||||
+5
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.utils.newHashMapWithExpectedSize
|
||||
|
||||
object ES6_INIT_CALL : IrStatementOriginImpl("ES6_INIT_CALL")
|
||||
object ES6_CONSTRUCTOR_REPLACEMENT : IrDeclarationOriginImpl("ES6_CONSTRUCTOR_REPLACEMENT")
|
||||
object ES6_SYNTHETIC_EXPORT_CONSTRUCTOR: IrDeclarationOriginImpl("ES6_SYNTHETIC_EXPORT_CONSTRUCTOR")
|
||||
object ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT : IrDeclarationOriginImpl("ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT")
|
||||
object ES6_INIT_FUNCTION : IrDeclarationOriginImpl("ES6_INIT_FUNCTION")
|
||||
object ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT : IrStatementOriginImpl("ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT")
|
||||
@@ -50,6 +51,9 @@ val IrDeclaration.isInitFunction: Boolean
|
||||
val IrFunctionAccessExpression.isInitCall: Boolean
|
||||
get() = origin == ES6_INIT_CALL
|
||||
|
||||
val IrDeclaration.isSyntheticConstructorForExport: Boolean
|
||||
get() = origin == ES6_SYNTHETIC_EXPORT_CONSTRUCTOR
|
||||
|
||||
class ES6ConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
private var IrConstructor.constructorFactory by context.mapping.secondaryConstructorToFactory
|
||||
|
||||
@@ -77,6 +81,7 @@ class ES6ConstructorLowering(val context: JsIrBackendContext) : DeclarationTrans
|
||||
statements.add(JsIrBuilder.buildReturn(symbol, selfReplacedConstructorCall, returnType))
|
||||
}
|
||||
}
|
||||
origin = ES6_SYNTHETIC_EXPORT_CONSTRUCTOR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-5
@@ -12,10 +12,7 @@ import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.MutableReference
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.irEmpty
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.mutableReferenceOf
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -35,12 +32,19 @@ class ES6PrimaryConstructorOptimizationLowering(private val context: JsIrBackend
|
||||
}
|
||||
|
||||
val irClass = declaration.parentAsClass
|
||||
val defaultConstructor = context.findDefaultConstructorFor(irClass)
|
||||
|
||||
if (irClass.isExported(context)) {
|
||||
irClass.removeConstructorForExport()
|
||||
}
|
||||
|
||||
return listOf(declaration.convertToRegularConstructor(irClass))
|
||||
val constructorReplacement = declaration.convertToRegularConstructor(irClass)
|
||||
|
||||
if (declaration == defaultConstructor) {
|
||||
context.mapping.classToItsDefaultConstructor[irClass] = constructorReplacement
|
||||
}
|
||||
|
||||
return listOf(constructorReplacement)
|
||||
}
|
||||
|
||||
private fun IrFunction.convertToRegularConstructor(irClass: IrClass): IrConstructor {
|
||||
|
||||
+42
-20
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isAllowedFakeOverriddenDeclaration
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported
|
||||
@@ -24,12 +25,15 @@ import org.jetbrains.kotlin.js.backend.ast.JsVars.JsVar
|
||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.butIf
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
||||
import org.jetbrains.kotlin.utils.toSmartList
|
||||
|
||||
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||
private val backendContext = context.staticContext.backendContext
|
||||
|
||||
private val perFile = context.staticContext.isPerFile
|
||||
private val es6mode = context.staticContext.backendContext.es6mode
|
||||
private val es6mode = backendContext.es6mode
|
||||
|
||||
private val className = context.getNameForClass(irClass)
|
||||
private val baseClass: IrType? = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
|
||||
@@ -151,7 +155,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
if (
|
||||
property.isFakeOverride &&
|
||||
!property.isAllowedFakeOverriddenDeclaration(context.staticContext.backendContext)
|
||||
!property.isAllowedFakeOverriddenDeclaration(backendContext)
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -170,8 +174,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
val overriddenSymbols = property.getter?.overriddenSymbols.orEmpty()
|
||||
|
||||
val backendContext = context.staticContext.backendContext
|
||||
|
||||
// Don't generate `defineProperty` if the property overrides a property from an exported class,
|
||||
// because we've already generated `defineProperty` for the base class property.
|
||||
// In other words, we only want to generate `defineProperty` once for each property.
|
||||
@@ -184,14 +186,14 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
val getterOverridesExternal = property.getter?.overridesExternal() == true
|
||||
val overriddenExportedGetter = !property.getter?.overriddenSymbols.isNullOrEmpty() &&
|
||||
property.getter?.isOverriddenExported(context.staticContext.backendContext) == true
|
||||
property.getter?.isOverriddenExported(backendContext) == true
|
||||
|
||||
val noOverriddenExportedSetter = property.setter?.isOverriddenExported(context.staticContext.backendContext) == false
|
||||
val noOverriddenExportedSetter = property.setter?.isOverriddenExported(backendContext) == false
|
||||
|
||||
val needsOverride = (overriddenExportedGetter && noOverriddenExportedSetter) ||
|
||||
property.isAllowedFakeOverriddenDeclaration(context.staticContext.backendContext)
|
||||
property.isAllowedFakeOverriddenDeclaration(backendContext)
|
||||
|
||||
if (irClass.isExported(context.staticContext.backendContext) &&
|
||||
if (irClass.isExported(backendContext) &&
|
||||
(overriddenSymbols.isEmpty() || needsOverride) ||
|
||||
hasOverriddenExportedInterfaceProperties ||
|
||||
getterOverridesExternal ||
|
||||
@@ -213,7 +215,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
// });
|
||||
|
||||
val getterForwarder = property.getter
|
||||
.takeIf { it.shouldExportAccessor(context.staticContext.backendContext) }
|
||||
.takeIf { it.shouldExportAccessor(backendContext) }
|
||||
.getOrGenerateIfFinalOrEs6Mode {
|
||||
propertyAccessorForwarder("getter forwarder") {
|
||||
JsReturn(JsInvocation(it))
|
||||
@@ -221,7 +223,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
|
||||
val setterForwarder = property.setter
|
||||
.takeIf { it.shouldExportAccessor(context.staticContext.backendContext) }
|
||||
.takeIf { it.shouldExportAccessor(backendContext) }
|
||||
.getOrGenerateIfFinalOrEs6Mode {
|
||||
val setterArgName = JsName("value", false)
|
||||
propertyAccessorForwarder("setter forwarder") {
|
||||
@@ -266,7 +268,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
private fun IrSimpleFunction.isDefinedInsideExportedInterface(): Boolean {
|
||||
if (isJsExportIgnore() || correspondingPropertySymbol?.owner?.isJsExportIgnore() == true) return false
|
||||
return (!isFakeOverride && parentClassOrNull.isExportedInterface(context.staticContext.backendContext)) ||
|
||||
return (!isFakeOverride && parentClassOrNull.isExportedInterface(backendContext)) ||
|
||||
overriddenSymbols.any { it.owner.isDefinedInsideExportedInterface() }
|
||||
}
|
||||
|
||||
@@ -281,7 +283,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
private fun IrSimpleFunction.generateAssignmentIfMangled(memberName: JsName) {
|
||||
if (
|
||||
irClass.isExported(context.staticContext.backendContext) &&
|
||||
irClass.isExported(backendContext) &&
|
||||
visibility.isPublicAPI && hasMangledName() &&
|
||||
correspondingPropertySymbol == null
|
||||
) {
|
||||
@@ -370,24 +372,33 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
|
||||
private fun generateSetMetadataCall(): JsStatement {
|
||||
val setMetadataFor = context.staticContext.backendContext.intrinsics.setMetadataForSymbol.owner
|
||||
val setMetadataFor = backendContext.intrinsics.setMetadataForSymbol.owner
|
||||
|
||||
val ctor = classNameRef
|
||||
val parent = baseClassRef?.takeIf { !es6mode }
|
||||
val name = generateSimpleName()
|
||||
val interfaces = generateInterfacesList()
|
||||
val metadataConstructor = getMetadataConstructor()
|
||||
val defaultConstructor = runIf(irClass.isClass, ::findDefaultConstructor)
|
||||
val associatedObjectKey = generateAssociatedObjectKey()
|
||||
val associatedObjects = generateAssociatedObjects()
|
||||
val suspendArity = generateSuspendArity()
|
||||
|
||||
val undefined = context.staticContext.backendContext.getVoid().accept(IrElementToJsExpressionTransformer(), context)
|
||||
|
||||
return JsInvocation(
|
||||
JsNameRef(context.getNameForStaticFunction(setMetadataFor)),
|
||||
listOf(ctor, name, metadataConstructor, parent, interfaces, associatedObjectKey, associatedObjects, suspendArity)
|
||||
listOf(
|
||||
ctor,
|
||||
name,
|
||||
metadataConstructor,
|
||||
parent,
|
||||
interfaces,
|
||||
defaultConstructor,
|
||||
associatedObjectKey,
|
||||
associatedObjects,
|
||||
suspendArity
|
||||
)
|
||||
.dropLastWhile { it == null }
|
||||
.memoryOptimizedMap { it ?: undefined }
|
||||
.memoryOptimizedMap { it ?: jsUndefined }
|
||||
).makeStmt()
|
||||
|
||||
}
|
||||
@@ -408,7 +419,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
|
||||
private fun getMetadataConstructor(): JsNameRef {
|
||||
val metadataConstructorSymbol = with(context.staticContext.backendContext.intrinsics) {
|
||||
val metadataConstructorSymbol = with(backendContext.intrinsics) {
|
||||
when {
|
||||
irClass.isInterface -> metadataInterfaceConstructorSymbol
|
||||
irClass.isObject -> metadataObjectConstructorSymbol
|
||||
@@ -428,8 +439,19 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
return JsArrayLiteral(listRef.toSmartList())
|
||||
}
|
||||
|
||||
private fun findDefaultConstructor(): JsNameRef? {
|
||||
return when (val defaultConstructor = backendContext.findDefaultConstructorFor(irClass)) {
|
||||
is IrConstructor -> context.getNameForConstructor(defaultConstructor).makeRef()
|
||||
is IrSimpleFunction -> when {
|
||||
es6mode -> JsNameRef(context.getNameForMemberFunction(defaultConstructor), classNameRef)
|
||||
else -> context.getNameForStaticFunction(defaultConstructor).makeRef()
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateSuspendArity(): JsArrayLiteral? {
|
||||
val invokeFunctions = context.staticContext.backendContext.mapping.suspendArityStore[irClass] ?: return null
|
||||
val invokeFunctions = backendContext.mapping.suspendArityStore[irClass] ?: return null
|
||||
val arity = invokeFunctions
|
||||
.map { it.valueParameters.size }
|
||||
.distinct()
|
||||
@@ -447,7 +469,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
val annotationClass = annotation.symbol.owner.constructedClass
|
||||
context.getAssociatedObjectKey(annotationClass)?.let { key ->
|
||||
annotation.associatedObject()?.let { obj ->
|
||||
context.staticContext.backendContext.mapping.objectToGetInstanceFunction[obj]?.let { factory ->
|
||||
backendContext.mapping.objectToGetInstanceFunction[obj]?.let { factory ->
|
||||
JsPropertyInitializer(JsIntLiteral(key), context.staticContext.getNameForStaticFunction(factory).makeRef())
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -86,6 +86,8 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
|
||||
prefixOp(intrinsics.jsTypeOf, JsUnaryOperator.TYPEOF)
|
||||
|
||||
add(intrinsics.jsIsEs6) { _, _ -> JsBooleanLiteral(backendContext.es6mode) }
|
||||
|
||||
add(intrinsics.jsObjectCreateSymbol) { call, context ->
|
||||
val classToCreate = call.getTypeArgument(0)!!.classifierOrFail.owner as IrClass
|
||||
val className = classToCreate.getClassRef(context.staticContext)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.parents
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.isClass
|
||||
import org.jetbrains.kotlin.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
@@ -14,6 +15,10 @@ import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBoxParameter
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isSyntheticConstructorForExport
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isSyntheticPrimaryConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
@@ -25,13 +30,10 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.isEnumClass
|
||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.utils.filterIsInstanceAnd
|
||||
|
||||
fun IrClass.jsConstructorReference(context: JsIrBackendContext): IrExpression {
|
||||
return JsIrBuilder.buildCall(context.intrinsics.jsClass, origin = JsStatementOrigins.CLASS_REFERENCE)
|
||||
@@ -127,3 +129,9 @@ fun IrDeclaration.isObjectInstanceField(): Boolean {
|
||||
fun IrField.isObjectInstanceField(): Boolean {
|
||||
return origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE
|
||||
}
|
||||
|
||||
fun JsIrBackendContext.findDefaultConstructorFor(irClass: IrClass): IrFunction? {
|
||||
return mapping.classToItsDefaultConstructor[irClass]?.let {
|
||||
mapping.secondaryConstructorToFactory[it] ?: it
|
||||
}
|
||||
}
|
||||
+12
@@ -9914,6 +9914,18 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
|
||||
runTest("js/js.translator/testData/box/reflection/classJsName.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("createInstance.kt")
|
||||
public void testCreateInstance() throws Exception {
|
||||
runTest("js/js.translator/testData/box/reflection/createInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("createInstanceByInstance.kt")
|
||||
public void testCreateInstanceByInstance() throws Exception {
|
||||
runTest("js/js.translator/testData/box/reflection/createInstanceByInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("external.kt")
|
||||
public void testExternal() throws Exception {
|
||||
|
||||
+12
@@ -10020,6 +10020,18 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
||||
runTest("js/js.translator/testData/box/reflection/classJsName.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("createInstance.kt")
|
||||
public void testCreateInstance() throws Exception {
|
||||
runTest("js/js.translator/testData/box/reflection/createInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("createInstanceByInstance.kt")
|
||||
public void testCreateInstanceByInstance() throws Exception {
|
||||
runTest("js/js.translator/testData/box/reflection/createInstanceByInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("external.kt")
|
||||
public void testExternal() throws Exception {
|
||||
|
||||
+12
@@ -9914,6 +9914,18 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/reflection/classJsName.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("createInstance.kt")
|
||||
public void testCreateInstance() throws Exception {
|
||||
runTest("js/js.translator/testData/box/reflection/createInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("createInstanceByInstance.kt")
|
||||
public void testCreateInstanceByInstance() throws Exception {
|
||||
runTest("js/js.translator/testData/box/reflection/createInstanceByInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("external.kt")
|
||||
public void testExternal() throws Exception {
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// IGNORE_BACKEND: JS
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import kotlin.reflect.createInstance
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
// Good classes
|
||||
|
||||
class Simple
|
||||
class PrimaryWithDefaults(val d1: String = "d1", val d2: Int = 2)
|
||||
class Secondary(val s: String) {
|
||||
constructor() : this("s")
|
||||
}
|
||||
class SecondaryWithDefaults(val s: String) {
|
||||
constructor(x: Int = 0) : this(x.toString())
|
||||
}
|
||||
class SecondaryWithDefaultsNoPrimary {
|
||||
constructor(x: Int) {}
|
||||
constructor(s: String = "") {}
|
||||
}
|
||||
|
||||
// Bad classes
|
||||
|
||||
class NoNoArgConstructor(val s: String) {
|
||||
constructor(x: Int) : this(x.toString())
|
||||
}
|
||||
class NoArgAndDefault() {
|
||||
constructor(x: Int = 0) : this()
|
||||
}
|
||||
class DefaultPrimaryAndDefaultSecondary(val s: String = "") {
|
||||
constructor(x: Int = 0) : this(x.toString())
|
||||
}
|
||||
class SeveralDefaultSecondaries {
|
||||
constructor(x: Int = 0) {}
|
||||
constructor(s: String = "") {}
|
||||
constructor(d: Double = 3.14) {}
|
||||
}
|
||||
class PrivateConstructor private constructor()
|
||||
object Object
|
||||
interface Interface
|
||||
enum class EnumFoo { A, B }
|
||||
|
||||
abstract class AbstractClass
|
||||
|
||||
sealed class SealedClass
|
||||
|
||||
// -----------
|
||||
|
||||
inline fun <reified T : Any> test() {
|
||||
val instance = T::class.createInstance()
|
||||
assertTrue(instance is T)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> testFail() {
|
||||
try {
|
||||
T::class.createInstance()
|
||||
fail("createInstance should have failed on ${T::class}")
|
||||
} catch (e: Exception) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test<Any>()
|
||||
test<Simple>()
|
||||
test<PrimaryWithDefaults>()
|
||||
test<Secondary>()
|
||||
test<SecondaryWithDefaults>()
|
||||
test<SecondaryWithDefaultsNoPrimary>()
|
||||
|
||||
testFail<NoNoArgConstructor>()
|
||||
testFail<NoArgAndDefault>()
|
||||
testFail<DefaultPrimaryAndDefaultSecondary>()
|
||||
testFail<SeveralDefaultSecondaries>()
|
||||
testFail<PrivateConstructor>()
|
||||
testFail<Object>()
|
||||
testFail<Interface>()
|
||||
testFail<EnumFoo>()
|
||||
testFail<AbstractClass>()
|
||||
testFail<SealedClass>()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// IGNORE_BACKEND: JS
|
||||
// KJS_WITH_FULL_RUNTIME
|
||||
|
||||
import kotlin.reflect.createInstance
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
// Good classes
|
||||
|
||||
class Simple
|
||||
class PrimaryWithDefaults(val d1: String = "d1", val d2: Int = 2)
|
||||
class Secondary(val s: String) {
|
||||
constructor() : this("s")
|
||||
}
|
||||
class SecondaryWithDefaults(val s: String) {
|
||||
constructor(x: Int = 0) : this(x.toString())
|
||||
}
|
||||
class SecondaryWithDefaultsNoPrimary {
|
||||
constructor(x: Int) {}
|
||||
constructor(s: String = "") {}
|
||||
}
|
||||
|
||||
// Bad classes
|
||||
|
||||
class NoNoArgConstructor(val s: String) {
|
||||
constructor(x: Int) : this(x.toString())
|
||||
}
|
||||
class NoArgAndDefault() {
|
||||
constructor(x: Int = 0) : this()
|
||||
}
|
||||
class DefaultPrimaryAndDefaultSecondary(val s: String = "") {
|
||||
constructor(x: Int = 0) : this(x.toString())
|
||||
}
|
||||
class SeveralDefaultSecondaries {
|
||||
constructor(x: Int = 0) {}
|
||||
constructor(s: String = "") {}
|
||||
constructor(d: Double = 3.14) {}
|
||||
}
|
||||
class PrivateConstructor private constructor() {
|
||||
companion object {
|
||||
fun create() = PrivateConstructor()
|
||||
}
|
||||
}
|
||||
object Object
|
||||
enum class EnumFoo { A, B }
|
||||
|
||||
// -----------
|
||||
|
||||
inline fun <T : Any> testInstance(x: T) {
|
||||
val kclass = x::class
|
||||
val anotherInstance = kclass.createInstance()
|
||||
assertTrue(kclass.isInstance(x) && kclass.isInstance(anotherInstance))
|
||||
}
|
||||
|
||||
inline fun <T : Any> testInstanceFail(x: T) {
|
||||
try {
|
||||
val kclass = x::class
|
||||
kclass.createInstance()
|
||||
fail("createInstance should have failed on $kclass")
|
||||
} catch (e: Exception) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
testInstance(Simple())
|
||||
testInstance(PrimaryWithDefaults("d2"))
|
||||
testInstance(Secondary("test"))
|
||||
testInstance(SecondaryWithDefaults("test"))
|
||||
testInstance(SecondaryWithDefaultsNoPrimary(2))
|
||||
|
||||
testInstanceFail(NoNoArgConstructor(4))
|
||||
testInstanceFail(NoArgAndDefault())
|
||||
testInstanceFail(DefaultPrimaryAndDefaultSecondary(4))
|
||||
testInstanceFail(SeveralDefaultSecondaries(4))
|
||||
testInstanceFail(PrivateConstructor.create())
|
||||
testInstanceFail(Object)
|
||||
testInstanceFail(EnumFoo.A)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -216,6 +216,15 @@ public final annotation class ExperimentalJsFileName : kotlin.Annotation {
|
||||
public constructor ExperimentalJsFileName()
|
||||
}
|
||||
|
||||
@kotlin.RequiresOptIn(level = Level.WARNING)
|
||||
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
|
||||
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FIELD, AnnotationTarget.LOCAL_VARIABLE, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.TYPEALIAS})
|
||||
@kotlin.annotation.MustBeDocumented
|
||||
@kotlin.SinceKotlin(version = "1.9")
|
||||
public final annotation class ExperimentalJsReflectionCreateInstance : kotlin.Annotation {
|
||||
public constructor ExperimentalJsReflectionCreateInstance()
|
||||
}
|
||||
|
||||
public external object JSON {
|
||||
public final fun <T> parse(text: kotlin.String): T
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@ public inline fun <reified T> typeOf(): kotlin.reflect.KType
|
||||
@kotlin.internal.LowPriorityInOverloadResolution
|
||||
public fun <T : kotlin.Any> kotlin.reflect.KClass<T>.cast(value: kotlin.Any?): T
|
||||
|
||||
@kotlin.SinceKotlin(version = "1.9")
|
||||
@kotlin.js.ExperimentalJsReflectionCreateInstance
|
||||
public fun <T : kotlin.Any> kotlin.reflect.KClass<T>.createInstance(): T
|
||||
|
||||
@kotlin.reflect.ExperimentalAssociatedObjects
|
||||
public inline fun <reified T : kotlin.Annotation> kotlin.reflect.KClass<*>.findAssociatedObject(): kotlin.Any?
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package kotlin.js
|
||||
|
||||
import kotlin.annotation.AnnotationTarget.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Gives a declaration (a function, a property or a class) specific name in JavaScript.
|
||||
@@ -100,3 +101,30 @@ public expect annotation class JsExport() {
|
||||
public annotation class Ignore()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This annotation marks the experimental Kotlin/JS reflection API that allows to create an instance of provided [KClass]
|
||||
* The API can be removed completely in any further release.
|
||||
*
|
||||
* Any usage of a declaration annotated with `@ExperimentalJsReflectionCreateInstance` should be accepted either by
|
||||
* annotating that usage with the [OptIn] annotation, e.g. `@OptIn(ExperimentalJsReflectionCreateInstance::class)`,
|
||||
* or by using the compiler argument `-opt-in=kotlin.js.ExperimentalJsReflectionCreateInstance`.
|
||||
*/
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(
|
||||
AnnotationTarget.CLASS,
|
||||
AnnotationTarget.ANNOTATION_CLASS,
|
||||
AnnotationTarget.PROPERTY,
|
||||
AnnotationTarget.FIELD,
|
||||
AnnotationTarget.LOCAL_VARIABLE,
|
||||
AnnotationTarget.VALUE_PARAMETER,
|
||||
AnnotationTarget.CONSTRUCTOR,
|
||||
AnnotationTarget.FUNCTION,
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER,
|
||||
AnnotationTarget.TYPEALIAS
|
||||
)
|
||||
@MustBeDocumented
|
||||
@SinceKotlin("1.9")
|
||||
public annotation class ExperimentalJsReflectionCreateInstance
|
||||
@@ -8,8 +8,8 @@ package kotlin.js
|
||||
internal typealias BitMask = IntArray
|
||||
|
||||
private fun bitMaskWith(activeBit: Int): BitMask {
|
||||
val intArray = IntArray((activeBit shr 5) + 1)
|
||||
val numberIndex = activeBit shr 5
|
||||
val intArray = IntArray(numberIndex + 1)
|
||||
val positionInNumber = activeBit and 31
|
||||
val numberWithSettledBit = 1 shl positionInNumber
|
||||
intArray[numberIndex] = intArray[numberIndex] or numberWithSettledBit
|
||||
|
||||
@@ -227,4 +227,7 @@ internal fun jsInIntrinsic(lhs: Any?, rhs: Any): Boolean
|
||||
internal fun jsDelete(e: Any?)
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsContextfulRef(context: dynamic, fn: dynamic): dynamic
|
||||
internal fun jsContextfulRef(context: dynamic, fn: dynamic): dynamic
|
||||
|
||||
@JsIntrinsic
|
||||
internal fun jsIsEs6(): Boolean
|
||||
|
||||
@@ -7,9 +7,10 @@ package kotlin.js
|
||||
internal fun setMetadataFor(
|
||||
ctor: Ctor,
|
||||
name: String?,
|
||||
metadataConstructor: (name: String?, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?) -> Metadata,
|
||||
metadataConstructor: (name: String?, defaultConstructor: dynamic, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?) -> Metadata,
|
||||
parent: Ctor?,
|
||||
interfaces: Array<dynamic>?,
|
||||
defaultConstructor: dynamic,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?
|
||||
@@ -21,7 +22,7 @@ internal fun setMetadataFor(
|
||||
""")
|
||||
}
|
||||
|
||||
val metadata = metadataConstructor(name, associatedObjectKey, associatedObjects, suspendArity ?: js("[]"))
|
||||
val metadata = metadataConstructor(name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity ?: js("[]"))
|
||||
ctor.`$metadata$` = metadata
|
||||
|
||||
if (interfaces != null) {
|
||||
@@ -45,16 +46,34 @@ private fun generateInterfaceId(): Int {
|
||||
}
|
||||
|
||||
|
||||
internal fun interfaceMeta(name: String?, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?): Metadata {
|
||||
return createMetadata("interface", name, associatedObjectKey, associatedObjects, suspendArity, generateInterfaceId())
|
||||
internal fun interfaceMeta(
|
||||
name: String?,
|
||||
defaultConstructor: dynamic,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?
|
||||
): Metadata {
|
||||
return createMetadata("interface", name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity, generateInterfaceId())
|
||||
}
|
||||
|
||||
internal fun objectMeta(name: String?, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?): Metadata {
|
||||
return createMetadata("object", name, associatedObjectKey, associatedObjects, suspendArity, null)
|
||||
internal fun objectMeta(
|
||||
name: String?,
|
||||
defaultConstructor: dynamic,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?
|
||||
): Metadata {
|
||||
return createMetadata("object", name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity, null)
|
||||
}
|
||||
|
||||
internal fun classMeta(name: String?, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?): Metadata {
|
||||
return createMetadata("class", name, associatedObjectKey, associatedObjects, suspendArity, null)
|
||||
internal fun classMeta(
|
||||
name: String?,
|
||||
defaultConstructor: dynamic,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?
|
||||
): Metadata {
|
||||
return createMetadata("class", name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity, null)
|
||||
}
|
||||
|
||||
// Seems like we need to disable this check if variables are used inside js annotation
|
||||
@@ -62,6 +81,7 @@ internal fun classMeta(name: String?, associatedObjectKey: Number?, associatedOb
|
||||
private fun createMetadata(
|
||||
kind: String,
|
||||
name: String?,
|
||||
defaultConstructor: dynamic,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?,
|
||||
@@ -75,6 +95,7 @@ private fun createMetadata(
|
||||
associatedObjects: associatedObjects,
|
||||
suspendArity: suspendArity,
|
||||
${'$'}kClass$: undef,
|
||||
defaultConstructor: defaultConstructor,
|
||||
iid: iid
|
||||
})""")
|
||||
}
|
||||
@@ -90,6 +111,7 @@ internal external interface Metadata {
|
||||
val iid: Int?
|
||||
|
||||
var `$kClass$`: dynamic
|
||||
val defaultConstructor: dynamic
|
||||
|
||||
var errorInfo: Int? // Bits set for overridden properties: "message" => 0x1, "cause" => 0x2
|
||||
}
|
||||
@@ -44,7 +44,7 @@ private fun getKPropMetadata(paramCount: Int, setter: Any?): dynamic {
|
||||
}
|
||||
|
||||
private fun metadataObject(): Metadata {
|
||||
return classMeta(VOID, VOID, VOID, VOID)
|
||||
return classMeta(VOID, VOID, VOID, VOID, VOID)
|
||||
}
|
||||
|
||||
private val propertyRefClassMetadataCache: Array<Array<dynamic>> = arrayOf<Array<dynamic>>(
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.reflect
|
||||
|
||||
/**
|
||||
* Creates a new instance of the class, calling a constructor which either has no parameters or all parameters of which have
|
||||
* a default value. If there are no or many such constructors, an exception is thrown.
|
||||
*/
|
||||
@OptIn(JsIntrinsic::class)
|
||||
@SinceKotlin("1.9")
|
||||
@ExperimentalJsReflectionCreateInstance
|
||||
public fun <T : Any> KClass<T>.createInstance(): T {
|
||||
val jsClass = js.asDynamic()
|
||||
|
||||
if (jsClass === js("Object")) return js("{}")
|
||||
|
||||
val noArgsConstructor = jsClass.`$metadata$`.unsafeCast<Metadata?>()?.defaultConstructor
|
||||
?: throw IllegalArgumentException("Class \"$simpleName\" should have a single no-arg constructor")
|
||||
|
||||
return if (jsIsEs6() && noArgsConstructor !== jsClass) {
|
||||
js("noArgsConstructor.call(jsClass)")
|
||||
} else {
|
||||
js("new noArgsConstructor()")
|
||||
}
|
||||
}
|
||||
+3
@@ -3387,6 +3387,9 @@ public abstract interface annotation class kotlin/js/ExperimentalJsExport : java
|
||||
public abstract interface annotation class kotlin/js/ExperimentalJsFileName : java/lang/annotation/Annotation {
|
||||
}
|
||||
|
||||
public abstract interface annotation class kotlin/js/ExperimentalJsReflectionCreateInstance : java/lang/annotation/Annotation {
|
||||
}
|
||||
|
||||
public final class kotlin/jvm/JvmClassMappingKt {
|
||||
public static final fun getAnnotationClass (Ljava/lang/annotation/Annotation;)Lkotlin/reflect/KClass;
|
||||
public static final fun getJavaClass (Ljava/lang/Object;)Ljava/lang/Class;
|
||||
|
||||
Reference in New Issue
Block a user