[K/JS] Support essential Kotlin collections (List, MutableList, Set, MutableSet, Map, MutableMap) for exporting into JS
^KT-34995 Fixed ^KT-44871 Fixed
This commit is contained in:
+6
@@ -224,6 +224,12 @@ object FirJsExportDeclarationChecker : FirBasicDeclarationChecker(MppCheckerKind
|
|||||||
|| isNothingOrNullableNothing
|
|| isNothingOrNullableNothing
|
||||||
|| isPrimitiveArray
|
|| isPrimitiveArray
|
||||||
|| isNonPrimitiveArray
|
|| isNonPrimitiveArray
|
||||||
|
|| isList
|
||||||
|
|| isMutableList
|
||||||
|
|| isSet
|
||||||
|
|| isMutableSet
|
||||||
|
|| isMap
|
||||||
|
|| isMutableMap
|
||||||
|
|
||||||
private fun validateDeclarationOnConsumableName(
|
private fun validateDeclarationOnConsumableName(
|
||||||
declaration: FirMemberDeclaration,
|
declaration: FirMemberDeclaration,
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ val ConeKotlinType.isNullableString: Boolean get() = isBuiltinType(StandardClass
|
|||||||
|
|
||||||
val ConeKotlinType.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
val ConeKotlinType.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
||||||
|
|
||||||
|
val ConeKotlinType.isList: Boolean get() = isBuiltinType(StandardClassIds.List, false)
|
||||||
|
val ConeKotlinType.isMutableList: Boolean get() = isBuiltinType(StandardClassIds.MutableList, false)
|
||||||
|
val ConeKotlinType.isSet: Boolean get() = isBuiltinType(StandardClassIds.Set, false)
|
||||||
|
val ConeKotlinType.isMutableSet: Boolean get() = isBuiltinType(StandardClassIds.MutableSet, false)
|
||||||
|
val ConeKotlinType.isMap: Boolean get() = isBuiltinType(StandardClassIds.Map, false)
|
||||||
|
val ConeKotlinType.isMutableMap: Boolean get() = isBuiltinType(StandardClassIds.MutableMap, false)
|
||||||
|
|
||||||
val ConeKotlinType.isUByte: Boolean get() = isBuiltinType(StandardClassIds.UByte, false)
|
val ConeKotlinType.isUByte: Boolean get() = isBuiltinType(StandardClassIds.UByte, false)
|
||||||
val ConeKotlinType.isUShort: Boolean get() = isBuiltinType(StandardClassIds.UShort, false)
|
val ConeKotlinType.isUShort: Boolean get() = isBuiltinType(StandardClassIds.UShort, false)
|
||||||
val ConeKotlinType.isUInt: Boolean get() = isBuiltinType(StandardClassIds.UInt, false)
|
val ConeKotlinType.isUInt: Boolean get() = isBuiltinType(StandardClassIds.UInt, false)
|
||||||
|
|||||||
@@ -349,13 +349,10 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("DoNotIntrinsify"))
|
context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("DoNotIntrinsify"))
|
||||||
val jsFunAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsFun"))
|
val jsFunAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsFun"))
|
||||||
val jsNameAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsName"))
|
val jsNameAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsName"))
|
||||||
|
val jsExportAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsExport"))
|
||||||
val jsGeneratorAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsGenerator"))
|
val jsGeneratorAnnotationSymbol = context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsGenerator"))
|
||||||
|
|
||||||
val jsExportAnnotationSymbol by lazy(LazyThreadSafetyMode.NONE) {
|
val jsExportIgnoreAnnotationSymbol by context.lazy2 {
|
||||||
context.symbolTable.descriptorExtension.referenceClass(context.getJsInternalClass("JsExport"))
|
|
||||||
}
|
|
||||||
|
|
||||||
val jsExportIgnoreAnnotationSymbol by lazy(LazyThreadSafetyMode.NONE) {
|
|
||||||
jsExportAnnotationSymbol.owner
|
jsExportAnnotationSymbol.owner
|
||||||
.findDeclaration<IrClass> { it.fqNameWhenAvailable == FqName("kotlin.js.JsExport.Ignore") }
|
.findDeclaration<IrClass> { it.fqNameWhenAvailable == FqName("kotlin.js.JsExport.Ignore") }
|
||||||
?.symbol ?: error("can't find kotlin.js.JsExport.Ignore annotation")
|
?.symbol ?: error("can't find kotlin.js.JsExport.Ignore annotation")
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ private val collectClassDefaultConstructorsPhase = makeIrModulePhase(
|
|||||||
description = "Collect classes default constructors to add it to metadata on code generating phase"
|
description = "Collect classes default constructors to add it to metadata on code generating phase"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val prepareCollectionsToExportLowering = makeIrModulePhase(
|
||||||
|
::PrepareCollectionsToExportLowering,
|
||||||
|
name = "PrepareCollectionsToExportLowering",
|
||||||
|
description = "Add @JsImplicitExport to exportable collections all the declarations which we don't want to export such as `Enum.entries` or `DataClass::componentN`",
|
||||||
|
)
|
||||||
|
|
||||||
private val preventExportOfSyntheticDeclarationsLowering = makeIrModulePhase(
|
private val preventExportOfSyntheticDeclarationsLowering = makeIrModulePhase(
|
||||||
::ExcludeSyntheticDeclarationsFromExportLowering,
|
::ExcludeSyntheticDeclarationsFromExportLowering,
|
||||||
name = "ExcludeSyntheticDeclarationsFromExportLowering",
|
name = "ExcludeSyntheticDeclarationsFromExportLowering",
|
||||||
@@ -746,7 +752,7 @@ private val escapedIdentifiersLowering = makeIrModulePhase(
|
|||||||
private val implicitlyExportedDeclarationsMarkingLowering = makeIrModulePhase(
|
private val implicitlyExportedDeclarationsMarkingLowering = makeIrModulePhase(
|
||||||
::ImplicitlyExportedDeclarationsMarkingLowering,
|
::ImplicitlyExportedDeclarationsMarkingLowering,
|
||||||
name = "ImplicitlyExportedDeclarationsMarkingLowering",
|
name = "ImplicitlyExportedDeclarationsMarkingLowering",
|
||||||
description = "Add @JsImplicitExport annotation to declarations which are not exported but are used inside other exported declarations as a type"
|
description = "Add @JsImplicitExport annotation to declarations which are not exported but are used inside other exported declarations as a type",
|
||||||
)
|
)
|
||||||
|
|
||||||
private val cleanupLoweringPhase = makeIrModulePhase<JsIrBackendContext>(
|
private val cleanupLoweringPhase = makeIrModulePhase<JsIrBackendContext>(
|
||||||
@@ -782,6 +788,7 @@ val mainFunctionCallWrapperLowering = makeIrModulePhase<JsIrBackendContext>(
|
|||||||
val loweringList = listOf<SimpleNamedCompilerPhase<JsIrBackendContext, IrModuleFragment, IrModuleFragment>>(
|
val loweringList = listOf<SimpleNamedCompilerPhase<JsIrBackendContext, IrModuleFragment, IrModuleFragment>>(
|
||||||
scriptRemoveReceiverLowering,
|
scriptRemoveReceiverLowering,
|
||||||
validateIrBeforeLowering,
|
validateIrBeforeLowering,
|
||||||
|
prepareCollectionsToExportLowering,
|
||||||
preventExportOfSyntheticDeclarationsLowering,
|
preventExportOfSyntheticDeclarationsLowering,
|
||||||
inventNamesForLocalClassesPhase,
|
inventNamesForLocalClassesPhase,
|
||||||
collectClassIdentifiersLowering,
|
collectClassIdentifiersLowering,
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
|||||||
import org.jetbrains.kotlin.backend.common.phaser.PhaserState
|
import org.jetbrains.kotlin.backend.common.phaser.PhaserState
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations
|
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.CompilationOutputs
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsGenerationGranularity
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsGenerationGranularity
|
||||||
|
|||||||
+9
-5
@@ -34,7 +34,10 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
|||||||
|
|
||||||
fun generateExport(file: IrPackageFragment): List<ExportedDeclaration> {
|
fun generateExport(file: IrPackageFragment): List<ExportedDeclaration> {
|
||||||
val namespaceFqName = file.packageFqName
|
val namespaceFqName = file.packageFqName
|
||||||
val exports = file.declarations.memoryOptimizedFlatMap { declaration -> listOfNotNull(exportDeclaration(declaration)) }
|
val exports = file.declarations.memoryOptimizedMapNotNull { declaration ->
|
||||||
|
declaration.takeIf { it.couldBeConvertedToExplicitExport() != true }?.let(::exportDeclaration)
|
||||||
|
}
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
exports.isEmpty() -> emptyList()
|
exports.isEmpty() -> emptyList()
|
||||||
!generateNamespacesForPackages || namespaceFqName.isRoot -> exports
|
!generateNamespacesForPackages || namespaceFqName.isRoot -> exports
|
||||||
@@ -306,6 +309,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
|||||||
val candidate = getExportCandidate(declaration) ?: continue
|
val candidate = getExportCandidate(declaration) ?: continue
|
||||||
if (isImplicitlyExportedClass && candidate !is IrClass) continue
|
if (isImplicitlyExportedClass && candidate !is IrClass) continue
|
||||||
if (!shouldDeclarationBeExportedImplicitlyOrExplicitly(candidate, context)) continue
|
if (!shouldDeclarationBeExportedImplicitlyOrExplicitly(candidate, context)) continue
|
||||||
|
if (candidate.isFakeOverride && klass.isInterface) continue
|
||||||
|
|
||||||
val processingResult = specialProcessing(candidate)
|
val processingResult = specialProcessing(candidate)
|
||||||
if (processingResult != null) {
|
if (processingResult != null) {
|
||||||
@@ -734,15 +738,15 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont
|
|||||||
if (declaration is IrClass && declaration.kind == ClassKind.ENUM_ENTRY)
|
if (declaration is IrClass && declaration.kind == ClassKind.ENUM_ENTRY)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
if (declaration.isJsExportIgnore())
|
||||||
|
return false
|
||||||
|
|
||||||
if (context.additionalExportedDeclarationNames.contains(declaration.fqNameWhenAvailable))
|
if (context.additionalExportedDeclarationNames.contains(declaration.fqNameWhenAvailable))
|
||||||
return true
|
return true
|
||||||
|
|
||||||
if (context.additionalExportedDeclarations.contains(declaration))
|
if (context.additionalExportedDeclarations.contains(declaration))
|
||||||
return true
|
return true
|
||||||
|
|
||||||
if (declaration.isJsExportIgnore())
|
|
||||||
return false
|
|
||||||
|
|
||||||
if (declaration is IrOverridableDeclaration<*>) {
|
if (declaration is IrOverridableDeclaration<*>) {
|
||||||
val overriddenNonEmpty = declaration
|
val overriddenNonEmpty = declaration
|
||||||
.overriddenSymbols
|
.overriddenSymbols
|
||||||
@@ -770,7 +774,7 @@ fun IrOverridableDeclaration<*>.isAllowedFakeOverriddenDeclaration(context: JsIr
|
|||||||
resolveFakeOverrideMaybeAbstract { it === this || it.parentClassOrNull?.isExported(context) != true }
|
resolveFakeOverrideMaybeAbstract { it === this || it.parentClassOrNull?.isExported(context) != true }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstExportedRealOverride?.parentClassOrNull.isExportedInterface(context)) {
|
if (firstExportedRealOverride?.parentClassOrNull.isExportedInterface(context) && firstExportedRealOverride?.isJsExportIgnore() != true) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-13
@@ -9,7 +9,9 @@ import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
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.ir.JsIrBuilder
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
|
import org.jetbrains.kotlin.ir.backend.js.lazy2
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.couldBeConvertedToExplicitExport
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
@@ -17,17 +19,18 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
|
|||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.constructors
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
|
|
||||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
||||||
import org.jetbrains.kotlin.utils.memoryOptimizedPlus
|
import org.jetbrains.kotlin.utils.memoryOptimizedPlus
|
||||||
|
|
||||||
class ImplicitlyExportedDeclarationsMarkingLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
class ImplicitlyExportedDeclarationsMarkingLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
private val strictImplicitExport = context.configuration.getBoolean(JSConfigurationKeys.GENERATE_STRICT_IMPLICIT_EXPORT)
|
private val strictImplicitExport = context.configuration.getBoolean(JSConfigurationKeys.GENERATE_STRICT_IMPLICIT_EXPORT)
|
||||||
|
private val jsExportCtor by context.lazy2 { context.intrinsics.jsExportAnnotationSymbol.constructors.single() }
|
||||||
|
private val jsImplicitExportCtor by context.lazy2 { context.intrinsics.jsImplicitExportAnnotationSymbol.constructors.single() }
|
||||||
|
|
||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
if (!strictImplicitExport || !declaration.isExported(context)) return null
|
if (!declaration.isExported(context)) return null
|
||||||
|
|
||||||
val implicitlyExportedDeclarations = when (declaration) {
|
val implicitlyExportedDeclarations = when (declaration) {
|
||||||
is IrFunction -> declaration.collectImplicitlyExportedDeclarations()
|
is IrFunction -> declaration.collectImplicitlyExportedDeclarations()
|
||||||
@@ -36,7 +39,7 @@ class ImplicitlyExportedDeclarationsMarkingLowering(private val context: JsIrBac
|
|||||||
else -> emptySet()
|
else -> emptySet()
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitlyExportedDeclarations.forEach { it.markWithJsImplicitExport() }
|
implicitlyExportedDeclarations.forEach { it.markWithJsImplicitExportOrUpgrade() }
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -80,19 +83,28 @@ class ImplicitlyExportedDeclarationsMarkingLowering(private val context: JsIrBac
|
|||||||
classifier is IrTypeParameterSymbol -> classifier.owner.superTypes.flatMap { it.collectImplicitlyExportedDeclarations() }
|
classifier is IrTypeParameterSymbol -> classifier.owner.superTypes.flatMap { it.collectImplicitlyExportedDeclarations() }
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
classifier is IrClassSymbol -> setOfNotNull(classifier.owner.takeIf { it.shouldBeMarkedWithImplicitExport() })
|
classifier is IrClassSymbol -> setOfNotNull(classifier.owner.takeIf { it.shouldBeMarkedWithImplicitExportOrUpgraded() })
|
||||||
else -> emptySet()
|
else -> emptySet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrDeclaration.shouldBeMarkedWithImplicitExport(): Boolean {
|
private fun IrDeclaration.shouldBeMarkedWithImplicitExportOrUpgraded(): Boolean {
|
||||||
return this is IrClass && !isExternal && !isExported(context) && !isJsImplicitExport()
|
return this is IrClass && !isExternal && !isExported(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrDeclaration.markWithJsImplicitExport() {
|
private fun IrDeclaration.markWithJsImplicitExportOrUpgrade() {
|
||||||
val jsImplicitExportCtor = context.intrinsics.jsImplicitExportAnnotationSymbol.constructors.single()
|
if (couldBeConvertedToExplicitExport() == true) {
|
||||||
annotations = annotations memoryOptimizedPlus JsIrBuilder.buildConstructorCall(jsImplicitExportCtor)
|
annotations = annotations.memoryOptimizedMap {
|
||||||
|
if (it.isAnnotation(JsAnnotations.jsImplicitExportFqn)) {
|
||||||
|
JsIrBuilder.buildConstructorCall(jsExportCtor)
|
||||||
|
} else it
|
||||||
|
}
|
||||||
|
} else if (strictImplicitExport) {
|
||||||
|
annotations = annotations memoryOptimizedPlus JsIrBuilder.buildConstructorCall(jsImplicitExportCtor).apply {
|
||||||
|
putValueArgument(0, false.toIrConst(context.irBuiltIns.booleanType))
|
||||||
|
}
|
||||||
|
|
||||||
parentClassOrNull?.takeIf { it.shouldBeMarkedWithImplicitExport() }?.markWithJsImplicitExport()
|
parentClassOrNull?.takeIf { it.shouldBeMarkedWithImplicitExportOrUpgraded() }?.markWithJsImplicitExportOrUpgrade()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* 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.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||||
|
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.util.isFakeOverride
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||||
|
import org.jetbrains.kotlin.ir.util.toIrConst
|
||||||
|
import org.jetbrains.kotlin.utils.memoryOptimizedPlus
|
||||||
|
|
||||||
|
// TODO: Remove the lowering and move annotations into stdlib after solving problem with tests on KLIB
|
||||||
|
class PrepareCollectionsToExportLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||||
|
private val jsNameCtor by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
|
context.intrinsics.jsNameAnnotationSymbol.primaryConstructorSymbol
|
||||||
|
}
|
||||||
|
private val jsExportIgnoreCtor by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
|
context.intrinsics.jsExportIgnoreAnnotationSymbol.primaryConstructorSymbol
|
||||||
|
}
|
||||||
|
private val jsImplicitExportCtor by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
|
context.intrinsics.jsImplicitExportAnnotationSymbol.primaryConstructorSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
private val IrClassSymbol.primaryConstructorSymbol: IrConstructorSymbol get() = owner.primaryConstructor!!.symbol
|
||||||
|
|
||||||
|
private val exportedMethodNames = setOf(
|
||||||
|
"asJsReadonlyArrayView",
|
||||||
|
"asJsArrayView",
|
||||||
|
"asJsReadonlySetView",
|
||||||
|
"asJsSetView",
|
||||||
|
"asJsReadonlyMapView",
|
||||||
|
"asJsMapView"
|
||||||
|
)
|
||||||
|
|
||||||
|
private val exportableSymbols = setOf(
|
||||||
|
context.ir.symbols.list,
|
||||||
|
context.ir.symbols.mutableList,
|
||||||
|
context.ir.symbols.set,
|
||||||
|
context.ir.symbols.mutableSet,
|
||||||
|
context.ir.symbols.map,
|
||||||
|
context.ir.symbols.mutableMap,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
|
if (declaration is IrClass && declaration.symbol in exportableSymbols) {
|
||||||
|
declaration.addJsName()
|
||||||
|
declaration.markWithJsImplicitExport()
|
||||||
|
|
||||||
|
declaration.declarations.forEach {
|
||||||
|
if (it !is IrDeclarationWithName || it.name.toString() !in exportedMethodNames) {
|
||||||
|
it.excludeFromJsExport()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrDeclaration.excludeFromJsExport() {
|
||||||
|
if (this is IrSimpleFunction) {
|
||||||
|
correspondingPropertySymbol?.owner?.excludeFromJsExport()
|
||||||
|
}
|
||||||
|
annotations = annotations memoryOptimizedPlus JsIrBuilder.buildConstructorCall(jsExportIgnoreCtor)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrDeclarationWithName.addJsName() {
|
||||||
|
annotations = annotations memoryOptimizedPlus JsIrBuilder.buildConstructorCall(jsNameCtor).apply {
|
||||||
|
putValueArgument(0, "Kt${name.asString()}".toIrConst(context.irBuiltIns.stringType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrDeclaration.markWithJsImplicitExport() {
|
||||||
|
annotations = annotations memoryOptimizedPlus JsIrBuilder.buildConstructorCall(jsImplicitExportCtor).apply {
|
||||||
|
putValueArgument(0, true.toIrConst(context.irBuiltIns.booleanType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,10 @@ object JsAnnotations {
|
|||||||
fun IrConstructorCall.getSingleConstStringArgument() =
|
fun IrConstructorCall.getSingleConstStringArgument() =
|
||||||
(getValueArgument(0) as IrConst<String>).value
|
(getValueArgument(0) as IrConst<String>).value
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun IrConstructorCall.getSingleConstBooleanArgument() =
|
||||||
|
(getValueArgument(0) as IrConst<Boolean>).value
|
||||||
|
|
||||||
fun IrAnnotationContainer.getJsModule(): String? =
|
fun IrAnnotationContainer.getJsModule(): String? =
|
||||||
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
|
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
|
||||||
|
|
||||||
@@ -63,6 +67,9 @@ fun IrAnnotationContainer.isJsExport(): Boolean =
|
|||||||
fun IrAnnotationContainer.isJsImplicitExport(): Boolean =
|
fun IrAnnotationContainer.isJsImplicitExport(): Boolean =
|
||||||
hasAnnotation(JsAnnotations.jsImplicitExportFqn)
|
hasAnnotation(JsAnnotations.jsImplicitExportFqn)
|
||||||
|
|
||||||
|
fun IrAnnotationContainer.couldBeConvertedToExplicitExport(): Boolean? =
|
||||||
|
getAnnotation(JsAnnotations.jsImplicitExportFqn)?.getSingleConstBooleanArgument()
|
||||||
|
|
||||||
fun IrAnnotationContainer.isJsExportIgnore(): Boolean =
|
fun IrAnnotationContainer.isJsExportIgnore(): Boolean =
|
||||||
hasAnnotation(JsAnnotations.jsExportIgnoreFqn)
|
hasAnnotation(JsAnnotations.jsExportIgnoreFqn)
|
||||||
|
|
||||||
|
|||||||
+24
@@ -54,3 +54,27 @@ fun foo5(<!NON_EXPORTABLE_TYPE("parameter; kotlin.Function1<kotlin.Unit, kotlin.
|
|||||||
@JsExport
|
@JsExport
|
||||||
fun foo6(x: (A) -> A) {
|
fun foo6(x: (A) -> A) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo7(x: List<Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo8(x: MutableList<Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo9(x: Set<Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo10(x: MutableSet<Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo11(x: Map<String, Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo12(x: MutableMap<String, Int>) {
|
||||||
|
}
|
||||||
|
|||||||
+24
@@ -54,3 +54,27 @@ fun foo5(<!NON_EXPORTABLE_TYPE("parameter; (Unit) -> Unit")!>x: (Unit) -> Unit<!
|
|||||||
@JsExport
|
@JsExport
|
||||||
fun foo6(x: (A) -> A) {
|
fun foo6(x: (A) -> A) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo7(x: List<Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo8(x: MutableList<Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo9(x: Set<Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo10(x: MutableSet<Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo11(x: Map<String, Int>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun foo12(x: MutableMap<String, Int>) {
|
||||||
|
}
|
||||||
|
|||||||
+6
@@ -5,11 +5,17 @@ package foo {
|
|||||||
@kotlin.js.JsExport public var x2: foo.C
|
@kotlin.js.JsExport public var x2: foo.C
|
||||||
@kotlin.js.JsExport public fun bar(): foo.C
|
@kotlin.js.JsExport public fun bar(): foo.C
|
||||||
@kotlin.js.JsExport public fun foo(/*0*/ x: foo.C): kotlin.Unit
|
@kotlin.js.JsExport public fun foo(/*0*/ x: foo.C): kotlin.Unit
|
||||||
|
@kotlin.js.JsExport public fun foo10(/*0*/ x: kotlin.collections.MutableSet<kotlin.Int>): kotlin.Unit
|
||||||
|
@kotlin.js.JsExport public fun foo11(/*0*/ x: kotlin.collections.Map<kotlin.String, kotlin.Int>): kotlin.Unit
|
||||||
|
@kotlin.js.JsExport public fun foo12(/*0*/ x: kotlin.collections.MutableMap<kotlin.String, kotlin.Int>): kotlin.Unit
|
||||||
@kotlin.js.JsExport public fun foo2(): kotlin.Unit
|
@kotlin.js.JsExport public fun foo2(): kotlin.Unit
|
||||||
@kotlin.js.JsExport public fun foo3(/*0*/ x: kotlin.Unit): kotlin.Unit
|
@kotlin.js.JsExport public fun foo3(/*0*/ x: kotlin.Unit): kotlin.Unit
|
||||||
@kotlin.js.JsExport public fun foo4(/*0*/ x: () -> kotlin.Unit): kotlin.Unit
|
@kotlin.js.JsExport public fun foo4(/*0*/ x: () -> kotlin.Unit): kotlin.Unit
|
||||||
@kotlin.js.JsExport public fun foo5(/*0*/ x: (kotlin.Unit) -> kotlin.Unit): kotlin.Unit
|
@kotlin.js.JsExport public fun foo5(/*0*/ x: (kotlin.Unit) -> kotlin.Unit): kotlin.Unit
|
||||||
@kotlin.js.JsExport public fun foo6(/*0*/ x: (foo.A) -> foo.A): kotlin.Unit
|
@kotlin.js.JsExport public fun foo6(/*0*/ x: (foo.A) -> foo.A): kotlin.Unit
|
||||||
|
@kotlin.js.JsExport public fun foo7(/*0*/ x: kotlin.collections.List<kotlin.Int>): kotlin.Unit
|
||||||
|
@kotlin.js.JsExport public fun foo8(/*0*/ x: kotlin.collections.MutableList<kotlin.Int>): kotlin.Unit
|
||||||
|
@kotlin.js.JsExport public fun foo9(/*0*/ x: kotlin.collections.Set<kotlin.Int>): kotlin.Unit
|
||||||
|
|
||||||
@kotlin.js.JsExport public final class A {
|
@kotlin.js.JsExport public final class A {
|
||||||
public constructor A(/*0*/ x: foo.C, /*1*/ y: foo.C)
|
public constructor A(/*0*/ x: foo.C, /*1*/ y: foo.C)
|
||||||
|
|||||||
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// MUTE_LL_FIR: KT-65218
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
// FIR_DUMP
|
// FIR_DUMP
|
||||||
import kotlin.reflect.*
|
import kotlin.reflect.*
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// MUTE_LL_FIR: KT-65218
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
// FIR_DUMP
|
// FIR_DUMP
|
||||||
import kotlin.reflect.*
|
import kotlin.reflect.*
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// FIR_IDENTICAL
|
// FIR_IDENTICAL
|
||||||
// KT-64271
|
// KT-64271
|
||||||
// IGNORE_BACKEND_K2: JVM_IR
|
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6
|
||||||
|
// IGNORE_BACKEND_K2: JVM_IR, JS_IR, JS_IR_ES6
|
||||||
|
// ^ Set has js specific methods
|
||||||
|
|
||||||
inline class IT(val x: Int)
|
inline class IT(val x: Int)
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -1,5 +1,7 @@
|
|||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// IGNORE_BACKEND_K2: JS_IR NATIVE
|
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6
|
||||||
|
// ^ MutableList has js specific methods
|
||||||
|
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6, NATIVE
|
||||||
// ^ the order of fake overrides is different on K2
|
// ^ the order of fake overrides is different on K2
|
||||||
|
|
||||||
interface X {
|
interface X {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
|
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6
|
||||||
|
// ^ Map has js specific methods
|
||||||
// IGNORE_BACKEND_K2: JS_IR
|
// IGNORE_BACKEND_K2: JS_IR
|
||||||
// IGNORE_BACKEND_K2: NATIVE
|
// IGNORE_BACKEND_K2: NATIVE
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.js.resolve.diagnostics
|
|||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind.*
|
import org.jetbrains.kotlin.descriptors.ClassKind.*
|
||||||
@@ -14,6 +15,7 @@ import org.jetbrains.kotlin.js.common.RESERVED_KEYWORDS
|
|||||||
import org.jetbrains.kotlin.js.common.SPECIAL_KEYWORDS
|
import org.jetbrains.kotlin.js.common.SPECIAL_KEYWORDS
|
||||||
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
import org.jetbrains.kotlin.js.naming.NameSuggestion
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
@@ -190,9 +192,15 @@ class JsExportDeclarationChecker(private val includeUnsignedNumbers: Boolean) :
|
|||||||
KotlinBuiltIns.isString(nonNullable) ||
|
KotlinBuiltIns.isString(nonNullable) ||
|
||||||
(nonNullable.isPrimitiveNumberOrNullableType() && !nonNullable.isLong()) ||
|
(nonNullable.isPrimitiveNumberOrNullableType() && !nonNullable.isLong()) ||
|
||||||
nonNullable.isNothingOrNullableNothing() ||
|
nonNullable.isNothingOrNullableNothing() ||
|
||||||
KotlinBuiltIns.isArray(nonNullable) ||
|
(includeUnsignedNumbers && KotlinBuiltIns.isUnsignedNumber(nonNullable)) ||
|
||||||
KotlinBuiltIns.isPrimitiveArray(nonNullable) ||
|
KotlinBuiltIns.isArray(this) ||
|
||||||
(includeUnsignedNumbers && KotlinBuiltIns.isUnsignedNumber(nonNullable))
|
KotlinBuiltIns.isPrimitiveArray(this) ||
|
||||||
|
KotlinBuiltIns.isConstructedFromGivenClass(this, StandardNames.FqNames.list) ||
|
||||||
|
KotlinBuiltIns.isConstructedFromGivenClass(this, StandardNames.FqNames.mutableList) ||
|
||||||
|
KotlinBuiltIns.isConstructedFromGivenClass(this, StandardNames.FqNames.set) ||
|
||||||
|
KotlinBuiltIns.isConstructedFromGivenClass(this, StandardNames.FqNames.mutableSet) ||
|
||||||
|
KotlinBuiltIns.isConstructedFromGivenClass(this, StandardNames.FqNames.map) ||
|
||||||
|
KotlinBuiltIns.isConstructedFromGivenClass(this, StandardNames.FqNames.mutableMap)
|
||||||
|
|
||||||
if (isPrimitiveExportableType) return true
|
if (isPrimitiveExportableType) return true
|
||||||
|
|
||||||
|
|||||||
Generated
+32
@@ -57,6 +57,38 @@ public class IrJsES6TypeScriptExportTestGenerated extends AbstractIrJsES6TypeScr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("js/js.translator/testData/typescript-export/collections")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Collections {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInCollections() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/collections"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("collections.kt")
|
||||||
|
public void testCollections() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/typescript-export/collections/collections.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("js/js.translator/testData/typescript-export/collections-in-exported-file")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Collections_in_exported_file {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInCollections_in_exported_file() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/collections-in-exported-file"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("collections.kt")
|
||||||
|
public void testCollections() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/typescript-export/collections-in-exported-file/collections.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("js/js.translator/testData/typescript-export/constructors")
|
@TestMetadata("js/js.translator/testData/typescript-export/constructors")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
Generated
+32
@@ -57,6 +57,38 @@ public class IrJsTypeScriptExportTestGenerated extends AbstractIrJsTypeScriptExp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("js/js.translator/testData/typescript-export/collections")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Collections {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInCollections() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/collections"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("collections.kt")
|
||||||
|
public void testCollections() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/typescript-export/collections/collections.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
@TestMetadata("js/js.translator/testData/typescript-export/collections-in-exported-file")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
public class Collections_in_exported_file {
|
||||||
|
@Test
|
||||||
|
public void testAllFilesPresentInCollections_in_exported_file() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/collections-in-exported-file"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("collections.kt")
|
||||||
|
public void testCollections() throws Exception {
|
||||||
|
runTest("js/js.translator/testData/typescript-export/collections-in-exported-file/collections.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("js/js.translator/testData/typescript-export/constructors")
|
@TestMetadata("js/js.translator/testData/typescript-export/constructors")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
declare namespace JS_TESTS {
|
||||||
|
type Nullable<T> = T | null | undefined
|
||||||
|
namespace kotlin.collections {
|
||||||
|
interface KtList<E> /* extends kotlin.collections.Collection<E> */ {
|
||||||
|
asJsReadonlyArrayView(): ReadonlyArray<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtList": unique symbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface KtMap<K, V> {
|
||||||
|
asJsReadonlyMapView(): ReadonlyMap<K, V>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtMap": unique symbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface KtMutableList<E> extends kotlin.collections.KtList<E>/*, kotlin.collections.MutableCollection<E> */ {
|
||||||
|
asJsArrayView(): Array<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtMutableList": unique symbol;
|
||||||
|
} & kotlin.collections.KtList<E>["__doNotUseOrImplementIt"];
|
||||||
|
}
|
||||||
|
interface KtSet<E> /* extends kotlin.collections.Collection<E> */ {
|
||||||
|
asJsReadonlySetView(): ReadonlySet<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtSet": unique symbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface KtMutableSet<E> extends kotlin.collections.KtSet<E>/*, kotlin.collections.MutableCollection<E> */ {
|
||||||
|
asJsSetView(): Set<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtMutableSet": unique symbol;
|
||||||
|
} & kotlin.collections.KtSet<E>["__doNotUseOrImplementIt"];
|
||||||
|
}
|
||||||
|
interface KtMutableMap<K, V> extends kotlin.collections.KtMap<K, V> {
|
||||||
|
asJsMapView(): Map<K, V>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtMutableMap": unique symbol;
|
||||||
|
} & kotlin.collections.KtMap<K, V>["__doNotUseOrImplementIt"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function provideList(): kotlin.collections.KtList<number>;
|
||||||
|
function provideMutableList(): kotlin.collections.KtMutableList<number>;
|
||||||
|
function provideSet(): kotlin.collections.KtSet<number>;
|
||||||
|
function provideMutableSet(): kotlin.collections.KtMutableSet<number>;
|
||||||
|
function provideMap(): kotlin.collections.KtMap<string, number>;
|
||||||
|
function provideMutableMap(): kotlin.collections.KtMutableMap<string, number>;
|
||||||
|
function consumeList(list: kotlin.collections.KtList<number>): boolean;
|
||||||
|
function consumeMutableList(list: kotlin.collections.KtMutableList<number>): boolean;
|
||||||
|
function consumeSet(list: kotlin.collections.KtSet<number>): boolean;
|
||||||
|
function consumeMutableSet(list: kotlin.collections.KtMutableSet<number>): boolean;
|
||||||
|
function consumeMap(map: kotlin.collections.KtMap<string, number>): boolean;
|
||||||
|
function consumeMutableMap(map: kotlin.collections.KtMutableMap<string, number>): boolean;
|
||||||
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
/** This file is generated by {@link :js:js.test:generateTypeScriptJsExportOnFileTests} task. DO NOT MODIFY MANUALLY */
|
||||||
|
|
||||||
|
// CHECK_TYPESCRIPT_DECLARATIONS
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// WITH_STDLIB
|
||||||
|
// SKIP_MINIFICATION
|
||||||
|
// SKIP_NODE_JS
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
|
||||||
|
// TODO fix statics export in DCE-driven mode
|
||||||
|
// SKIP_DCE_DRIVEN
|
||||||
|
|
||||||
|
// MODULE: JS_TESTS
|
||||||
|
// FILE: f1.kt
|
||||||
|
|
||||||
|
@file:JsExport
|
||||||
|
|
||||||
|
|
||||||
|
fun provideList(): List<Int> = listOf(1, 2, 3)
|
||||||
|
|
||||||
|
|
||||||
|
fun provideMutableList(): MutableList<Int> = mutableListOf(4, 5, 6)
|
||||||
|
|
||||||
|
|
||||||
|
fun provideSet(): Set<Int> = setOf(1, 2, 3)
|
||||||
|
|
||||||
|
|
||||||
|
fun provideMutableSet(): MutableSet<Int> = mutableSetOf(4, 5, 6)
|
||||||
|
|
||||||
|
|
||||||
|
fun provideMap(): Map<String, Int> = mapOf("a" to 1, "b" to 2, "c" to 3)
|
||||||
|
|
||||||
|
|
||||||
|
fun provideMutableMap(): MutableMap<String, Int> = mutableMapOf("d" to 4, "e" to 5, "f" to 6)
|
||||||
|
|
||||||
|
|
||||||
|
fun consumeList(list: List<Int>) = list.toString() == "[1, 2, 3]"
|
||||||
|
|
||||||
|
|
||||||
|
fun consumeMutableList(list: MutableList<Int>): Boolean {
|
||||||
|
list.add(7)
|
||||||
|
return list.toString() == "[4, 5, 6, 7]"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun consumeSet(list: Set<Int>) = list.toString() == "[1, 2, 3]"
|
||||||
|
|
||||||
|
|
||||||
|
fun consumeMutableSet(list: MutableSet<Int>): Boolean {
|
||||||
|
list.add(7)
|
||||||
|
return list.toString() == "[4, 5, 6, 7]"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun consumeMap(map: Map<String, Int>) = map.toString() == "{a=1, b=2, c=3}"
|
||||||
|
|
||||||
|
|
||||||
|
fun consumeMutableMap(map: MutableMap<String, Int>): Boolean {
|
||||||
|
map["g"] = 7
|
||||||
|
return map.toString() == "{d=4, e=5, f=6, g=7}"
|
||||||
|
}
|
||||||
Vendored
+213
@@ -0,0 +1,213 @@
|
|||||||
|
import provideList = JS_TESTS.provideList;
|
||||||
|
import consumeList = JS_TESTS.consumeList;
|
||||||
|
import provideMutableList = JS_TESTS.provideMutableList;
|
||||||
|
import consumeMutableList = JS_TESTS.consumeMutableList;
|
||||||
|
import provideMutableSet = JS_TESTS.provideMutableSet;
|
||||||
|
import provideSet = JS_TESTS.provideSet;
|
||||||
|
import consumeSet = JS_TESTS.consumeSet;
|
||||||
|
import consumeMutableSet = JS_TESTS.consumeMutableSet;
|
||||||
|
import provideMap = JS_TESTS.provideMap;
|
||||||
|
import consumeMap = JS_TESTS.consumeMap;
|
||||||
|
import provideMutableMap = JS_TESTS.provideMutableMap;
|
||||||
|
import consumeMutableMap = JS_TESTS.consumeMutableMap;
|
||||||
|
|
||||||
|
function assert(condition: boolean, message: string) {
|
||||||
|
if (!condition) {
|
||||||
|
throw message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertThrow(fn: () => void, message: string) {
|
||||||
|
try {
|
||||||
|
fn();
|
||||||
|
throw message;
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function box(): string {
|
||||||
|
testImmutableList()
|
||||||
|
testImmutableSet()
|
||||||
|
testImmutableMap()
|
||||||
|
|
||||||
|
testMutableList()
|
||||||
|
testMutableSet()
|
||||||
|
testMutableMap()
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
function testImmutableList() {
|
||||||
|
const list = provideList()
|
||||||
|
const listReadonlyArrayView = list.asJsReadonlyArrayView()
|
||||||
|
|
||||||
|
assert(listReadonlyArrayView[0] == 1, "Problem with accessing of element in immutable list readonly array view")
|
||||||
|
assert(listReadonlyArrayView["0"] == 1, "Problem with accessing of element in immutable list readonly array view by string")
|
||||||
|
assert(listReadonlyArrayView.map(x => x + 1).join("") == "234", "Problem with immutable list readonly array view")
|
||||||
|
assert(consumeList(list), "Problem with consumption of a Kotlin list")
|
||||||
|
assertThrow(() => { (listReadonlyArrayView as Array<number>)[1] = 4 }, "Immutable list readonly array view have ability to mutate the list by direct set")
|
||||||
|
assertThrow(() => { (listReadonlyArrayView as Array<number>).push(4) }, "Immutable list readonly array view have ability to mutate the list by 'push'")
|
||||||
|
assertThrow(() => { (listReadonlyArrayView as Array<number>).pop() }, "Immutable list readonly array view have ability to mutate the list by 'pop'")
|
||||||
|
// @ts-expect-error
|
||||||
|
assertThrow(() => { listReadonlyArrayView["foo"] }, "Immutable list getting a random index from its readonly array view")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMutableList() {
|
||||||
|
const mutableList = provideMutableList()
|
||||||
|
const mutableListReadonlyArrayView = mutableList.asJsReadonlyArrayView()
|
||||||
|
|
||||||
|
assert(mutableListReadonlyArrayView[0] == 4, "Problem with accessing of element in mutable list readonly array view")
|
||||||
|
assert(mutableListReadonlyArrayView["0"] == 4, "Problem with accessing of element in immutable list readonly array view by string")
|
||||||
|
assert(mutableListReadonlyArrayView.map(x => x + 1).join("") == "567", "Problem with mutable list readonly array view")
|
||||||
|
assert(!consumeList(mutableList), "Problem with consumption of a Kotlin mutable list as a list")
|
||||||
|
assert(consumeMutableList(mutableList), "Problem with consumption of a Kotlin mutable list as a mutable list")
|
||||||
|
assert(mutableListReadonlyArrayView.map(x => x + 1).join("") == "5678", "Problem with mutable list readonly array view after original list is mutated")
|
||||||
|
assertThrow(() => { (mutableListReadonlyArrayView as Array<number>)[1] = 4 }, "Mutable list readonly array view have ability to mutate the list by direct set")
|
||||||
|
assertThrow(() => { (mutableListReadonlyArrayView as Array<number>).push(4) }, "Mutable list readonly array view have ability to mutate the list by 'push'")
|
||||||
|
assertThrow(() => { (mutableListReadonlyArrayView as Array<number>).pop() }, "Mutable list readonly array view have ability to mutate the list by 'pop'")
|
||||||
|
// @ts-expect-error
|
||||||
|
assertThrow(() => { mutableListReadonlyArrayView["foo"] }, "Immutable list getting a random index from its readonly array view")
|
||||||
|
|
||||||
|
const mutableListArrayView = mutableList.asJsArrayView()
|
||||||
|
mutableListArrayView.pop()
|
||||||
|
|
||||||
|
assert(mutableListArrayView[0] == 4, "Problem with accessing of element in mutable list array view")
|
||||||
|
assert(mutableListArrayView["0"] == 4, "Problem with accessing of element in mutable list array view by string")
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "567", "Problem with mutable list array view")
|
||||||
|
assert(consumeMutableList(mutableList), "Problem with consumption of a Kotlin mutable list as a mutable list")
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "5678", "Problem with mutable list array view after original list is mutated")
|
||||||
|
// @ts-expect-error
|
||||||
|
assertThrow(() => { mutableListArrayView["foo"] = 4 }, "Mutable list setting a random index in its array view")
|
||||||
|
|
||||||
|
mutableListArrayView.shift()
|
||||||
|
mutableListArrayView.unshift(9)
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "10678", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView.sort()
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "67810", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView.push(3)
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "678104", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView[3] = 4
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "67854", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView["3"] = 6
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "67874", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView.length = 3
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "678", "Problem with mutable list array view after the view is mutated after size decreased")
|
||||||
|
assert(mutableListReadonlyArrayView.map(x => x + 1).join("") == "678", "Problem with mutable list readonly array view after size decreased")
|
||||||
|
|
||||||
|
assertThrow(() => { mutableListArrayView.length = 5 }, "Mutable list view size increasing works, but should not")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testImmutableSet() {
|
||||||
|
const set = provideSet()
|
||||||
|
const setReadonlyView = set.asJsReadonlySetView();
|
||||||
|
|
||||||
|
assert(setReadonlyView.has(1), "Problem with accessing element of readonly view")
|
||||||
|
assert(joinSetOrMap(setReadonlyView) == "123", "Problem with readonly view iterator")
|
||||||
|
assert(consumeSet(set), "Problem with consumption of a Kotlin set")
|
||||||
|
assertThrow(() => { (setReadonlyView as Set<number>).add(4) }, "Set readonly view have ability to mutate the set by 'add'")
|
||||||
|
assertThrow(() => { (setReadonlyView as Set<number>).delete(4) }, "Set readonly view have ability to mutate the set by 'delete'")
|
||||||
|
assertThrow(() => { (setReadonlyView as Set<number>).clear() }, "Set readonly view have ability to mutate the set by 'clear'")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMutableSet() {
|
||||||
|
const mutableSet = provideMutableSet()
|
||||||
|
const mutableSetReadonlyView = mutableSet.asJsReadonlySetView()
|
||||||
|
|
||||||
|
assert(mutableSetReadonlyView.has(4), "Problem with accessing element of mutable set readonly view")
|
||||||
|
assert(joinSetOrMap(mutableSetReadonlyView) == "456", "Problem with mutable set readonly view iterator")
|
||||||
|
assert(!consumeSet(mutableSet), "Problem with consumption of a Kotlin mutable set as a set")
|
||||||
|
assert(consumeMutableSet(mutableSet), "Problem with consumption of a Kotlin mutable set as a mutable set")
|
||||||
|
assert(joinSetOrMap(mutableSetReadonlyView) == "4567", "Problem with mutable set readonly view after original set is mutated")
|
||||||
|
assertThrow(() => { (mutableSetReadonlyView as Set<number>).add(4) }, "Mutable set readonly view have ability to mutate the set by 'add'")
|
||||||
|
assertThrow(() => { (mutableSetReadonlyView as Set<number>).delete(4) }, "Mutable set readonly view have ability to mutate the set by 'delete'")
|
||||||
|
assertThrow(() => { (mutableSetReadonlyView as Set<number>).clear() }, "Mutable set readonly view have ability to mutate the set by 'clear'")
|
||||||
|
|
||||||
|
const mutableSetView = mutableSet.asJsSetView()
|
||||||
|
|
||||||
|
mutableSetView.delete(7)
|
||||||
|
|
||||||
|
assert(mutableSetView.has(4), "Problem with accessing element of mutable set view")
|
||||||
|
assert(joinSetOrMap(mutableSetView) == "456", "Problem with mutable set view")
|
||||||
|
assert(consumeMutableSet(mutableSet), "Problem with consumption of a Kotlin mutable set as a mutable set")
|
||||||
|
assert(joinSetOrMap(mutableSetView) == "4567", "Problem with mutable set view after original set is mutated")
|
||||||
|
|
||||||
|
mutableSetView.add(8)
|
||||||
|
|
||||||
|
assert(joinSetOrMap(mutableSetView) == "45678", "Problem with mutable set view after the view is mutated")
|
||||||
|
|
||||||
|
mutableSetView.clear()
|
||||||
|
|
||||||
|
assert(joinSetOrMap(mutableSetView) == "", "Problem with mutable set view after the view is mutated")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testImmutableMap() {
|
||||||
|
const map = provideMap()
|
||||||
|
const mapReadonlyView = map.asJsReadonlyMapView()
|
||||||
|
|
||||||
|
assert(mapReadonlyView.has("a"), "Problem with accessing element in map readonly view")
|
||||||
|
assert(mapReadonlyView.get("a") == 1, "Problem with accessing element in map readonly view")
|
||||||
|
assert(joinSetOrMap(mapReadonlyView) == "[a:1][b:2][c:3]", "Problem with map readonly view iterator")
|
||||||
|
assert(consumeMap(map), "Problem with consumption of a Kotlin map")
|
||||||
|
assertThrow(() => { (mapReadonlyView as Map<string, number>).set("d", 4) }, "Map readonly view have ability to mutate the map by 'set'")
|
||||||
|
assertThrow(() => { (mapReadonlyView as Map<string, number>).delete("a") }, "Map readonly view have ability to mutate the map by 'delete'")
|
||||||
|
assertThrow(() => { (mapReadonlyView as Map<string, number>).clear() }, "Map readonly view have ability to mutate the map by 'clear'")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMutableMap() {
|
||||||
|
const mutableMap = provideMutableMap()
|
||||||
|
const mutableMapReadonlyView = mutableMap.asJsReadonlyMapView()
|
||||||
|
|
||||||
|
assert(mutableMapReadonlyView.has("d"), "Problem with accessing element in mutable map readonly view")
|
||||||
|
assert(mutableMapReadonlyView.get("d") == 4, "Problem with accessing element in mutable map readonly view")
|
||||||
|
assert(joinSetOrMap(mutableMapReadonlyView) == "[d:4][e:5][f:6]", "Problem with mutable map readonly view")
|
||||||
|
assert(!consumeMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a map")
|
||||||
|
assert(consumeMutableMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a mutable map")
|
||||||
|
assert(joinSetOrMap(mutableMapReadonlyView) == "[d:4][e:5][f:6][g:7]", "Problem with mutable map readonly view after original map is mutated")
|
||||||
|
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).set("d", 4) }, "Mutable map readonly view have ability to mutate the map by 'set'")
|
||||||
|
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).delete("a") }, "Mutable map readonly view have ability to mutate the map by 'delete'")
|
||||||
|
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).clear() }, "Mutable map readonly view have ability to mutate the map by 'clear'")
|
||||||
|
|
||||||
|
const mutableMapView = mutableMap.asJsMapView()
|
||||||
|
|
||||||
|
mutableMapView.delete("g")
|
||||||
|
|
||||||
|
assert(mutableMapView.has("d"), "Problem with accessing element in mutable map view")
|
||||||
|
assert(mutableMapView.get("d") == 4, "Problem with accessing element in mutable map view")
|
||||||
|
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6]", "Problem with mutable map view")
|
||||||
|
assert(consumeMutableMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a mutable map")
|
||||||
|
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6][g:7]", "Problem with mutable map view after original map is mutated")
|
||||||
|
|
||||||
|
mutableMapView.set("h", 8)
|
||||||
|
|
||||||
|
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6][g:7][h:8]", "Problem with mutable map view after the view is mutated")
|
||||||
|
|
||||||
|
mutableMapView.clear()
|
||||||
|
|
||||||
|
assert(joinSetOrMap(mutableMapView) == "", "Problem with mutable map view after the view is mutated")
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinSetOrMap(setOrMap: ReadonlySet<number> | ReadonlyMap<string, number>): string {
|
||||||
|
let result = ""
|
||||||
|
|
||||||
|
if (setOrMap instanceof Set) {
|
||||||
|
setOrMap.forEach((a: any) => {
|
||||||
|
result += a
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setOrMap.forEach((key: any, value: any) => {
|
||||||
|
result += `[${key}:${value}]`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"include": [ "./*" ],
|
||||||
|
"extends": "../common.tsconfig.json"
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
declare namespace JS_TESTS {
|
||||||
|
type Nullable<T> = T | null | undefined
|
||||||
|
namespace kotlin.collections {
|
||||||
|
interface KtList<E> /* extends kotlin.collections.Collection<E> */ {
|
||||||
|
asJsReadonlyArrayView(): ReadonlyArray<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtList": unique symbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface KtMap<K, V> {
|
||||||
|
asJsReadonlyMapView(): ReadonlyMap<K, V>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtMap": unique symbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface KtMutableList<E> extends kotlin.collections.KtList<E>/*, kotlin.collections.MutableCollection<E> */ {
|
||||||
|
asJsArrayView(): Array<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtMutableList": unique symbol;
|
||||||
|
} & kotlin.collections.KtList<E>["__doNotUseOrImplementIt"];
|
||||||
|
}
|
||||||
|
interface KtSet<E> /* extends kotlin.collections.Collection<E> */ {
|
||||||
|
asJsReadonlySetView(): ReadonlySet<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtSet": unique symbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface KtMutableSet<E> extends kotlin.collections.KtSet<E>/*, kotlin.collections.MutableCollection<E> */ {
|
||||||
|
asJsSetView(): Set<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtMutableSet": unique symbol;
|
||||||
|
} & kotlin.collections.KtSet<E>["__doNotUseOrImplementIt"];
|
||||||
|
}
|
||||||
|
interface KtMutableMap<K, V> extends kotlin.collections.KtMap<K, V> {
|
||||||
|
asJsMapView(): Map<K, V>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtMutableMap": unique symbol;
|
||||||
|
} & kotlin.collections.KtMap<K, V>["__doNotUseOrImplementIt"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function provideList(): kotlin.collections.KtList<number>;
|
||||||
|
function provideMutableList(): kotlin.collections.KtMutableList<number>;
|
||||||
|
function provideSet(): kotlin.collections.KtSet<number>;
|
||||||
|
function provideMutableSet(): kotlin.collections.KtMutableSet<number>;
|
||||||
|
function provideMap(): kotlin.collections.KtMap<string, number>;
|
||||||
|
function provideMutableMap(): kotlin.collections.KtMutableMap<string, number>;
|
||||||
|
function consumeList(list: kotlin.collections.KtList<number>): boolean;
|
||||||
|
function consumeMutableList(list: kotlin.collections.KtMutableList<number>): boolean;
|
||||||
|
function consumeSet(list: kotlin.collections.KtSet<number>): boolean;
|
||||||
|
function consumeMutableSet(list: kotlin.collections.KtMutableSet<number>): boolean;
|
||||||
|
function consumeMap(map: kotlin.collections.KtMap<string, number>): boolean;
|
||||||
|
function consumeMutableMap(map: kotlin.collections.KtMutableMap<string, number>): boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
// CHECK_TYPESCRIPT_DECLARATIONS
|
||||||
|
// RUN_PLAIN_BOX_FUNCTION
|
||||||
|
// WITH_STDLIB
|
||||||
|
// SKIP_MINIFICATION
|
||||||
|
// SKIP_NODE_JS
|
||||||
|
// INFER_MAIN_MODULE
|
||||||
|
|
||||||
|
// TODO fix statics export in DCE-driven mode
|
||||||
|
// SKIP_DCE_DRIVEN
|
||||||
|
|
||||||
|
// MODULE: JS_TESTS
|
||||||
|
// FILE: f1.kt
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun provideList(): List<Int> = listOf(1, 2, 3)
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun provideMutableList(): MutableList<Int> = mutableListOf(4, 5, 6)
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun provideSet(): Set<Int> = setOf(1, 2, 3)
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun provideMutableSet(): MutableSet<Int> = mutableSetOf(4, 5, 6)
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun provideMap(): Map<String, Int> = mapOf("a" to 1, "b" to 2, "c" to 3)
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun provideMutableMap(): MutableMap<String, Int> = mutableMapOf("d" to 4, "e" to 5, "f" to 6)
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun consumeList(list: List<Int>) = list.toString() == "[1, 2, 3]"
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun consumeMutableList(list: MutableList<Int>): Boolean {
|
||||||
|
list.add(7)
|
||||||
|
return list.toString() == "[4, 5, 6, 7]"
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun consumeSet(list: Set<Int>) = list.toString() == "[1, 2, 3]"
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun consumeMutableSet(list: MutableSet<Int>): Boolean {
|
||||||
|
list.add(7)
|
||||||
|
return list.toString() == "[4, 5, 6, 7]"
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun consumeMap(map: Map<String, Int>) = map.toString() == "{a=1, b=2, c=3}"
|
||||||
|
|
||||||
|
@JsExport
|
||||||
|
fun consumeMutableMap(map: MutableMap<String, Int>): Boolean {
|
||||||
|
map["g"] = 7
|
||||||
|
return map.toString() == "{d=4, e=5, f=6, g=7}"
|
||||||
|
}
|
||||||
+213
@@ -0,0 +1,213 @@
|
|||||||
|
import provideList = JS_TESTS.provideList;
|
||||||
|
import consumeList = JS_TESTS.consumeList;
|
||||||
|
import provideMutableList = JS_TESTS.provideMutableList;
|
||||||
|
import consumeMutableList = JS_TESTS.consumeMutableList;
|
||||||
|
import provideMutableSet = JS_TESTS.provideMutableSet;
|
||||||
|
import provideSet = JS_TESTS.provideSet;
|
||||||
|
import consumeSet = JS_TESTS.consumeSet;
|
||||||
|
import consumeMutableSet = JS_TESTS.consumeMutableSet;
|
||||||
|
import provideMap = JS_TESTS.provideMap;
|
||||||
|
import consumeMap = JS_TESTS.consumeMap;
|
||||||
|
import provideMutableMap = JS_TESTS.provideMutableMap;
|
||||||
|
import consumeMutableMap = JS_TESTS.consumeMutableMap;
|
||||||
|
|
||||||
|
function assert(condition: boolean, message: string) {
|
||||||
|
if (!condition) {
|
||||||
|
throw message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertThrow(fn: () => void, message: string) {
|
||||||
|
try {
|
||||||
|
fn();
|
||||||
|
throw message;
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function box(): string {
|
||||||
|
testImmutableList()
|
||||||
|
testImmutableSet()
|
||||||
|
testImmutableMap()
|
||||||
|
|
||||||
|
testMutableList()
|
||||||
|
testMutableSet()
|
||||||
|
testMutableMap()
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
function testImmutableList() {
|
||||||
|
const list = provideList()
|
||||||
|
const listReadonlyArrayView = list.asJsReadonlyArrayView()
|
||||||
|
|
||||||
|
assert(listReadonlyArrayView[0] == 1, "Problem with accessing of element in immutable list readonly array view")
|
||||||
|
assert(listReadonlyArrayView["0"] == 1, "Problem with accessing of element in immutable list readonly array view by string")
|
||||||
|
assert(listReadonlyArrayView.map(x => x + 1).join("") == "234", "Problem with immutable list readonly array view")
|
||||||
|
assert(consumeList(list), "Problem with consumption of a Kotlin list")
|
||||||
|
assertThrow(() => { (listReadonlyArrayView as Array<number>)[1] = 4 }, "Immutable list readonly array view have ability to mutate the list by direct set")
|
||||||
|
assertThrow(() => { (listReadonlyArrayView as Array<number>).push(4) }, "Immutable list readonly array view have ability to mutate the list by 'push'")
|
||||||
|
assertThrow(() => { (listReadonlyArrayView as Array<number>).pop() }, "Immutable list readonly array view have ability to mutate the list by 'pop'")
|
||||||
|
// @ts-expect-error
|
||||||
|
assertThrow(() => { listReadonlyArrayView["foo"] }, "Immutable list getting a random index from its readonly array view")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMutableList() {
|
||||||
|
const mutableList = provideMutableList()
|
||||||
|
const mutableListReadonlyArrayView = mutableList.asJsReadonlyArrayView()
|
||||||
|
|
||||||
|
assert(mutableListReadonlyArrayView[0] == 4, "Problem with accessing of element in mutable list readonly array view")
|
||||||
|
assert(mutableListReadonlyArrayView["0"] == 4, "Problem with accessing of element in immutable list readonly array view by string")
|
||||||
|
assert(mutableListReadonlyArrayView.map(x => x + 1).join("") == "567", "Problem with mutable list readonly array view")
|
||||||
|
assert(!consumeList(mutableList), "Problem with consumption of a Kotlin mutable list as a list")
|
||||||
|
assert(consumeMutableList(mutableList), "Problem with consumption of a Kotlin mutable list as a mutable list")
|
||||||
|
assert(mutableListReadonlyArrayView.map(x => x + 1).join("") == "5678", "Problem with mutable list readonly array view after original list is mutated")
|
||||||
|
assertThrow(() => { (mutableListReadonlyArrayView as Array<number>)[1] = 4 }, "Mutable list readonly array view have ability to mutate the list by direct set")
|
||||||
|
assertThrow(() => { (mutableListReadonlyArrayView as Array<number>).push(4) }, "Mutable list readonly array view have ability to mutate the list by 'push'")
|
||||||
|
assertThrow(() => { (mutableListReadonlyArrayView as Array<number>).pop() }, "Mutable list readonly array view have ability to mutate the list by 'pop'")
|
||||||
|
// @ts-expect-error
|
||||||
|
assertThrow(() => { mutableListReadonlyArrayView["foo"] }, "Immutable list getting a random index from its readonly array view")
|
||||||
|
|
||||||
|
const mutableListArrayView = mutableList.asJsArrayView()
|
||||||
|
mutableListArrayView.pop()
|
||||||
|
|
||||||
|
assert(mutableListArrayView[0] == 4, "Problem with accessing of element in mutable list array view")
|
||||||
|
assert(mutableListArrayView["0"] == 4, "Problem with accessing of element in mutable list array view by string")
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "567", "Problem with mutable list array view")
|
||||||
|
assert(consumeMutableList(mutableList), "Problem with consumption of a Kotlin mutable list as a mutable list")
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "5678", "Problem with mutable list array view after original list is mutated")
|
||||||
|
// @ts-expect-error
|
||||||
|
assertThrow(() => { mutableListArrayView["foo"] = 4 }, "Mutable list setting a random index in its array view")
|
||||||
|
|
||||||
|
mutableListArrayView.shift()
|
||||||
|
mutableListArrayView.unshift(9)
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "10678", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView.sort()
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "67810", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView.push(3)
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "678104", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView[3] = 4
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "67854", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView["3"] = 6
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "67874", "Problem with mutable list array view after the view is mutated")
|
||||||
|
|
||||||
|
mutableListArrayView.length = 3
|
||||||
|
|
||||||
|
assert(mutableListArrayView.map(x => x + 1).join("") == "678", "Problem with mutable list array view after the view is mutated after size decreased")
|
||||||
|
assert(mutableListReadonlyArrayView.map(x => x + 1).join("") == "678", "Problem with mutable list readonly array view after size decreased")
|
||||||
|
|
||||||
|
assertThrow(() => { mutableListArrayView.length = 5 }, "Mutable list view size increasing works, but should not")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testImmutableSet() {
|
||||||
|
const set = provideSet()
|
||||||
|
const setReadonlyView = set.asJsReadonlySetView();
|
||||||
|
|
||||||
|
assert(setReadonlyView.has(1), "Problem with accessing element of readonly view")
|
||||||
|
assert(joinSetOrMap(setReadonlyView) == "123", "Problem with readonly view iterator")
|
||||||
|
assert(consumeSet(set), "Problem with consumption of a Kotlin set")
|
||||||
|
assertThrow(() => { (setReadonlyView as Set<number>).add(4) }, "Set readonly view have ability to mutate the set by 'add'")
|
||||||
|
assertThrow(() => { (setReadonlyView as Set<number>).delete(4) }, "Set readonly view have ability to mutate the set by 'delete'")
|
||||||
|
assertThrow(() => { (setReadonlyView as Set<number>).clear() }, "Set readonly view have ability to mutate the set by 'clear'")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMutableSet() {
|
||||||
|
const mutableSet = provideMutableSet()
|
||||||
|
const mutableSetReadonlyView = mutableSet.asJsReadonlySetView()
|
||||||
|
|
||||||
|
assert(mutableSetReadonlyView.has(4), "Problem with accessing element of mutable set readonly view")
|
||||||
|
assert(joinSetOrMap(mutableSetReadonlyView) == "456", "Problem with mutable set readonly view iterator")
|
||||||
|
assert(!consumeSet(mutableSet), "Problem with consumption of a Kotlin mutable set as a set")
|
||||||
|
assert(consumeMutableSet(mutableSet), "Problem with consumption of a Kotlin mutable set as a mutable set")
|
||||||
|
assert(joinSetOrMap(mutableSetReadonlyView) == "4567", "Problem with mutable set readonly view after original set is mutated")
|
||||||
|
assertThrow(() => { (mutableSetReadonlyView as Set<number>).add(4) }, "Mutable set readonly view have ability to mutate the set by 'add'")
|
||||||
|
assertThrow(() => { (mutableSetReadonlyView as Set<number>).delete(4) }, "Mutable set readonly view have ability to mutate the set by 'delete'")
|
||||||
|
assertThrow(() => { (mutableSetReadonlyView as Set<number>).clear() }, "Mutable set readonly view have ability to mutate the set by 'clear'")
|
||||||
|
|
||||||
|
const mutableSetView = mutableSet.asJsSetView()
|
||||||
|
|
||||||
|
mutableSetView.delete(7)
|
||||||
|
|
||||||
|
assert(mutableSetView.has(4), "Problem with accessing element of mutable set view")
|
||||||
|
assert(joinSetOrMap(mutableSetView) == "456", "Problem with mutable set view")
|
||||||
|
assert(consumeMutableSet(mutableSet), "Problem with consumption of a Kotlin mutable set as a mutable set")
|
||||||
|
assert(joinSetOrMap(mutableSetView) == "4567", "Problem with mutable set view after original set is mutated")
|
||||||
|
|
||||||
|
mutableSetView.add(8)
|
||||||
|
|
||||||
|
assert(joinSetOrMap(mutableSetView) == "45678", "Problem with mutable set view after the view is mutated")
|
||||||
|
|
||||||
|
mutableSetView.clear()
|
||||||
|
|
||||||
|
assert(joinSetOrMap(mutableSetView) == "", "Problem with mutable set view after the view is mutated")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testImmutableMap() {
|
||||||
|
const map = provideMap()
|
||||||
|
const mapReadonlyView = map.asJsReadonlyMapView()
|
||||||
|
|
||||||
|
assert(mapReadonlyView.has("a"), "Problem with accessing element in map readonly view")
|
||||||
|
assert(mapReadonlyView.get("a") == 1, "Problem with accessing element in map readonly view")
|
||||||
|
assert(joinSetOrMap(mapReadonlyView) == "[a:1][b:2][c:3]", "Problem with map readonly view iterator")
|
||||||
|
assert(consumeMap(map), "Problem with consumption of a Kotlin map")
|
||||||
|
assertThrow(() => { (mapReadonlyView as Map<string, number>).set("d", 4) }, "Map readonly view have ability to mutate the map by 'set'")
|
||||||
|
assertThrow(() => { (mapReadonlyView as Map<string, number>).delete("a") }, "Map readonly view have ability to mutate the map by 'delete'")
|
||||||
|
assertThrow(() => { (mapReadonlyView as Map<string, number>).clear() }, "Map readonly view have ability to mutate the map by 'clear'")
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMutableMap() {
|
||||||
|
const mutableMap = provideMutableMap()
|
||||||
|
const mutableMapReadonlyView = mutableMap.asJsReadonlyMapView()
|
||||||
|
|
||||||
|
assert(mutableMapReadonlyView.has("d"), "Problem with accessing element in mutable map readonly view")
|
||||||
|
assert(mutableMapReadonlyView.get("d") == 4, "Problem with accessing element in mutable map readonly view")
|
||||||
|
assert(joinSetOrMap(mutableMapReadonlyView) == "[d:4][e:5][f:6]", "Problem with mutable map readonly view")
|
||||||
|
assert(!consumeMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a map")
|
||||||
|
assert(consumeMutableMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a mutable map")
|
||||||
|
assert(joinSetOrMap(mutableMapReadonlyView) == "[d:4][e:5][f:6][g:7]", "Problem with mutable map readonly view after original map is mutated")
|
||||||
|
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).set("d", 4) }, "Mutable map readonly view have ability to mutate the map by 'set'")
|
||||||
|
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).delete("a") }, "Mutable map readonly view have ability to mutate the map by 'delete'")
|
||||||
|
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).clear() }, "Mutable map readonly view have ability to mutate the map by 'clear'")
|
||||||
|
|
||||||
|
const mutableMapView = mutableMap.asJsMapView()
|
||||||
|
|
||||||
|
mutableMapView.delete("g")
|
||||||
|
|
||||||
|
assert(mutableMapView.has("d"), "Problem with accessing element in mutable map view")
|
||||||
|
assert(mutableMapView.get("d") == 4, "Problem with accessing element in mutable map view")
|
||||||
|
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6]", "Problem with mutable map view")
|
||||||
|
assert(consumeMutableMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a mutable map")
|
||||||
|
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6][g:7]", "Problem with mutable map view after original map is mutated")
|
||||||
|
|
||||||
|
mutableMapView.set("h", 8)
|
||||||
|
|
||||||
|
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6][g:7][h:8]", "Problem with mutable map view after the view is mutated")
|
||||||
|
|
||||||
|
mutableMapView.clear()
|
||||||
|
|
||||||
|
assert(joinSetOrMap(mutableMapView) == "", "Problem with mutable map view after the view is mutated")
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinSetOrMap(setOrMap: ReadonlySet<number> | ReadonlyMap<string, number>): string {
|
||||||
|
let result = ""
|
||||||
|
|
||||||
|
if (setOrMap instanceof Set) {
|
||||||
|
setOrMap.forEach((a: any) => {
|
||||||
|
result += a
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setOrMap.forEach((key: any, value: any) => {
|
||||||
|
result += `[${key}:${value}]`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"include": [ "./*" ],
|
||||||
|
"extends": "../common.tsconfig.json"
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"newLine": "lf"
|
"newLine": "lf",
|
||||||
|
"lib": ["es2015", "dom"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+10
-2
@@ -1,5 +1,13 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
namespace kotlin.collections {
|
||||||
|
interface KtList<E> /* extends kotlin.collections.Collection<E> */ {
|
||||||
|
asJsReadonlyArrayView(): ReadonlyArray<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtList": unique symbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
namespace foo {
|
namespace foo {
|
||||||
interface SomeExternalInterface {
|
interface SomeExternalInterface {
|
||||||
}
|
}
|
||||||
@@ -18,8 +26,8 @@ declare namespace JS_TESTS {
|
|||||||
function genericWithMultipleConstraints<T extends unknown/* kotlin.Comparable<T> */ & foo.SomeExternalInterface & Error>(x: T): T;
|
function genericWithMultipleConstraints<T extends unknown/* kotlin.Comparable<T> */ & foo.SomeExternalInterface & Error>(x: T): T;
|
||||||
function generic3<A, B, C, D, E>(a: A, b: B, c: C, d: D): Nullable<E>;
|
function generic3<A, B, C, D, E>(a: A, b: B, c: C, d: D): Nullable<E>;
|
||||||
function inlineFun(x: number, callback: (p0: number) => void): void;
|
function inlineFun(x: number, callback: (p0: number) => void): void;
|
||||||
function formatList(value: any/* kotlin.collections.List<UnknownType *> */): string;
|
function formatList(value: kotlin.collections.KtList<any /*UnknownType **/>): string;
|
||||||
function createList(): any/* kotlin.collections.List<UnknownType *> */;
|
function createList(): kotlin.collections.KtList<any /*UnknownType **/>;
|
||||||
function defaultParametersAtTheBegining(a: string | undefined, b: string): string;
|
function defaultParametersAtTheBegining(a: string | undefined, b: string): string;
|
||||||
function nonDefaultParameterInBetween(a: string | undefined, b: string, c?: string): string;
|
function nonDefaultParameterInBetween(a: string | undefined, b: string, c?: string): string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
namespace kotlin.collections {
|
||||||
|
interface KtList<E> /* extends kotlin.collections.Collection<E> */ {
|
||||||
|
asJsReadonlyArrayView(): ReadonlyArray<E>;
|
||||||
|
readonly __doNotUseOrImplementIt: {
|
||||||
|
readonly "kotlin.collections.KtList": unique symbol;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
namespace foo {
|
namespace foo {
|
||||||
interface SomeExternalInterface {
|
interface SomeExternalInterface {
|
||||||
}
|
}
|
||||||
@@ -18,8 +26,8 @@ declare namespace JS_TESTS {
|
|||||||
function genericWithMultipleConstraints<T extends unknown/* kotlin.Comparable<T> */ & foo.SomeExternalInterface & Error>(x: T): T;
|
function genericWithMultipleConstraints<T extends unknown/* kotlin.Comparable<T> */ & foo.SomeExternalInterface & Error>(x: T): T;
|
||||||
function generic3<A, B, C, D, E>(a: A, b: B, c: C, d: D): Nullable<E>;
|
function generic3<A, B, C, D, E>(a: A, b: B, c: C, d: D): Nullable<E>;
|
||||||
function inlineFun(x: number, callback: (p0: number) => void): void;
|
function inlineFun(x: number, callback: (p0: number) => void): void;
|
||||||
function formatList(value: any/* kotlin.collections.List<UnknownType *> */): string;
|
function formatList(value: kotlin.collections.KtList<any /*UnknownType **/>): string;
|
||||||
function createList(): any/* kotlin.collections.List<UnknownType *> */;
|
function createList(): kotlin.collections.KtList<any /*UnknownType **/>;
|
||||||
function defaultParametersAtTheBegining(a: string | undefined, b: string): string;
|
function defaultParametersAtTheBegining(a: string | undefined, b: string): string;
|
||||||
function nonDefaultParameterInBetween(a: string | undefined, b: string, c?: string): string;
|
function nonDefaultParameterInBetween(a: string | undefined, b: string, c?: string): string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10111,6 +10111,11 @@ public open class ArrayList<E> : kotlin.collections.AbstractMutableList<E>, kotl
|
|||||||
|
|
||||||
public open override fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
public open override fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
||||||
|
|
||||||
|
@kotlin.js.ExperimentalJsExport
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
public open override fun asJsArrayView(): kotlin.js.collections.JsArray<E>
|
||||||
|
|
||||||
public open override fun clear(): kotlin.Unit
|
public open override fun clear(): kotlin.Unit
|
||||||
|
|
||||||
public final fun ensureCapacity(minCapacity: kotlin.Int): kotlin.Unit
|
public final fun ensureCapacity(minCapacity: kotlin.Int): kotlin.Unit
|
||||||
@@ -10310,6 +10315,11 @@ public open class LinkedHashSet<E> : kotlin.collections.HashSet<E>, kotlin.colle
|
|||||||
public interface List<out E> : kotlin.collections.Collection<E> {
|
public interface List<out E> : kotlin.collections.Collection<E> {
|
||||||
public abstract override val size: kotlin.Int { get; }
|
public abstract override val size: kotlin.Int { get; }
|
||||||
|
|
||||||
|
@kotlin.js.ExperimentalJsExport
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
public open fun asJsReadonlyArrayView(): kotlin.js.collections.JsReadonlyArray<E>
|
||||||
|
|
||||||
public abstract override operator fun contains(element: E): kotlin.Boolean
|
public abstract override operator fun contains(element: E): kotlin.Boolean
|
||||||
|
|
||||||
public abstract override fun containsAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
public abstract override fun containsAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
||||||
@@ -10362,6 +10372,11 @@ public interface Map<K, out V> {
|
|||||||
|
|
||||||
public abstract val values: kotlin.collections.Collection<V> { get; }
|
public abstract val values: kotlin.collections.Collection<V> { get; }
|
||||||
|
|
||||||
|
@kotlin.js.ExperimentalJsExport
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
public open fun asJsReadonlyMapView(): kotlin.js.collections.JsReadonlyMap<K, V>
|
||||||
|
|
||||||
public abstract fun containsKey(key: K): kotlin.Boolean
|
public abstract fun containsKey(key: K): kotlin.Boolean
|
||||||
|
|
||||||
public abstract fun containsValue(value: V): kotlin.Boolean
|
public abstract fun containsValue(value: V): kotlin.Boolean
|
||||||
@@ -10410,6 +10425,11 @@ public interface MutableList<E> : kotlin.collections.List<E>, kotlin.collections
|
|||||||
|
|
||||||
public abstract override fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
public abstract override fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
||||||
|
|
||||||
|
@kotlin.js.ExperimentalJsExport
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
public open fun asJsArrayView(): kotlin.js.collections.JsArray<E>
|
||||||
|
|
||||||
public abstract override fun clear(): kotlin.Unit
|
public abstract override fun clear(): kotlin.Unit
|
||||||
|
|
||||||
public abstract override fun listIterator(): kotlin.collections.MutableListIterator<E>
|
public abstract override fun listIterator(): kotlin.collections.MutableListIterator<E>
|
||||||
@@ -10448,6 +10468,11 @@ public interface MutableMap<K, V> : kotlin.collections.Map<K, V> {
|
|||||||
|
|
||||||
public abstract override val values: kotlin.collections.MutableCollection<V> { get; }
|
public abstract override val values: kotlin.collections.MutableCollection<V> { get; }
|
||||||
|
|
||||||
|
@kotlin.js.ExperimentalJsExport
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
public open fun asJsMapView(): kotlin.js.collections.JsMap<K, V>
|
||||||
|
|
||||||
public abstract fun clear(): kotlin.Unit
|
public abstract fun clear(): kotlin.Unit
|
||||||
|
|
||||||
public abstract fun put(key: K, value: V): V?
|
public abstract fun put(key: K, value: V): V?
|
||||||
@@ -10466,6 +10491,11 @@ public interface MutableSet<E> : kotlin.collections.Set<E>, kotlin.collections.M
|
|||||||
|
|
||||||
public abstract override fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
public abstract override fun addAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
||||||
|
|
||||||
|
@kotlin.js.ExperimentalJsExport
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
public open fun asJsSetView(): kotlin.js.collections.JsSet<E>
|
||||||
|
|
||||||
public abstract override fun clear(): kotlin.Unit
|
public abstract override fun clear(): kotlin.Unit
|
||||||
|
|
||||||
public abstract override operator fun iterator(): kotlin.collections.MutableIterator<E>
|
public abstract override operator fun iterator(): kotlin.collections.MutableIterator<E>
|
||||||
@@ -10483,6 +10513,11 @@ public interface RandomAccess {
|
|||||||
public interface Set<out E> : kotlin.collections.Collection<E> {
|
public interface Set<out E> : kotlin.collections.Collection<E> {
|
||||||
public abstract override val size: kotlin.Int { get; }
|
public abstract override val size: kotlin.Int { get; }
|
||||||
|
|
||||||
|
@kotlin.js.ExperimentalJsExport
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
public open fun asJsReadonlySetView(): kotlin.js.collections.JsReadonlySet<E>
|
||||||
|
|
||||||
public abstract override operator fun contains(element: E): kotlin.Boolean
|
public abstract override operator fun contains(element: E): kotlin.Boolean
|
||||||
|
|
||||||
public abstract override fun containsAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
public abstract override fun containsAll(elements: kotlin.collections.Collection<E>): kotlin.Boolean
|
||||||
@@ -10498,4 +10533,4 @@ public abstract class ShortIterator : kotlin.collections.Iterator<kotlin.Short>
|
|||||||
public final override operator fun next(): kotlin.Short
|
public final override operator fun next(): kotlin.Short
|
||||||
|
|
||||||
public abstract fun nextShort(): kotlin.Short
|
public abstract fun nextShort(): kotlin.Short
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
@kotlin.js.JsName(name = "Array")
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
public open external class JsArray<E> : kotlin.js.collections.JsReadonlyArray<E> {
|
||||||
|
public constructor JsArray<E>()
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.js.JsName(name = "Map")
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
public open external class JsMap<K, V> : kotlin.js.collections.JsReadonlyMap<K, V> {
|
||||||
|
public constructor JsMap<K, V>()
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.js.JsName(name = "ReadonlyArray")
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
public external interface JsReadonlyArray<out E> {
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.js.JsName(name = "ReadonlyMap")
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
public external interface JsReadonlyMap<K, out V> {
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.js.JsName(name = "ReadonlySet")
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
public external interface JsReadonlySet<out E> {
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.js.JsName(name = "Set")
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
@kotlin.js.ExperimentalJsCollectionsApi
|
||||||
|
public open external class JsSet<E> : kotlin.js.collections.JsReadonlySet<E> {
|
||||||
|
public constructor JsSet<E>()
|
||||||
|
}
|
||||||
@@ -201,6 +201,15 @@ public final annotation class EagerInitialization : kotlin.Annotation {
|
|||||||
public constructor EagerInitialization()
|
public constructor EagerInitialization()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@kotlin.RequiresOptIn(level = Level.WARNING)
|
||||||
|
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
|
||||||
|
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.FUNCTION})
|
||||||
|
@kotlin.annotation.MustBeDocumented
|
||||||
|
@kotlin.SinceKotlin(version = "1.9")
|
||||||
|
public final annotation class ExperimentalJsCollectionsApi : kotlin.Annotation {
|
||||||
|
public constructor ExperimentalJsCollectionsApi()
|
||||||
|
}
|
||||||
|
|
||||||
@kotlin.RequiresOptIn(level = Level.WARNING)
|
@kotlin.RequiresOptIn(level = Level.WARNING)
|
||||||
@kotlin.annotation.MustBeDocumented
|
@kotlin.annotation.MustBeDocumented
|
||||||
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
|
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
|
||||||
|
|||||||
@@ -130,4 +130,19 @@ public expect annotation class JsExport() {
|
|||||||
)
|
)
|
||||||
@MustBeDocumented
|
@MustBeDocumented
|
||||||
@SinceKotlin("1.9")
|
@SinceKotlin("1.9")
|
||||||
public annotation class ExperimentalJsReflectionCreateInstance
|
public annotation class ExperimentalJsReflectionCreateInstance
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This annotation marks the experimental JS-collections API that allows to manipulate with native JS-collections
|
||||||
|
* The API can be removed completely in any further release.
|
||||||
|
*
|
||||||
|
* Any usage of a declaration annotated with `@ExperimentalJsCollectionsApi` should be accepted either by
|
||||||
|
* annotating that usage with the [OptIn] annotation, e.g. `@OptIn(ExperimentalJsCollectionsApi::class)`,
|
||||||
|
* or by using the compiler argument `-opt-in=kotlin.js.ExperimentalJsCollectionsApi`.
|
||||||
|
*/
|
||||||
|
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
|
||||||
|
@MustBeDocumented
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
public annotation class ExperimentalJsCollectionsApi
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
package kotlin.collections
|
package kotlin.collections
|
||||||
|
|
||||||
|
import kotlin.js.collections.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Classes that inherit from this interface can be represented as a sequence of elements that can
|
* Classes that inherit from this interface can be represented as a sequence of elements that can
|
||||||
* be iterated over.
|
* be iterated over.
|
||||||
@@ -146,8 +148,11 @@ public interface List<out E> : Collection<E> {
|
|||||||
// Query Operations
|
// Query Operations
|
||||||
|
|
||||||
override val size: Int
|
override val size: Int
|
||||||
|
|
||||||
override fun isEmpty(): Boolean
|
override fun isEmpty(): Boolean
|
||||||
|
|
||||||
override fun contains(element: @UnsafeVariance E): Boolean
|
override fun contains(element: @UnsafeVariance E): Boolean
|
||||||
|
|
||||||
override fun iterator(): Iterator<E>
|
override fun iterator(): Iterator<E>
|
||||||
|
|
||||||
// Bulk Operations
|
// Bulk Operations
|
||||||
@@ -191,6 +196,15 @@ public interface List<out E> : Collection<E> {
|
|||||||
* Structural changes in the base list make the behavior of the view undefined.
|
* Structural changes in the base list make the behavior of the view undefined.
|
||||||
*/
|
*/
|
||||||
public fun subList(fromIndex: Int, toIndex: Int): List<E>
|
public fun subList(fromIndex: Int, toIndex: Int): List<E>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a view with the [JsReadonlyArray] methods to consume it in JavaScript as a regular readonly array.
|
||||||
|
* Structural changes in the base list are synchronized with the view.
|
||||||
|
*/
|
||||||
|
@ExperimentalJsExport
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
public fun asJsReadonlyArrayView(): JsReadonlyArray<E> = createJsReadonlyArrayViewFrom(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -226,7 +240,9 @@ public interface MutableList<E> : List<E>, MutableCollection<E> {
|
|||||||
public fun addAll(index: Int, elements: Collection<E>): Boolean
|
public fun addAll(index: Int, elements: Collection<E>): Boolean
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<E>): Boolean
|
override fun removeAll(elements: Collection<E>): Boolean
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<E>): Boolean
|
override fun retainAll(elements: Collection<E>): Boolean
|
||||||
|
|
||||||
override fun clear(): Unit
|
override fun clear(): Unit
|
||||||
|
|
||||||
// Positional Access Operations
|
// Positional Access Operations
|
||||||
@@ -256,6 +272,15 @@ public interface MutableList<E> : List<E>, MutableCollection<E> {
|
|||||||
|
|
||||||
// View
|
// View
|
||||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E>
|
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a view with the [JsArray] methods to consume it in JavaScript as a regular array.
|
||||||
|
* Structural changes in the base list are synchronized with the view, and vice verse.
|
||||||
|
*/
|
||||||
|
@ExperimentalJsExport
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
public fun asJsArrayView(): JsArray<E> = createJsArrayViewFrom(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -268,12 +293,24 @@ public interface Set<out E> : Collection<E> {
|
|||||||
// Query Operations
|
// Query Operations
|
||||||
|
|
||||||
override val size: Int
|
override val size: Int
|
||||||
|
|
||||||
override fun isEmpty(): Boolean
|
override fun isEmpty(): Boolean
|
||||||
|
|
||||||
override fun contains(element: @UnsafeVariance E): Boolean
|
override fun contains(element: @UnsafeVariance E): Boolean
|
||||||
|
|
||||||
override fun iterator(): Iterator<E>
|
override fun iterator(): Iterator<E>
|
||||||
|
|
||||||
// Bulk Operations
|
// Bulk Operations
|
||||||
override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
|
override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a view with the [JsReadonlySet] methods to consume it in JavaScript as a regular readonly Set.
|
||||||
|
* Structural changes in the base set are synchronized with the view.
|
||||||
|
*/
|
||||||
|
@ExperimentalJsExport
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
public fun asJsReadonlySetView(): JsReadonlySet<E> = createJsReadonlySetViewFrom(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -299,9 +336,21 @@ public interface MutableSet<E> : Set<E>, MutableCollection<E> {
|
|||||||
// Bulk Modification Operations
|
// Bulk Modification Operations
|
||||||
|
|
||||||
override fun addAll(elements: Collection<E>): Boolean
|
override fun addAll(elements: Collection<E>): Boolean
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<E>): Boolean
|
override fun removeAll(elements: Collection<E>): Boolean
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<E>): Boolean
|
override fun retainAll(elements: Collection<E>): Boolean
|
||||||
|
|
||||||
override fun clear(): Unit
|
override fun clear(): Unit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a view with the [JsSet] methods to consume it in JavaScript as a regular Set.
|
||||||
|
* Structural changes in the base set are synchronized with the view, and vice verse.
|
||||||
|
*/
|
||||||
|
@ExperimentalJsExport
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
public fun asJsSetView(): JsSet<E> = createJsSetViewFrom(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -370,6 +419,15 @@ public interface Map<K, out V> {
|
|||||||
*/
|
*/
|
||||||
public val value: V
|
public val value: V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a view with the [JsReadonlyMap] methods to consume it in JavaScript as a regular readonly Map.
|
||||||
|
* Structural changes in the base map are synchronized with the view.
|
||||||
|
*/
|
||||||
|
@ExperimentalJsExport
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
public fun asJsReadonlyMapView(): JsReadonlyMap<K, V> = createJsReadonlyMapViewFrom(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -432,4 +490,13 @@ public interface MutableMap<K, V> : Map<K, V> {
|
|||||||
*/
|
*/
|
||||||
public fun setValue(newValue: V): V
|
public fun setValue(newValue: V): V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a view with the [JsMap] methods to consume it in JavaScript as a regular Map.
|
||||||
|
* Structural changes in the base map are synchronized with the view, and vice verse.
|
||||||
|
*/
|
||||||
|
@ExperimentalJsExport
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
public fun asJsMapView(): JsMap<K, V> = createJsMapViewFrom(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
@file:OptIn(ExperimentalJsCollectionsApi::class)
|
||||||
|
|
||||||
|
package kotlin.collections
|
||||||
|
|
||||||
|
import kotlin.js.collections.*
|
||||||
|
|
||||||
|
private class JsArrayView<E> : JsArray<E>()
|
||||||
|
|
||||||
|
private fun UNSUPPORTED_OPERATION() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <E> createJsReadonlyArrayViewFrom(list: List<E>): JsReadonlyArray<E> =
|
||||||
|
createJsArrayViewWith(
|
||||||
|
listSize = { list.size },
|
||||||
|
listGet = { i -> list[i] },
|
||||||
|
listSet = ::UNSUPPORTED_OPERATION.asDynamic(),
|
||||||
|
listDecreaseSize = ::UNSUPPORTED_OPERATION.asDynamic(),
|
||||||
|
listIncreaseSize = ::UNSUPPORTED_OPERATION.asDynamic()
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun <E> createJsArrayViewFrom(list: MutableList<E>): JsArray<E> =
|
||||||
|
createJsArrayViewWith(
|
||||||
|
listSize = { list.size },
|
||||||
|
listGet = { i -> list[i] },
|
||||||
|
listSet = { i, v -> list[i] = v },
|
||||||
|
listDecreaseSize = { size -> list.subList(list.size - size, list.size).clear() },
|
||||||
|
listIncreaseSize = ::UNSUPPORTED_OPERATION.asDynamic()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE", "UNUSED_PARAMETER")
|
||||||
|
private fun <E> createJsArrayViewWith(
|
||||||
|
listSize: () -> Int,
|
||||||
|
listGet: (Int) -> E,
|
||||||
|
listSet: (Int, E) -> Unit,
|
||||||
|
listDecreaseSize: (Int) -> Unit,
|
||||||
|
listIncreaseSize: (Int) -> Unit,
|
||||||
|
): dynamic {
|
||||||
|
val arrayView = objectCreate<JsArrayView<*>>()
|
||||||
|
|
||||||
|
return js("""
|
||||||
|
new Proxy(arrayView, {
|
||||||
|
get: function(target, prop, receiver) {
|
||||||
|
if (prop === "length") return listSize();
|
||||||
|
var type = typeof prop
|
||||||
|
var index = type === "string" || type === "number" ? +prop : undefined
|
||||||
|
if (!isNaN(index)) return listGet(index);
|
||||||
|
return target[prop]
|
||||||
|
},
|
||||||
|
has: function(target, key) { return !isNaN(key) && key < listSize() },
|
||||||
|
set: function(obj, prop, value) {
|
||||||
|
if (prop === "length") {
|
||||||
|
var size = listSize();
|
||||||
|
var newSize = type === "string" || type === "number" ? +prop : undefined
|
||||||
|
if (isNaN(newSize)) throw new RangeError("invalid array length")
|
||||||
|
if (newSize < size) listDecreaseSize(size - newSize)
|
||||||
|
else listIncreaseSize(newSize - size)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = typeof prop;
|
||||||
|
var index = type === "string" || type === "number" ? +prop : undefined;
|
||||||
|
|
||||||
|
if (isNaN(index)) return false;
|
||||||
|
|
||||||
|
listSet(index, value)
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JsSetView<E> : JsSet<E>()
|
||||||
|
|
||||||
|
internal fun <E> createJsReadonlySetViewFrom(set: Set<E>): JsReadonlySet<E> =
|
||||||
|
createJsSetViewWith<E>(
|
||||||
|
setSize = { set.size },
|
||||||
|
setAdd = ::UNSUPPORTED_OPERATION.asDynamic(),
|
||||||
|
setRemove = ::UNSUPPORTED_OPERATION.asDynamic(),
|
||||||
|
setClear = ::UNSUPPORTED_OPERATION.asDynamic(),
|
||||||
|
setContains = { v -> set.contains(v) },
|
||||||
|
valuesIterator = { createJsIteratorFrom(set.iterator()) },
|
||||||
|
entriesIterator = { createJsIteratorFrom(set.iterator()) { arrayOf(it, it) } },
|
||||||
|
forEach = { cb, t -> forEach(cb, t) }
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun <E> createJsSetViewFrom(set: MutableSet<E>): JsSet<E> =
|
||||||
|
createJsSetViewWith<E>(
|
||||||
|
setSize = { set.size },
|
||||||
|
setAdd = { v -> set.add(v) },
|
||||||
|
setRemove = { v -> set.remove(v) },
|
||||||
|
setClear = { set.clear() },
|
||||||
|
setContains = { v -> set.contains(v) },
|
||||||
|
valuesIterator = { createJsIteratorFrom(set.iterator()) },
|
||||||
|
entriesIterator = { createJsIteratorFrom(set.iterator()) { arrayOf(it, it) } },
|
||||||
|
forEach = { cb, t -> forEach(cb, t) }
|
||||||
|
)
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE", "UNUSED_PARAMETER")
|
||||||
|
private fun <E> createJsSetViewWith(
|
||||||
|
setSize: () -> Int,
|
||||||
|
setAdd: (E) -> Unit,
|
||||||
|
setRemove: (E) -> Boolean,
|
||||||
|
setClear: () -> Unit,
|
||||||
|
setContains: (E) -> Boolean,
|
||||||
|
valuesIterator: () -> dynamic,
|
||||||
|
entriesIterator: () -> dynamic,
|
||||||
|
forEach: (dynamic, dynamic) -> Unit,
|
||||||
|
): dynamic {
|
||||||
|
val setView = objectCreate<JsSetView<E>>().also {
|
||||||
|
js("it[Symbol.iterator] = valuesIterator")
|
||||||
|
defineProp(it, "size", setSize, VOID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return js("""
|
||||||
|
Object.assign(setView, {
|
||||||
|
add: function(value) { setAdd(value); return this },
|
||||||
|
'delete': setRemove,
|
||||||
|
clear: setClear,
|
||||||
|
has: setContains,
|
||||||
|
keys: valuesIterator,
|
||||||
|
values: valuesIterator,
|
||||||
|
entries: entriesIterator,
|
||||||
|
forEach: function (cb, thisArg) { forEach(cb, thisArg || setView) }
|
||||||
|
})
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class JsMapView<K, V> : JsMap<K, V>()
|
||||||
|
|
||||||
|
internal fun <K, V> createJsReadonlyMapViewFrom(map: Map<K, V>): JsReadonlyMap<K, V> =
|
||||||
|
createJsMapViewWith<K, V>(
|
||||||
|
mapSize = { map.size },
|
||||||
|
mapGet = { k -> map[k] },
|
||||||
|
mapContains = { k -> map.containsKey(k) },
|
||||||
|
mapPut = ::UNSUPPORTED_OPERATION.asDynamic(),
|
||||||
|
mapRemove = ::UNSUPPORTED_OPERATION.asDynamic(),
|
||||||
|
mapClear = ::UNSUPPORTED_OPERATION.asDynamic(),
|
||||||
|
keysIterator = { createJsIteratorFrom(map.keys.iterator()) },
|
||||||
|
valuesIterator = { createJsIteratorFrom(map.values.iterator()) },
|
||||||
|
entriesIterator = { createJsIteratorFrom(map.entries.iterator()) { arrayOf(it.key, it.value) } },
|
||||||
|
forEach = { cb, t -> forEach(cb, t) }
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun <K, V> createJsMapViewFrom(map: MutableMap<K, V>): JsMap<K, V> =
|
||||||
|
createJsMapViewWith<K, V>(
|
||||||
|
mapSize = { map.size },
|
||||||
|
mapGet = { k -> map[k] },
|
||||||
|
mapContains = { k -> map.containsKey(k) },
|
||||||
|
mapPut = { k, v -> map.put(k, v) },
|
||||||
|
mapRemove = { k -> map.remove(k) },
|
||||||
|
mapClear = { map.clear() },
|
||||||
|
keysIterator = { createJsIteratorFrom(map.keys.iterator()) },
|
||||||
|
valuesIterator = { createJsIteratorFrom(map.values.iterator()) },
|
||||||
|
entriesIterator = { createJsIteratorFrom(map.entries.iterator()) { arrayOf(it.key, it.value) } },
|
||||||
|
forEach = { cb, t -> forEach(cb, t) }
|
||||||
|
)
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE", "UNUSED_PARAMETER")
|
||||||
|
private fun <K, V> createJsMapViewWith(
|
||||||
|
mapSize: () -> Int,
|
||||||
|
mapGet: (K) -> V?,
|
||||||
|
mapContains: (K) -> Boolean,
|
||||||
|
mapPut: (K, V) -> Unit,
|
||||||
|
mapRemove: (K) -> Unit,
|
||||||
|
mapClear: () -> Unit,
|
||||||
|
keysIterator: () -> dynamic,
|
||||||
|
valuesIterator: () -> dynamic,
|
||||||
|
entriesIterator: () -> dynamic,
|
||||||
|
forEach: (dynamic, dynamic) -> Unit,
|
||||||
|
): dynamic {
|
||||||
|
val mapView = objectCreate<JsMapView<K, V>>().also {
|
||||||
|
js("it[Symbol.iterator] = entriesIterator")
|
||||||
|
defineProp(it, "size", mapSize, VOID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return js("""
|
||||||
|
Object.assign(mapView, {
|
||||||
|
get: mapGet,
|
||||||
|
set: function(key, value) { mapPut(key, value); return this },
|
||||||
|
'delete': mapRemove,
|
||||||
|
clear: mapClear,
|
||||||
|
has: mapContains,
|
||||||
|
keys: valuesIterator,
|
||||||
|
values: valuesIterator,
|
||||||
|
entries: entriesIterator,
|
||||||
|
forEach: function (cb, thisArg) { forEach(cb, thisArg || mapView) }
|
||||||
|
})
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE", "UNUSED_PARAMETER")
|
||||||
|
private fun <T> createJsIteratorFrom(iterator: Iterator<T>, transform: (T) -> dynamic = { it }): dynamic {
|
||||||
|
val iteratorNext = { iterator.next() }
|
||||||
|
val iteratorHasNext = { iterator.hasNext() }
|
||||||
|
return js("""{
|
||||||
|
next: function() {
|
||||||
|
var result = { done: !iteratorHasNext() };
|
||||||
|
if (!result.done) result.value = transform(iteratorNext());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}""")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun forEach(cb: (dynamic, dynamic, dynamic) -> Unit, thisArg: dynamic) {
|
||||||
|
val iterator = thisArg.entries()
|
||||||
|
var result = iterator.next()
|
||||||
|
|
||||||
|
while (!result.done) {
|
||||||
|
val value = result.value
|
||||||
|
cb(value[0], value[1], thisArg)
|
||||||
|
result = iterator.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -208,7 +208,7 @@ internal fun protoOf(constructor: Any) =
|
|||||||
js("constructor.prototype")
|
js("constructor.prototype")
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
internal fun <T> objectCreate(proto: T?) =
|
internal fun <T> objectCreate(proto: T? = null): T =
|
||||||
js("Object.create(proto)")
|
js("Object.create(proto)")
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
|||||||
@@ -44,16 +44,17 @@ internal fun safePropertySet(self: dynamic, setterName: String, propName: String
|
|||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||||
internal annotation class JsFun(val code: String)
|
internal annotation class JsFun(val code: String)
|
||||||
|
|
||||||
/**
|
|
||||||
* The annotation is needed for annotating class declarations and type alias which are used inside exported declarations, but
|
|
||||||
* doesn't contain @JsExport annotation
|
|
||||||
* This information is used for generating special tagged types inside d.ts files, for more strict usage of implicitly exported entities
|
|
||||||
*/
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
internal annotation class JsImplicitExport
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The annotation is needed for annotating function declarations that should be compiled as ES6 generators
|
* The annotation is needed for annotating function declarations that should be compiled as ES6 generators
|
||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.FUNCTION)
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
internal annotation class JsGenerator
|
internal annotation class JsGenerator
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The annotation is needed for annotating class declarations and type alias which are used inside exported declarations, but
|
||||||
|
* doesn't contain @JsExport annotation
|
||||||
|
* This information is used for generating special tagged types inside d.ts files, for more strict usage of implicitly exported entities
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
internal annotation class JsImplicitExport(val couldBeConvertedToExplicitExport: Boolean)
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package kotlin.collections
|
package kotlin.collections
|
||||||
|
|
||||||
|
import kotlin.js.collections.JsArray
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a [MutableList] implementation, which uses a resizable array as its backing storage.
|
* Provides a [MutableList] implementation, which uses a resizable array as its backing storage.
|
||||||
*
|
*
|
||||||
@@ -178,6 +180,10 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
|
|||||||
return js("[]").slice.call(array)
|
return js("[]").slice.call(array)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExperimentalJsExport
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
override fun asJsArrayView(): JsArray<E> = array.unsafeCast<JsArray<E>>()
|
||||||
|
|
||||||
internal override fun checkIsMutable() {
|
internal override fun checkIsMutable() {
|
||||||
if (isReadOnly) throw UnsupportedOperationException()
|
if (isReadOnly) throw UnsupportedOperationException()
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.js.collections
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes the TypeScript [ReadonlyArray](https://www.typescriptlang.org/docs/handbook/2/objects.html#the-readonlyarray-type) to Kotlin.
|
||||||
|
*/
|
||||||
|
@JsName("ReadonlyArray")
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
public external interface JsReadonlyArray<out E>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes the JavaScript [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) to Kotlin.
|
||||||
|
*/
|
||||||
|
@JsName("Array")
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
public external open class JsArray<E> : JsReadonlyArray<E>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes the TypeScript [ReadonlySet](https://github.com/microsoft/TypeScript/blob/bd952a7a83ce04b3541b952238b6c0e4316b7d5d/src/lib/es2015.collection.d.ts#L103) to Kotlin.
|
||||||
|
*/
|
||||||
|
@JsName("ReadonlySet")
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
public external interface JsReadonlySet<out E>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes the JavaScript [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) to Kotlin.
|
||||||
|
*/
|
||||||
|
@JsName("Set")
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
public external open class JsSet<E> : JsReadonlySet<E>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes the TypeScript [ReadonlyMap](https://github.com/microsoft/TypeScript/blob/bd952a7a83ce04b3541b952238b6c0e4316b7d5d/src/lib/es2015.collection.d.ts#L37) to Kotlin.
|
||||||
|
*/
|
||||||
|
@JsName("ReadonlyMap")
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
public external interface JsReadonlyMap<K, out V>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes the JavaScript [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) to Kotlin.
|
||||||
|
*/
|
||||||
|
@JsName("Map")
|
||||||
|
@SinceKotlin("1.9")
|
||||||
|
@ExperimentalJsCollectionsApi
|
||||||
|
public external open class JsMap<K, V> : JsReadonlyMap<K, V>
|
||||||
+3
@@ -3384,6 +3384,9 @@ public final class kotlin/jdk7/AutoCloseableKt {
|
|||||||
public static final fun closeFinally (Ljava/lang/AutoCloseable;Ljava/lang/Throwable;)V
|
public static final fun closeFinally (Ljava/lang/AutoCloseable;Ljava/lang/Throwable;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract interface annotation class kotlin/js/ExperimentalJsCollectionsApi : java/lang/annotation/Annotation {
|
||||||
|
}
|
||||||
|
|
||||||
public abstract interface annotation class kotlin/js/ExperimentalJsExport : java/lang/annotation/Annotation {
|
public abstract interface annotation class kotlin/js/ExperimentalJsExport : java/lang/annotation/Annotation {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user