[K/JS] Make interface subtyping faster and lighter.
This commit is contained in:
@@ -8,12 +8,10 @@ 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.backend.js.utils.getJsName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.isLong
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
@@ -109,6 +107,9 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
|
||||
// RTTI:
|
||||
val implementSymbol = getInternalFunction("implement")
|
||||
val setMetadataForSymbol = getInternalFunction("setMetadataFor")
|
||||
|
||||
val isInterfaceSymbol = getInternalFunction("isInterface")
|
||||
val isArraySymbol = getInternalFunction("isArray")
|
||||
// val isCharSymbol = getInternalFunction("isChar")
|
||||
|
||||
@@ -155,6 +155,7 @@ class JsIrBackendContext(
|
||||
|
||||
val dynamicType: IrDynamicType = IrDynamicTypeImpl(null, emptyList(), Variance.INVARIANT)
|
||||
val intrinsics: JsIntrinsics = JsIntrinsics(irBuiltIns, this)
|
||||
|
||||
override val reflectionSymbols: ReflectionSymbols get() = intrinsics.reflectionSymbols
|
||||
|
||||
override val propertyLazyInitialization: PropertyLazyInitialization = PropertyLazyInitialization(
|
||||
|
||||
@@ -526,7 +526,7 @@ private val privateMemberUsagesLoweringPhase = makeBodyLoweringPhase(
|
||||
private val propertyReferenceLoweringPhase = makeBodyLoweringPhase(
|
||||
::PropertyReferenceLowering,
|
||||
name = "PropertyReferenceLowering",
|
||||
description = "Transform property references"
|
||||
description = "Transform property references",
|
||||
)
|
||||
|
||||
private val interopCallableReferenceLoweringPhase = makeBodyLoweringPhase(
|
||||
@@ -669,7 +669,7 @@ private val typeOperatorLoweringPhase = makeBodyLoweringPhase(
|
||||
bridgesConstructionPhase,
|
||||
removeInlineDeclarationsWithReifiedTypeParametersLoweringPhase,
|
||||
singleAbstractMethodPhase, errorExpressionLoweringPhase,
|
||||
interopCallableReferenceLoweringPhase
|
||||
interopCallableReferenceLoweringPhase,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -705,7 +705,6 @@ private val constLoweringPhase = makeBodyLoweringPhase(
|
||||
name = "ConstLowering",
|
||||
description = "Wrap Long and Char constants into constructor invocation"
|
||||
)
|
||||
|
||||
private val inlineClassDeclarationLoweringPhase = makeDeclarationTransformerPhase(
|
||||
{ InlineClassLowering(it).inlineClassDeclarationLowering },
|
||||
name = "InlineClassDeclarationLowering",
|
||||
@@ -806,6 +805,7 @@ private val implicitlyExportedDeclarationsMarkingLowering = makeDeclarationTrans
|
||||
description = "Add @JsImplicitExport annotation to declarations which are not exported but are used inside other exported declarations as a type"
|
||||
)
|
||||
|
||||
|
||||
private val cleanupLoweringPhase = makeBodyLoweringPhase(
|
||||
{ CleanupLowering() },
|
||||
name = "CleanupLowering",
|
||||
|
||||
+34
-11
@@ -5,22 +5,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.dce
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.MethodsFromAnyGeneratorForLowerings.Companion.collectOverridenSymbols
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.associatedObject
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.invokeFunForLambda
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
|
||||
internal class JsUsefulDeclarationProcessor(
|
||||
@@ -33,6 +28,13 @@ internal class JsUsefulDeclarationProcessor(
|
||||
private val hashCodeMethod = getMethodOfAny("hashCode")
|
||||
|
||||
override val bodyVisitor: BodyVisitorBase = object : BodyVisitorBase() {
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: IrDeclaration) {
|
||||
if (expression.symbol != context.intrinsics.implementSymbol) {
|
||||
// Just ignore implement to not include large chunk of code inside small applications if it's not needed
|
||||
super.visitFunctionAccess(expression, data)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: IrDeclaration) {
|
||||
super.visitCall(expression, data)
|
||||
when (expression.symbol) {
|
||||
@@ -113,20 +115,41 @@ internal class JsUsefulDeclarationProcessor(
|
||||
|
||||
}
|
||||
|
||||
override fun processSuperTypes(irClass: IrClass) {
|
||||
irClass.superTypes.forEach {
|
||||
if (!it.isInterface()) {
|
||||
(it.classifierOrNull as? IrClassSymbol)?.owner?.enqueue(irClass, "superTypes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processClass(irClass: IrClass) {
|
||||
super.processClass(irClass)
|
||||
|
||||
if (irClass.containsMetadata()) {
|
||||
when {
|
||||
irClass.isInterface -> context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
||||
irClass.isInterface -> {
|
||||
context.intrinsics.implementSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
}
|
||||
else -> context.intrinsics.metadataClassConstructorSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
|
||||
context.intrinsics.setMetadataForSymbol.owner.enqueue(irClass, "metadata")
|
||||
}
|
||||
}
|
||||
|
||||
override fun processSimpleFunction(irFunction: IrSimpleFunction) {
|
||||
super.processSimpleFunction(irFunction)
|
||||
|
||||
if (irFunction.isReal && irFunction.body != null) {
|
||||
irFunction.parentClassOrNull?.takeIf { it.isInterface }?.enqueue(irFunction, "interface default method is used")
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.containsMetadata(): Boolean =
|
||||
!isExternal && !isExpect && !isBuiltInClass(this)
|
||||
!isExternal && !isExpect && !isBuiltInClass(this)
|
||||
|
||||
override fun processConstructedClassDeclaration(declaration: IrDeclaration) {
|
||||
if (declaration in result) return
|
||||
|
||||
+9
-4
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isAssociatedObjectAnnotatedAnnot
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
@@ -138,14 +139,12 @@ abstract class UsefulDeclarationProcessor(
|
||||
protected val result = hashSetOf<IrDeclaration>()
|
||||
protected val classesWithObjectAssociations = hashSetOf<IrClass>()
|
||||
|
||||
public val usefulPolyfilledDeclarations = hashSetOf<IrDeclaration>()
|
||||
val usefulPolyfilledDeclarations = hashSetOf<IrDeclaration>()
|
||||
|
||||
protected open fun processField(irField: IrField): Unit = Unit
|
||||
|
||||
protected open fun processClass(irClass: IrClass) {
|
||||
irClass.superTypes.forEach {
|
||||
(it.classifierOrNull as? IrClassSymbol)?.owner?.enqueue(irClass, "superTypes")
|
||||
}
|
||||
processSuperTypes(irClass)
|
||||
|
||||
if (irClass.isObject && isExported(irClass)) {
|
||||
context.mapping.objectToGetInstanceFunction[irClass]
|
||||
@@ -161,6 +160,12 @@ abstract class UsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun processSuperTypes(irClass: IrClass) {
|
||||
irClass.superTypes.forEach {
|
||||
(it.classifierOrNull as? IrClassSymbol)?.owner?.enqueue(irClass, "superTypes")
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun processSimpleFunction(irFunction: IrSimpleFunction) {
|
||||
if (irFunction.isFakeOverride) {
|
||||
irFunction.resolveFakeOverride()?.enqueue(irFunction, "real overridden fun", isContagious = false)
|
||||
|
||||
+24
@@ -13,6 +13,11 @@ import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -24,6 +29,8 @@ class UselessDeclarationsRemover(
|
||||
private val context: JsIrBackendContext,
|
||||
private val dceRuntimeDiagnostic: RuntimeDiagnostic?,
|
||||
) : IrElementVisitorVoid {
|
||||
private val savedTypesCache = hashMapOf<IrClassSymbol, Set<IrClassSymbol>>()
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
@@ -47,6 +54,23 @@ class UselessDeclarationsRemover(
|
||||
if (removeUnusedAssociatedObjects && declaration.annotations.any { !it.shouldKeepAnnotation() }) {
|
||||
declaration.annotations = declaration.annotations.filter { it.shouldKeepAnnotation() }
|
||||
}
|
||||
|
||||
declaration.superTypes = declaration.superTypes
|
||||
.flatMap { it.classOrNull?.collectUsedSuperTypes() ?: emptyList() }
|
||||
.distinct()
|
||||
.map { it.defaultType }
|
||||
}
|
||||
|
||||
private fun IrClassSymbol.collectUsedSuperTypes(): Set<IrClassSymbol> {
|
||||
return savedTypesCache.getOrPut(this) {
|
||||
if (owner in usefulDeclarations) {
|
||||
setOf(this)
|
||||
} else {
|
||||
owner.superTypes
|
||||
.flatMap { it.takeIf { !it.isAny() }?.classOrNull?.collectUsedSuperTypes() ?: emptyList() }
|
||||
.toSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO bring back the primary constructor fix
|
||||
|
||||
+2
-2
@@ -128,8 +128,8 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue, context: JsGenerationContext): JsExpression {
|
||||
val obj = expression.symbol.owner
|
||||
|
||||
assert(obj.kind == ClassKind.OBJECT)
|
||||
assert(obj.isEffectivelyExternal()) { "Non external IrGetObjectValue must be lowered" }
|
||||
assert(obj.kind == ClassKind.OBJECT)
|
||||
assert(obj.isEffectivelyExternal()) { "Non external IrGetObjectValue must be lowered" }
|
||||
|
||||
return context.getRefForExternalClass(obj).withSource(expression, context)
|
||||
}
|
||||
|
||||
+1
-1
@@ -269,7 +269,7 @@ class IrModuleToJsTransformerTmp(
|
||||
|
||||
staticContext.classModels.entries.forEach { (symbol, model) ->
|
||||
result.classes[nameGenerator.getNameForClass(symbol.owner)] =
|
||||
JsIrIcClassModel(model.klass.superTypes.map { staticContext.getNameForClass((it.classifierOrFail as IrClassSymbol).owner) }).also {
|
||||
JsIrIcClassModel(model.superClasses.map { staticContext.getNameForClass(it.owner) }).also {
|
||||
it.preDeclarationBlock.statements += model.preDeclarationBlock.statements
|
||||
it.postDeclarationBlock.statements += model.postDeclarationBlock.statements
|
||||
}
|
||||
|
||||
+61
-66
@@ -6,27 +6,31 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
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
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||
|
||||
private val className = context.getNameForClass(irClass)
|
||||
private val classNameRef = className.makeRef()
|
||||
private val baseClass: IrType? = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
|
||||
@@ -44,6 +48,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
assert(!irClass.isExpect)
|
||||
|
||||
if (!es6mode) maybeGeneratePrimaryConstructor()
|
||||
|
||||
val transformer = IrDeclarationToJsTransformer()
|
||||
|
||||
// Properties might be lowered out of classes
|
||||
@@ -74,7 +79,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
} else {
|
||||
classBlock.statements += declaration.accept(transformer, context)
|
||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
}
|
||||
is IrSimpleFunction -> {
|
||||
@@ -104,8 +108,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
|
||||
classBlock.statements += generateClassMetadata()
|
||||
|
||||
if (!irClass.isInterface) {
|
||||
for (property in properties) {
|
||||
if (property.getter?.extensionReceiverParameter != null || property.setter?.extensionReceiverParameter != null)
|
||||
@@ -206,7 +208,11 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
classModel.preDeclarationBlock.statements += generateSetMetadataCall()
|
||||
|
||||
context.staticContext.classModels[irClass.symbol] = classModel
|
||||
|
||||
return classBlock
|
||||
}
|
||||
|
||||
@@ -307,24 +313,49 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
val func = JsFunction(emptyScope, JsBlock(), "Ctor for ${irClass.name}")
|
||||
func.name = className
|
||||
classBlock.statements += func.makeStmt()
|
||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateInheritanceCode(): List<JsStatement> {
|
||||
val baseClassPrototype = baseClassRef ?: return emptyList()
|
||||
private fun generateSetMetadataCall(): JsStatement {
|
||||
val setMetadataFor = context.staticContext.backendContext.intrinsics.setMetadataForSymbol.owner
|
||||
|
||||
val createCall = jsAssignment(
|
||||
classPrototypeRef, JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototypeOf(baseClassPrototype))
|
||||
val ctor = classNameRef
|
||||
val parent = baseClassRef
|
||||
val name = generateSimpleName()
|
||||
val interfaces = generateInterfacesList()
|
||||
val metadataConstructor = getMetadataConstructor()
|
||||
val associatedObjectKey = generateAssociatedObjectKey()
|
||||
val associatedObjects = generateAssociatedObjects()
|
||||
val suspendArity = generateSuspendArity()
|
||||
|
||||
return JsInvocation(
|
||||
JsNameRef(context.getNameForStaticFunction(setMetadataFor)),
|
||||
listOf(ctor, name, metadataConstructor, parent, interfaces, associatedObjectKey, associatedObjects, suspendArity)
|
||||
.dropLastWhile { it == null }
|
||||
.map { it ?: Namer.JS_UNDEFINED }
|
||||
).makeStmt()
|
||||
|
||||
val ctorAssign = jsAssignment(JsNameRef(Namer.CONSTRUCTOR_NAME, classPrototypeRef), classNameRef).makeStmt()
|
||||
|
||||
return listOf(createCall, ctorAssign)
|
||||
}
|
||||
|
||||
private fun generateClassMetadata(): JsStatement {
|
||||
val metadataConstructor = with(context.staticContext.backendContext.intrinsics) {
|
||||
|
||||
private fun IrType.asConstructorRef(): JsNameRef? {
|
||||
val ownerSymbol = classOrNull?.takeIf {
|
||||
!isAny() && !isFunctionType() && !it.owner.isEffectivelyExternal()
|
||||
} ?: return null
|
||||
|
||||
return JsNameRef(context.getNameForClass(ownerSymbol.owner))
|
||||
}
|
||||
|
||||
private fun IrType.isFunctionType() = isFunctionOrKFunction() || isSuspendFunctionOrKFunction()
|
||||
|
||||
private fun isCoroutineClass(): Boolean = irClass.superTypes.any { it.isSuspendFunctionTypeOrSubtype() }
|
||||
|
||||
private fun generateSimpleName(): JsStringLiteral? {
|
||||
return irClass.name.takeIf { !it.isSpecial }?.let { JsStringLiteral(it.identifier) }
|
||||
}
|
||||
|
||||
private fun getMetadataConstructor(): JsNameRef {
|
||||
val metadataConstructorSymbol = with(context.staticContext.backendContext.intrinsics) {
|
||||
when {
|
||||
irClass.isInterface -> metadataInterfaceConstructorSymbol
|
||||
irClass.isObject -> metadataObjectConstructorSymbol
|
||||
@@ -332,32 +363,21 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
|
||||
val simpleName = irClass.name
|
||||
.takeIf { !it.isSpecial }
|
||||
?.let { JsStringLiteral(it.identifier) }
|
||||
|
||||
val interfaces = generateSuperClasses()
|
||||
val associatedObjectKey = generateAssociatedObjectKey()
|
||||
val associatedObjects = generateAssociatedObjects()
|
||||
val fastPrototype = generateFastPrototype()
|
||||
val suspendArity = generateSuspendArity()
|
||||
|
||||
val constructorCall = JsInvocation(
|
||||
JsNameRef(context.getNameForStaticFunction(metadataConstructor.owner)),
|
||||
listOf(simpleName, interfaces, associatedObjectKey, associatedObjects, suspendArity, fastPrototype)
|
||||
.dropLastWhile { it == null }
|
||||
.map { it ?: Namer.JS_UNDEFINED }
|
||||
)
|
||||
|
||||
return jsAssignment(JsNameRef(Namer.METADATA, classNameRef), constructorCall).makeStmt()
|
||||
return JsNameRef(context.getNameForStaticFunction(metadataConstructorSymbol.owner))
|
||||
}
|
||||
|
||||
private fun isCoroutineClass(): Boolean = irClass.superTypes.any { it.isSuspendFunctionTypeOrSubtype() }
|
||||
private fun generateInterfacesList(): JsArrayLiteral? {
|
||||
val listRef = irClass.superTypes
|
||||
.filter { it.classOrNull?.owner?.isExternal != true }
|
||||
.takeIf { it.size > 1 || it.singleOrNull() != baseClass }
|
||||
?.mapNotNull { it.asConstructorRef() }
|
||||
?.takeIf { it.isNotEmpty() } ?: return null
|
||||
return JsArrayLiteral(listRef)
|
||||
}
|
||||
|
||||
private fun generateSuspendArity(): JsArrayLiteral? {
|
||||
if (!isCoroutineClass()) return null
|
||||
|
||||
val arity = context.staticContext.backendContext.mapping.suspendArityStore[irClass]!!
|
||||
val invokeFunctions = context.staticContext.backendContext.mapping.suspendArityStore[irClass] ?: return null
|
||||
val arity = invokeFunctions
|
||||
.map { it.valueParameters.size }
|
||||
.distinct()
|
||||
.map { JsIntLiteral(it) }
|
||||
@@ -365,30 +385,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
return JsArrayLiteral(arity)
|
||||
}
|
||||
|
||||
private fun generateSuperClasses(): JsArrayLiteral? {
|
||||
val parentSymbols = irClass.superTypes.mapNotNull {
|
||||
val symbol = it.classifierOrFail as IrClassSymbol
|
||||
val isFunctionType = it.isFunctionType()
|
||||
// TODO: make sure that there is a test which breaks when isExternal is used here instead of isEffectivelyExternal
|
||||
val requireInMetadata = if (context.staticContext.backendContext.baseClassIntoMetadata)
|
||||
!it.isAny()
|
||||
else
|
||||
symbol.isInterface
|
||||
|
||||
if (requireInMetadata && !isFunctionType && !symbol.isEffectivelyExternal) {
|
||||
symbol
|
||||
} else null
|
||||
}
|
||||
|
||||
return parentSymbols
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.run { JsArrayLiteral(map { JsNameRef(context.getNameForClass(it.owner)) }) }
|
||||
}
|
||||
|
||||
private fun generateFastPrototype() = baseClassRef?.let { prototypeOf(it) }
|
||||
|
||||
private fun IrType.isFunctionType() = isFunctionOrKFunction() || isSuspendFunctionOrKFunction()
|
||||
|
||||
private fun generateAssociatedObjectKey(): JsIntLiteral? {
|
||||
return context.getAssociatedObjectKey(irClass)?.let { JsIntLiteral(it) }
|
||||
}
|
||||
@@ -440,10 +436,9 @@ private fun IrOverridableDeclaration<*>.overridesExternal(): Boolean {
|
||||
}
|
||||
|
||||
private val IrClassifierSymbol.isInterface get() = (owner as? IrClass)?.isInterface == true
|
||||
private val IrClassifierSymbol.isEffectivelyExternal get() = (owner as? IrDeclaration)?.isEffectivelyExternal() == true
|
||||
|
||||
class JsIrClassModel(val klass: IrClass) {
|
||||
val superClasses = klass.superTypes.map { it.classifierOrFail as IrClassSymbol }
|
||||
val superClasses = klass.superTypes.map { it.classifierOrNull as IrClassSymbol }
|
||||
|
||||
val preDeclarationBlock = JsCompositeBlock()
|
||||
val postDeclarationBlock = JsCompositeBlock()
|
||||
|
||||
+1
-1
@@ -272,7 +272,7 @@ class Merger(
|
||||
|
||||
DFS.dfs(
|
||||
classModelMap.keys,
|
||||
{ klass -> classModelMap[klass]?.superClasses ?: emptyList() },
|
||||
{ classModelMap[it]?.superClasses ?: emptyList() },
|
||||
declarationHandler
|
||||
)
|
||||
}
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.declarations.IrOverridableDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -36,8 +37,8 @@ fun IrConstructorCall.getSingleConstStringArgument() =
|
||||
(getValueArgument(0) as IrConst<String>).value
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun IrConstructorCall.getSingleConstBooleanArgument() =
|
||||
(getValueArgument(0) as IrConst<Boolean>).value
|
||||
fun IrConstructorCall.getClassReferencVarargArguments() =
|
||||
(getValueArgument(0) as? IrVararg)?.elements as? List<IrClassReference>
|
||||
|
||||
fun IrAnnotationContainer.getJsModule(): String? =
|
||||
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
|
||||
|
||||
@@ -32,7 +32,7 @@ object Namer {
|
||||
val JS_OBJECT_CREATE_FUNCTION = JsNameRef("create", JS_OBJECT)
|
||||
|
||||
val METADATA = "\$metadata\$"
|
||||
val METADATA_INTERFACE_ID = "interfaceId"
|
||||
val INTERFACES_MASK = "\$imask\$"
|
||||
|
||||
val KCALLABLE_GET_NAME = "<get-name>"
|
||||
val KCALLABLE_NAME = "callableName"
|
||||
|
||||
@@ -3811,6 +3811,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/expression/typeCheck"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("complexIsInterface.kt")
|
||||
public void testComplexIsInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/complexIsInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleAsClass.kt")
|
||||
public void testSimpleAsClass() throws Exception {
|
||||
|
||||
+6
@@ -4265,6 +4265,12 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/expression/typeCheck"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("complexIsInterface.kt")
|
||||
public void testComplexIsInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/complexIsInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleAsClass.kt")
|
||||
public void testSimpleAsClass() throws Exception {
|
||||
|
||||
+6
@@ -4265,6 +4265,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/expression/typeCheck"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("complexIsInterface.kt")
|
||||
public void testComplexIsInterface() throws Exception {
|
||||
runTest("js/js.translator/testData/box/expression/typeCheck/complexIsInterface.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleAsClass.kt")
|
||||
public void testSimpleAsClass() throws Exception {
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
package foo
|
||||
|
||||
interface I1: I61
|
||||
interface I2: I61, I62
|
||||
interface I3: I61, I62, I63
|
||||
interface I4: I61, I62, I63, I64
|
||||
interface I5: I61, I62, I63, I64, I65
|
||||
interface I6: I61, I62, I63, I64, I65, I66
|
||||
interface I7: I61, I62, I63, I64, I65, I66, I67
|
||||
interface I8: I61, I62, I63, I64, I65, I66, I67, I68
|
||||
interface I9: I61, I62, I63, I64, I65, I66, I67, I68, I69
|
||||
interface I10: I61, I62, I63, I64, I65, I66, I67, I68, I69, I70
|
||||
|
||||
interface I11: I51, I52, I53, I54, I55, I56, I57, I58, I59, I60
|
||||
interface I12: I51, I52, I53, I54, I55, I56, I57, I58, I59
|
||||
interface I13: I51, I52, I53, I54, I55, I56, I57, I58
|
||||
interface I14: I51, I52, I53, I54, I55, I56, I57
|
||||
interface I15: I51, I52, I53, I54, I55, I56
|
||||
interface I16: I51, I52, I53, I54, I55
|
||||
interface I17: I51, I52, I53, I54
|
||||
interface I18: I51, I52, I53
|
||||
interface I19: I51, I52
|
||||
interface I20: I51
|
||||
|
||||
interface I21
|
||||
interface I22: I21
|
||||
interface I23: I22
|
||||
interface I24: I23
|
||||
interface I25: I24
|
||||
interface I26: I25
|
||||
interface I27: I26
|
||||
interface I28: I27
|
||||
interface I29: I28
|
||||
interface I30: I29
|
||||
|
||||
interface I31: I40
|
||||
interface I32: I37
|
||||
interface I33: I36
|
||||
interface I34: I35
|
||||
interface I35
|
||||
interface I36: I34
|
||||
interface I37: I33
|
||||
interface I38: I32
|
||||
interface I39: I31
|
||||
interface I40
|
||||
|
||||
interface I41: I1
|
||||
interface I42: I1, I2
|
||||
interface I43: I1, I2, I3
|
||||
interface I44: I1, I2, I3, I4
|
||||
interface I45: I1, I2, I3, I4, I5
|
||||
interface I46: I1, I2, I3, I4, I5, I6
|
||||
interface I47: I1, I2, I3, I4, I5, I6, I7
|
||||
interface I48: I1, I2, I3, I4, I5, I6, I7, I8
|
||||
interface I49: I1, I2, I3, I4, I5, I6, I7, I8, I9
|
||||
interface I50: I1, I2, I3, I4, I5, I6, I7, I8, I9, I10
|
||||
|
||||
interface I51: I10
|
||||
interface I52: I20
|
||||
interface I53: I30
|
||||
interface I54: I40
|
||||
interface I55: I50
|
||||
interface I56: I60
|
||||
interface I57: I70
|
||||
interface I58
|
||||
interface I59
|
||||
interface I60
|
||||
|
||||
interface I61
|
||||
interface I62
|
||||
interface I63
|
||||
interface I64
|
||||
interface I65
|
||||
interface I66
|
||||
interface I67
|
||||
interface I68
|
||||
interface I69
|
||||
interface I70
|
||||
|
||||
open class C1: I51
|
||||
open class C2: C1(), I52
|
||||
open class C3: C2(), I53
|
||||
open class C4: C3(), I54
|
||||
open class C5: C4(), I55
|
||||
open class C6: C5(), I56
|
||||
open class C7: C6(), I57
|
||||
open class C8: C7() // SKIP I58
|
||||
open class C9: C8() // SKIP I59
|
||||
class C10: C9(), I60
|
||||
|
||||
class C11: I1, I11
|
||||
class C12: I2, I12
|
||||
class C13: I3, I13
|
||||
class C14: I4, I14
|
||||
class C15: I5, I15
|
||||
class C16: I6, I16
|
||||
class C17: I7, I17
|
||||
class C18: I8, I18
|
||||
class C19: I9, I19
|
||||
class C20: I10, I20
|
||||
|
||||
open class C21: I31, I32, I33
|
||||
class C22: C21(), I34, I35, I36
|
||||
open class C23: I37, I38, I39
|
||||
class C24: C23(), I40, I50, I60
|
||||
class C25
|
||||
|
||||
fun process(instance: Any, label: String, interfaces: Set<String>) {
|
||||
assertEquals("I1" in interfaces, instance is I1, "$label is I1")
|
||||
assertEquals("I2" in interfaces, instance is I2, "$label is I2")
|
||||
assertEquals("I3" in interfaces, instance is I3, "$label is I3")
|
||||
assertEquals("I4" in interfaces, instance is I4, "$label is I4")
|
||||
assertEquals("I5" in interfaces, instance is I5, "$label is I5")
|
||||
assertEquals("I6" in interfaces, instance is I6, "$label is I6")
|
||||
assertEquals("I7" in interfaces, instance is I7, "$label is I7")
|
||||
assertEquals("I8" in interfaces, instance is I8, "$label is I8")
|
||||
assertEquals("I9" in interfaces, instance is I9, "$label is I9")
|
||||
assertEquals("I10" in interfaces, instance is I10, "$label is I10")
|
||||
|
||||
assertEquals("I11" in interfaces, instance is I11, "$label is I11")
|
||||
assertEquals("I12" in interfaces, instance is I12, "$label is I12")
|
||||
assertEquals("I13" in interfaces, instance is I13, "$label is I13")
|
||||
assertEquals("I14" in interfaces, instance is I14, "$label is I14")
|
||||
assertEquals("I15" in interfaces, instance is I15, "$label is I15")
|
||||
assertEquals("I16" in interfaces, instance is I16, "$label is I16")
|
||||
assertEquals("I17" in interfaces, instance is I17, "$label is I17")
|
||||
assertEquals("I18" in interfaces, instance is I18, "$label is I18")
|
||||
assertEquals("I19" in interfaces, instance is I19, "$label is I19")
|
||||
assertEquals("I20" in interfaces, instance is I20, "$label is I20")
|
||||
|
||||
assertEquals("I21" in interfaces, instance is I21, "$label is I21")
|
||||
assertEquals("I22" in interfaces, instance is I22, "$label is I22")
|
||||
assertEquals("I23" in interfaces, instance is I23, "$label is I23")
|
||||
assertEquals("I24" in interfaces, instance is I24, "$label is I24")
|
||||
assertEquals("I25" in interfaces, instance is I25, "$label is I25")
|
||||
assertEquals("I26" in interfaces, instance is I26, "$label is I26")
|
||||
assertEquals("I27" in interfaces, instance is I27, "$label is I27")
|
||||
assertEquals("I28" in interfaces, instance is I28, "$label is I28")
|
||||
assertEquals("I29" in interfaces, instance is I29, "$label is I29")
|
||||
assertEquals("I30" in interfaces, instance is I30, "$label is I30")
|
||||
|
||||
assertEquals("I31" in interfaces, instance is I31, "$label is I31")
|
||||
assertEquals("I32" in interfaces, instance is I32, "$label is I32")
|
||||
assertEquals("I33" in interfaces, instance is I33, "$label is I33")
|
||||
assertEquals("I34" in interfaces, instance is I34, "$label is I34")
|
||||
assertEquals("I35" in interfaces, instance is I35, "$label is I35")
|
||||
assertEquals("I36" in interfaces, instance is I36, "$label is I36")
|
||||
assertEquals("I37" in interfaces, instance is I37, "$label is I37")
|
||||
assertEquals("I38" in interfaces, instance is I38, "$label is I38")
|
||||
assertEquals("I39" in interfaces, instance is I39, "$label is I39")
|
||||
assertEquals("I40" in interfaces, instance is I40, "$label is I40")
|
||||
|
||||
assertEquals("I41" in interfaces, instance is I41, "$label is I41")
|
||||
assertEquals("I42" in interfaces, instance is I42, "$label is I42")
|
||||
assertEquals("I43" in interfaces, instance is I43, "$label is I43")
|
||||
assertEquals("I44" in interfaces, instance is I44, "$label is I44")
|
||||
assertEquals("I45" in interfaces, instance is I45, "$label is I45")
|
||||
assertEquals("I46" in interfaces, instance is I46, "$label is I46")
|
||||
assertEquals("I47" in interfaces, instance is I47, "$label is I47")
|
||||
assertEquals("I48" in interfaces, instance is I48, "$label is I48")
|
||||
assertEquals("I49" in interfaces, instance is I49, "$label is I49")
|
||||
assertEquals("I50" in interfaces, instance is I50, "$label is I50")
|
||||
|
||||
assertEquals("I51" in interfaces, instance is I51, "$label is I51")
|
||||
assertEquals("I52" in interfaces, instance is I52, "$label is I52")
|
||||
assertEquals("I53" in interfaces, instance is I53, "$label is I53")
|
||||
assertEquals("I54" in interfaces, instance is I54, "$label is I54")
|
||||
assertEquals("I55" in interfaces, instance is I55, "$label is I55")
|
||||
assertEquals("I56" in interfaces, instance is I56, "$label is I56")
|
||||
assertEquals("I57" in interfaces, instance is I57, "$label is I57")
|
||||
assertEquals("I58" in interfaces, instance is I58, "$label is I58")
|
||||
assertEquals("I59" in interfaces, instance is I59, "$label is I59")
|
||||
assertEquals("I60" in interfaces, instance is I60, "$label is I60")
|
||||
|
||||
assertEquals("I61" in interfaces, instance is I61, "$label is I61")
|
||||
assertEquals("I62" in interfaces, instance is I62, "$label is I62")
|
||||
assertEquals("I63" in interfaces, instance is I63, "$label is I63")
|
||||
assertEquals("I64" in interfaces, instance is I64, "$label is I64")
|
||||
assertEquals("I65" in interfaces, instance is I65, "$label is I65")
|
||||
assertEquals("I66" in interfaces, instance is I66, "$label is I66")
|
||||
assertEquals("I67" in interfaces, instance is I67, "$label is I67")
|
||||
assertEquals("I68" in interfaces, instance is I68, "$label is I68")
|
||||
assertEquals("I69" in interfaces, instance is I69, "$label is I69")
|
||||
assertEquals("I70" in interfaces, instance is I70, "$label is I70")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
process(C1(), "C1", setOf("I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C2(), "C2", setOf("I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C3(), "C3", setOf("I53", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C4(), "C4", setOf("I54", "I40", "I53", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C5(), "C5", setOf("I55", "I50", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I54", "I40", "I53", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C6(), "C6", setOf("I56", "I60", "I55", "I50", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I54", "I40", "I53", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C7(), "C7", setOf("I57", "I56", "I60", "I55", "I50", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I54", "I40", "I53", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C8(), "C8", setOf("I57", "I56", "I60", "I55", "I50", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I54", "I40", "I53", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C9(), "C9", setOf("I57", "I56", "I60", "I55", "I50", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I54", "I40", "I53", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C10(), "C10", setOf("I57", "I56", "I60", "I55", "I50", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I54", "I40", "I53", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I52", "I20", "I51", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
|
||||
process(C11(), "C11", setOf("I1", "I61", "I11", "I51", "I52", "I53", "I54", "I55", "I56", "I57", "I58", "I59", "I60", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70", "I10", "I20", "I30", "I40", "I50", "I60", "I70", "I21", "I22", "I23", "I24", "I25", "I26", "I27", "I28", "I29", "I30", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10"))
|
||||
process(C12(), "C12", setOf("I2", "I61", "I62", "I12", "I51", "I52", "I53", "I54", "I55", "I56", "I57", "I58", "I59", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70", "I10", "I20", "I30", "I40", "I50", "I70", "I21", "I22", "I23", "I24", "I25", "I26", "I27", "I28", "I29", "I30", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I60"))
|
||||
process(C13(), "C13", setOf("I3", "I13", "I61", "I62", "I63", "I51", "I52", "I53", "I54", "I55", "I56", "I57", "I58", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70", "I10", "I20", "I30", "I40", "I50", "I70", "I21", "I22", "I23", "I24", "I25", "I26", "I27", "I28", "I29", "I30", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I60"))
|
||||
process(C14(), "C14", setOf("I4", "I14", "I61", "I62", "I63", "I64", "I51", "I52", "I53", "I54", "I55", "I56", "I57", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70", "I10", "I20", "I30", "I40", "I50", "I70", "I21", "I22", "I23", "I24", "I25", "I26", "I27", "I28", "I29", "I30", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I60"))
|
||||
process(C15(), "C15", setOf("I5", "I61", "I62", "I63", "I64", "I65", "I15", "I51", "I52", "I53", "I54", "I55", "I56", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70", "I10", "I20", "I30", "I40", "I50", "I21", "I22", "I23", "I24", "I25", "I26", "I27", "I28", "I29", "I30", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I60"))
|
||||
process(C16(), "C16", setOf("I6", "I61", "I62", "I63", "I64", "I65", "I66", "I16", "I51", "I52", "I53", "I54", "I55", "I10", "I20", "I30", "I40", "I50", "I67", "I68", "I69", "I70", "I51", "I29", "I21", "I22", "I23", "I24", "I25", "I26", "I27", "I28", "I29", "I30", "I40", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I67", "I68", "I69", "I70"))
|
||||
process(C17(), "C17", setOf("I7", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I17", "I51", "I52", "I53", "I54", "I10", "I68", "I69", "I70", "I20", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21", "I40"))
|
||||
process(C18(), "C18", setOf("I8", "I18", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I51", "I52", "I53", "I10", "I69", "I70", "I20", "I30", "I29", "I28", "I27", "I26", "I25", "I24", "I23", "I22", "I21"))
|
||||
process(C19(), "C19", setOf("I9", "I19", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I51", "I52", "I10", "I70", "I20"))
|
||||
process(C20(), "C20", setOf("I10", "I20", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70", "I51"))
|
||||
|
||||
process(C21(), "C21", setOf("I31", "I32", "I33", "I40", "I37", "I33", "I36", "I34", "I35"))
|
||||
process(C22(), "C22", setOf("I31", "I32", "I33", "I40", "I37", "I33", "I36", "I34", "I35"))
|
||||
process(C23(), "C23", setOf("I37", "I38", "I39", "I33", "I36", "I34", "I35", "I32", "I31", "I40"))
|
||||
process(C24(), "C24", setOf("I37", "I38", "I39", "I33", "I36", "I34", "I35", "I32", "I31", "I40", "I50", "I60", "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I61", "I62", "I63", "I64", "I65", "I66", "I67", "I68", "I69", "I70"))
|
||||
process(C25(), "C25", emptySet())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// EXPECTED_REACHABLE_NODES: 1403
|
||||
|
||||
package foo
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.js
|
||||
|
||||
internal fun implement(vararg interfaces: dynamic): BitMask {
|
||||
var maxSize = 1
|
||||
val masks = js("[]")
|
||||
|
||||
for (i in interfaces) {
|
||||
var currentSize = maxSize
|
||||
val imask: BitMask? = i.prototype.`$imask$` ?: i.`$imask$`
|
||||
|
||||
if (imask != null) {
|
||||
masks.push(imask)
|
||||
currentSize = imask.intArray.size
|
||||
}
|
||||
|
||||
val iid: Int? = i.`$metadata$`.iid
|
||||
val iidImask: BitMask? = iid?.let { BitMask(arrayOf(it)) }
|
||||
|
||||
if (iidImask != null) {
|
||||
masks.push(iidImask)
|
||||
currentSize = JsMath.max(currentSize, iidImask.intArray.size)
|
||||
}
|
||||
|
||||
if (currentSize > maxSize) {
|
||||
maxSize = currentSize
|
||||
}
|
||||
}
|
||||
|
||||
val resultIntArray = IntArray(maxSize) { i ->
|
||||
masks.reduce({ acc: Int, it: BitMask ->
|
||||
if (i >= it.intArray.size)
|
||||
acc
|
||||
else
|
||||
acc or it.intArray[i]
|
||||
}, 0)
|
||||
}
|
||||
|
||||
val result = BitMask(emptyArray())
|
||||
result.intArray = resultIntArray
|
||||
return result
|
||||
}
|
||||
|
||||
internal class BitMask(activeBits: Array<Int>) {
|
||||
var intArray: IntArray = run {
|
||||
if (activeBits.size == 0) {
|
||||
IntArray(0)
|
||||
} else {
|
||||
val max: Int = JsMath.asDynamic().max.apply(null, activeBits)
|
||||
val intArray = IntArray((max shr 5) + 1)
|
||||
for (activeBit in activeBits) {
|
||||
val numberIndex = activeBit shr 5
|
||||
val positionInNumber = activeBit and 31
|
||||
val numberWithSettledBit = 1 shl positionInNumber
|
||||
intArray[numberIndex] = intArray[numberIndex] or numberWithSettledBit
|
||||
}
|
||||
intArray
|
||||
}
|
||||
}
|
||||
|
||||
fun isBitSet(possibleActiveBit: Int): Boolean {
|
||||
val numberIndex = possibleActiveBit shr 5
|
||||
if (numberIndex > intArray.size) return false
|
||||
val positionInNumber = possibleActiveBit and 31
|
||||
val numberWithSettledBit = 1 shl positionInNumber
|
||||
return intArray[numberIndex] and numberWithSettledBit != 0
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
package kotlin.js
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@PublishedApi
|
||||
internal fun <T : Enum<T>> enumValuesIntrinsic(): Array<T> =
|
||||
throw IllegalStateException("Should be replaced by compiler")
|
||||
@@ -51,3 +53,6 @@ internal annotation class JsFun(val code: String)
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
internal annotation class JsImplicitExport()
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
internal annotation class JsSubtypeCheckable(vararg val implements: KClass<*>)
|
||||
@@ -7,44 +7,45 @@ package kotlin.js
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
internal fun getPropertyCallableRef(name: String, paramCount: Int, type: dynamic, getter: dynamic, setter: dynamic): KProperty<*> {
|
||||
internal fun getPropertyCallableRef(
|
||||
name: String,
|
||||
paramCount: Int,
|
||||
superType: dynamic,
|
||||
getter: dynamic,
|
||||
setter: dynamic
|
||||
): KProperty<*> {
|
||||
getter.get = getter
|
||||
getter.set = setter
|
||||
getter.callableName = name
|
||||
return getPropertyRefClass(getter, getKPropMetadata(paramCount, setter, type)).unsafeCast<KProperty<*>>()
|
||||
return getPropertyRefClass(
|
||||
getter,
|
||||
getKPropMetadata(paramCount, setter),
|
||||
getInterfaceMaskFor(getter, superType)
|
||||
).unsafeCast<KProperty<*>>()
|
||||
}
|
||||
|
||||
internal fun getLocalDelegateReference(name: String, type: dynamic, mutable: Boolean, lambda: dynamic): KProperty<*> {
|
||||
return getPropertyCallableRef(name, 0, type, lambda, if (mutable) lambda else null)
|
||||
internal fun getLocalDelegateReference(name: String, superType: dynamic, mutable: Boolean, lambda: dynamic): KProperty<*> {
|
||||
return getPropertyCallableRef(name, 0, superType, lambda, if (mutable) lambda else null)
|
||||
}
|
||||
|
||||
private fun getPropertyRefClass(obj: Ctor, metadata: Metadata): dynamic {
|
||||
obj.`$metadata$` = metadata;
|
||||
obj.constructor = obj;
|
||||
private fun getPropertyRefClass(obj: Ctor, metadata: Metadata, imask: BitMask): dynamic {
|
||||
obj.`$metadata$` = metadata
|
||||
obj.constructor = obj
|
||||
obj.`$imask$` = imask
|
||||
return obj;
|
||||
}
|
||||
|
||||
private fun getKPropMetadata(paramCount: Int, setter: Any?, type: dynamic): dynamic {
|
||||
val mdata: Metadata = propertyRefClassMetadataCache[paramCount][if (setter == null) 0 else 1]
|
||||
private fun getInterfaceMaskFor(obj: Ctor, superType: dynamic): BitMask =
|
||||
obj.`$imask$` ?: implement(superType)
|
||||
|
||||
if (mdata.interfaces.size == 0) {
|
||||
mdata.interfaces.asDynamic().push(type)
|
||||
|
||||
if (mdata.interfacesCache == null) {
|
||||
mdata.interfacesCache = generateInterfaceCache()
|
||||
} else {
|
||||
mdata.interfacesCache!!.isComplete = false
|
||||
}
|
||||
|
||||
mdata.interfacesCache!!.extendCacheWithSingle(type)
|
||||
}
|
||||
|
||||
return mdata
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun getKPropMetadata(paramCount: Int, setter: Any?): dynamic {
|
||||
return propertyRefClassMetadataCache[paramCount][if (setter == null) 0 else 1]
|
||||
}
|
||||
|
||||
private fun metadataObject(): Metadata {
|
||||
val undef = js("undefined")
|
||||
return classMeta(undef, undef, undef, undef, undef, undef)
|
||||
return classMeta(undef, undef, undef, undef)
|
||||
}
|
||||
|
||||
private val propertyRefClassMetadataCache: Array<Array<dynamic>> = arrayOf<Array<dynamic>>(
|
||||
|
||||
@@ -5,36 +5,42 @@
|
||||
|
||||
package kotlin.js
|
||||
|
||||
internal fun interfaceMeta(
|
||||
internal fun setMetadataFor(
|
||||
ctor: Ctor,
|
||||
name: String?,
|
||||
interfaces: Array<Ctor>?,
|
||||
metadataConstructor: (name: String?, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?) -> Metadata,
|
||||
parent: Ctor?,
|
||||
interfaces: Array<dynamic>?,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?,
|
||||
): Metadata {
|
||||
return createMetadata("interface", name, interfaces, associatedObjectKey, associatedObjects, suspendArity, js("undefined"))
|
||||
suspendArity: Array<Int>?
|
||||
) {
|
||||
if (parent != null) {
|
||||
js("""
|
||||
ctor.prototype = Object.create(parent.prototype)
|
||||
ctor.prototype.constructor = ctor;
|
||||
""")
|
||||
}
|
||||
|
||||
val metadata = metadataConstructor(name, associatedObjectKey, associatedObjects, suspendArity)
|
||||
ctor.`$metadata$` = metadata
|
||||
|
||||
if (interfaces != null) {
|
||||
val receiver = if (metadata.iid != null) ctor else ctor.prototype
|
||||
receiver.`$imask$` = implement(*interfaces)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun objectMeta(
|
||||
name: String?,
|
||||
interfaces: Array<Ctor>?,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?,
|
||||
fastPrototype: Prototype?,
|
||||
): Metadata {
|
||||
return createMetadata("object", name, interfaces, associatedObjectKey, associatedObjects, suspendArity, fastPrototype)
|
||||
internal fun interfaceMeta(name: String?, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?): Metadata {
|
||||
return createMetadata("interface", name, associatedObjectKey, associatedObjects, suspendArity, generateInterfaceId())
|
||||
}
|
||||
|
||||
internal fun classMeta(
|
||||
name: String?,
|
||||
interfaces: Array<Ctor>?,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?,
|
||||
fastPrototype: Prototype?,
|
||||
): Metadata {
|
||||
return createMetadata("class", name, interfaces, associatedObjectKey, associatedObjects, suspendArity, fastPrototype)
|
||||
internal fun objectMeta(name: String?, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?): Metadata {
|
||||
return createMetadata("object", name, 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)
|
||||
}
|
||||
|
||||
// Seems like we need to disable this check if variables are used inside js annotation
|
||||
@@ -42,192 +48,103 @@ internal fun classMeta(
|
||||
private fun createMetadata(
|
||||
kind: String,
|
||||
name: String?,
|
||||
interfaces: Array<Ctor>?,
|
||||
associatedObjectKey: Number?,
|
||||
associatedObjects: dynamic,
|
||||
suspendArity: Array<Int>?,
|
||||
fastPrototype: Prototype?
|
||||
iid: Int?
|
||||
): Metadata {
|
||||
return js("""({
|
||||
kind: kind,
|
||||
simpleName: name,
|
||||
interfaceId: kind === "interface" ? -1 : undefined,
|
||||
interfaces: interfaces || [],
|
||||
associatedObjectKey: associatedObjectKey,
|
||||
associatedObjects: associatedObjects,
|
||||
suspendArity: suspendArity,
|
||||
fastPrototype: fastPrototype,
|
||||
${'$'}kClass$: undefined,
|
||||
interfacesCache: {
|
||||
isComplete: fastPrototype === undefined && (interfaces === undefined || interfaces.length === 0),
|
||||
implementInterfaceMemo: {}
|
||||
}
|
||||
iid: iid
|
||||
})""")
|
||||
}
|
||||
|
||||
internal external interface Metadata {
|
||||
val kind: String
|
||||
val interfaces: Array<Ctor>
|
||||
// This field gives fast access to the prototype of metadata owner (Object.getPrototypeOf())
|
||||
// Can be pre-initialized or lazy initialized and then should be immutable
|
||||
val simpleName: String?
|
||||
val associatedObjectKey: Number?
|
||||
val associatedObjects: dynamic
|
||||
var interfaceId: Number?
|
||||
var fastPrototype: Prototype?
|
||||
val suspendArity: Array<Int>?
|
||||
val iid: Int?
|
||||
|
||||
var `$kClass$`: dynamic
|
||||
// This is an object for memoization of a isInterfaceImpl function
|
||||
// Can be mutated quite often
|
||||
var interfacesCache: IsImplementsCache?
|
||||
}
|
||||
|
||||
// This is a flag for memoization of a isInterfaceImpl function
|
||||
internal external interface IsImplementsCache {
|
||||
var isComplete: Boolean
|
||||
val implementInterfaceMemo: dynamic
|
||||
}
|
||||
|
||||
internal external interface Ctor {
|
||||
var `$metadata$`: Metadata?
|
||||
var `$imask$`: BitMask?
|
||||
var `$metadata$`: Metadata
|
||||
var constructor: Ctor?
|
||||
val prototype: Prototype?
|
||||
val prototype: dynamic
|
||||
}
|
||||
|
||||
internal external interface Prototype {
|
||||
val constructor: Ctor?
|
||||
}
|
||||
private var iid: Int? = null
|
||||
|
||||
private var interfacesCounter = 0
|
||||
|
||||
private fun Ctor.getOrDefineInterfaceId(): Number? {
|
||||
val metadata = `$metadata$`.unsafeCast<Metadata>()
|
||||
val interfaceId = metadata.interfaceId ?: -1
|
||||
return if (interfaceId != -1) {
|
||||
interfaceId
|
||||
@Suppress("SMARTCAST_IMPOSSIBLE")
|
||||
internal fun generateInterfaceId(): Int {
|
||||
if (iid == null) {
|
||||
iid = 1
|
||||
} else {
|
||||
val result = interfacesCounter++
|
||||
metadata.interfaceId = result
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
private fun Ctor.getPrototype() = prototype?.let { js("Object").getPrototypeOf(it).unsafeCast<Prototype>() }
|
||||
|
||||
internal fun IsImplementsCache.extendCacheWith(cache: IsImplementsCache?) {
|
||||
val anotherInterfaceMemo = cache?.implementInterfaceMemo ?: return
|
||||
js("Object").assign(implementInterfaceMemo, anotherInterfaceMemo)
|
||||
}
|
||||
|
||||
internal fun IsImplementsCache.extendCacheWithSingle(intr: Ctor) {
|
||||
implementInterfaceMemo[intr.getOrDefineInterfaceId()] = true
|
||||
}
|
||||
|
||||
private fun fastGetPrototype(ctor: Ctor): Prototype? {
|
||||
return ctor.`$metadata$`?.run {
|
||||
if (fastPrototype == null) {
|
||||
fastPrototype = ctor.getPrototype()
|
||||
}
|
||||
fastPrototype
|
||||
} ?: ctor.getPrototype()
|
||||
}
|
||||
|
||||
private fun completeInterfaceCache(ctor: Ctor): IsImplementsCache? {
|
||||
val metadata = ctor.`$metadata$`
|
||||
|
||||
if (metadata != null && metadata.interfacesCache == null) {
|
||||
metadata.interfacesCache = generateInterfaceCache()
|
||||
iid += 1
|
||||
}
|
||||
|
||||
val interfacesCache = metadata?.interfacesCache
|
||||
|
||||
if (interfacesCache != null) {
|
||||
if (interfacesCache.isComplete == true) {
|
||||
return interfacesCache
|
||||
}
|
||||
|
||||
for (i in metadata.interfaces) {
|
||||
interfacesCache.extendCacheWithSingle(i)
|
||||
interfacesCache.extendCacheWith(completeInterfaceCache(i))
|
||||
}
|
||||
}
|
||||
|
||||
val parentInterfacesCache = fastGetPrototype(ctor)?.constructor?.let(::completeInterfaceCache)
|
||||
|
||||
return interfacesCache?.apply {
|
||||
extendCacheWith(parentInterfacesCache)
|
||||
isComplete = true
|
||||
} ?: parentInterfacesCache
|
||||
return iid
|
||||
}
|
||||
|
||||
// Old JS Backend
|
||||
internal fun generateInterfaceCache(): IsImplementsCache {
|
||||
return js("{ isComplete: false, implementInterfaceMemo: {} }")
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun getPrototypeOf(obj: dynamic) =
|
||||
js("Object.getPrototypeOf(obj)")
|
||||
|
||||
private fun searchForMetadata(obj: dynamic): Metadata? {
|
||||
if (obj == null) {
|
||||
return null
|
||||
}
|
||||
var metadata: Metadata? = obj.`$metadata$`
|
||||
var currentObject = getPrototypeOf(obj)
|
||||
|
||||
while (metadata == null && currentObject != null) {
|
||||
val currentConstructor = currentObject.constructor
|
||||
metadata = currentConstructor.`$metadata$`
|
||||
currentObject = getPrototypeOf(currentObject)
|
||||
}
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
private fun isInterfaceImpl(ctor: Ctor, iface: Ctor): Boolean {
|
||||
if (ctor === iface) {
|
||||
return true
|
||||
// TODO: Remove after 1.8 bootstrapping
|
||||
// Needed to pass all nodejs tests, because of stdlib compilation via bootstrapped compiler with old metadata format
|
||||
private fun verySlowIsInterfaceImpl(obj: dynamic, iface: dynamic): Boolean {
|
||||
val metadata = searchForMetadata(obj) ?: return false
|
||||
val interfaces = metadata.asDynamic().associatedObjectKey
|
||||
|
||||
if (
|
||||
interfaces != null &&
|
||||
(interfaces.indexOf(iface) != -1 || interfaces.some { x -> verySlowIsInterfaceImpl(x, iface) })
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
val metadata = ctor.`$metadata$`
|
||||
return verySlowIsInterfaceImpl(getPrototypeOf(obj), iface)
|
||||
}
|
||||
|
||||
if (metadata != null && metadata.interfacesCache == null) {
|
||||
metadata.interfacesCache = generateInterfaceCache()
|
||||
}
|
||||
|
||||
val interfacesCache = metadata?.interfacesCache
|
||||
|
||||
return if (interfacesCache != null) {
|
||||
if (!interfacesCache.isComplete) completeInterfaceCache(ctor)
|
||||
val interfaceId = iface.`$metadata$`?.interfaceId ?: return false
|
||||
!!interfacesCache.implementInterfaceMemo[interfaceId]
|
||||
} else {
|
||||
val constructor = fastGetPrototype(ctor)?.constructor ?: return false
|
||||
isInterfaceImpl(constructor, iface)
|
||||
}
|
||||
private fun isInterfaceImpl(obj: dynamic, iface: Int): Boolean {
|
||||
val mask: BitMask = obj.`$imask$`.unsafeCast<BitMask?>() ?: return false
|
||||
return mask.isBitSet(iface)
|
||||
}
|
||||
|
||||
internal fun isInterface(obj: dynamic, iface: dynamic): Boolean {
|
||||
val ctor = obj.constructor ?: return false
|
||||
return isInterfaceImpl(ctor, iface)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
internal interface ClassMetadata {
|
||||
val simpleName: String
|
||||
val interfaces: Array<dynamic>
|
||||
}
|
||||
|
||||
// TODO: replace `isInterface` with the following
|
||||
public fun isInterface(ctor: dynamic, IType: dynamic): Boolean {
|
||||
if (ctor === IType) return true
|
||||
|
||||
val metadata = ctor.`$metadata$`.unsafeCast<ClassMetadata?>()
|
||||
|
||||
if (metadata !== null) {
|
||||
val interfaces = metadata.interfaces
|
||||
for (i in interfaces) {
|
||||
if (isInterface(i, IType)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return if (obj.`$imask$` != null) {
|
||||
isInterfaceImpl(obj, iface.`$metadata$`.iid)
|
||||
} else {
|
||||
verySlowIsInterfaceImpl(obj, iface)
|
||||
}
|
||||
|
||||
var superPrototype = ctor.prototype
|
||||
if (superPrototype !== null) {
|
||||
superPrototype = js("Object.getPrototypeOf(superPrototype)")
|
||||
}
|
||||
|
||||
val superConstructor = if (superPrototype !== null) {
|
||||
superPrototype.constructor
|
||||
} else null
|
||||
|
||||
return superConstructor != null && isInterface(superConstructor, IType)
|
||||
}
|
||||
*/
|
||||
|
||||
internal fun isSuspendFunction(obj: dynamic, arity: Int): Boolean {
|
||||
if (jsTypeOf(obj) == "function") {
|
||||
@@ -237,7 +154,7 @@ internal fun isSuspendFunction(obj: dynamic, arity: Int): Boolean {
|
||||
|
||||
if (jsTypeOf(obj) == "object" && jsIn("${'$'}metadata${'$'}", obj.constructor)) {
|
||||
@Suppress("IMPLICIT_BOXING_IN_IDENTITY_EQUALS")
|
||||
return obj.constructor.unsafeCast<Ctor>().`$metadata$`?.suspendArity?.let {
|
||||
return obj.constructor.unsafeCast<Ctor>().`$metadata$`.suspendArity?.let {
|
||||
var result = false
|
||||
for (item in it) {
|
||||
if (arity == item) {
|
||||
@@ -288,7 +205,6 @@ internal fun isFloatArray(a: dynamic): Boolean = jsInstanceOf(a, js("Float32Arra
|
||||
internal fun isDoubleArray(a: dynamic): Boolean = jsInstanceOf(a, js("Float64Array"))
|
||||
internal fun isLongArray(a: dynamic): Boolean = isJsArray(a) && a.`$type$` === "LongArray"
|
||||
|
||||
|
||||
internal fun jsGetPrototypeOf(jsClass: dynamic) = js("Object").getPrototypeOf(jsClass)
|
||||
|
||||
internal fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean {
|
||||
@@ -320,8 +236,9 @@ internal fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean {
|
||||
return jsInstanceOf(obj, jsClass)
|
||||
}
|
||||
|
||||
if (klassMetadata.kind === "interface" && obj.constructor != null) {
|
||||
return isInterfaceImpl(obj.constructor, jsClass)
|
||||
if (klassMetadata.kind === "interface") {
|
||||
val iid = klassMetadata.iid.unsafeCast<Int?>()
|
||||
return iid?.let { isInterfaceImpl(obj, it) } ?: verySlowIsInterfaceImpl(obj, constructor)
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -329,14 +246,16 @@ internal fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean {
|
||||
|
||||
internal fun isNumber(a: dynamic) = jsTypeOf(a) == "number" || a is Long
|
||||
|
||||
@OptIn(JsIntrinsic::class)
|
||||
internal fun isComparable(value: dynamic): Boolean {
|
||||
var type = jsTypeOf(value)
|
||||
|
||||
return type == "string" ||
|
||||
type == "boolean" ||
|
||||
isNumber(value) ||
|
||||
isInterface(value, Comparable::class.js)
|
||||
isInterface(value, jsClassIntrinsic<Comparable<*>>())
|
||||
}
|
||||
|
||||
@OptIn(JsIntrinsic::class)
|
||||
internal fun isCharSequence(value: dynamic): Boolean =
|
||||
jsTypeOf(value) == "string" || isInterface(value, CharSequence::class.js)
|
||||
jsTypeOf(value) == "string" || isInterface(value, jsClassIntrinsic<CharSequence>())
|
||||
|
||||
@@ -9,8 +9,8 @@ import kotlin.reflect.js.internal.*
|
||||
@PublishedApi
|
||||
internal fun <T : Annotation> KClass<*>.findAssociatedObject(annotationClass: KClass<T>): Any? {
|
||||
return if (this is KClassImpl<*> && annotationClass is KClassImpl<T>) {
|
||||
val key = annotationClass.jClass.asDynamic().unsafeCast<Ctor>().`$metadata$`?.associatedObjectKey?.unsafeCast<Int>() ?: return null
|
||||
val map = jClass.asDynamic().unsafeCast<Ctor>().`$metadata$`?.associatedObjects ?: return null
|
||||
val key = annotationClass.jClass.asDynamic().`$metadata$`?.associatedObjectKey?.unsafeCast<Int>() ?: return null
|
||||
val map = jClass.asDynamic().`$metadata$`?.associatedObjects ?: return null
|
||||
val factory = map[key] ?: return null
|
||||
return factory()
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user