diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index df144c5159c..bb0f815ea72 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -7214,18 +7214,18 @@ - - - - - - + + + + + + @@ -7258,12 +7258,6 @@ - - - - - - @@ -7316,18 +7310,18 @@ - - - - - - + + + + + + @@ -7360,12 +7354,6 @@ - - - - - - diff --git a/plugins/kotlinx-serialization/build.gradle.kts b/plugins/kotlinx-serialization/build.gradle.kts index 061c8fe302d..298cd4f1044 100644 --- a/plugins/kotlinx-serialization/build.gradle.kts +++ b/plugins/kotlinx-serialization/build.gradle.kts @@ -1,3 +1,7 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute +import org.jetbrains.kotlin.gradle.targets.js.d8.D8RootPlugin + description = "Kotlin Serialization Compiler Plugin" plugins { @@ -5,6 +9,23 @@ plugins { id("jps-compatible") } +val d8Plugin = D8RootPlugin.apply(rootProject) +d8Plugin.version = v8Version + +val jsonJsIrRuntimeForTests: Configuration by configurations.creating { + attributes { + attribute(KotlinPlatformType.attribute, KotlinPlatformType.js) + attribute(KotlinJsCompilerAttribute.jsCompilerAttribute, KotlinJsCompilerAttribute.ir) + } +} + +val coreJsIrRuntimeForTests: Configuration by configurations.creating { + attributes { + attribute(KotlinPlatformType.attribute, KotlinPlatformType.js) + attribute(KotlinJsCompilerAttribute.jsCompilerAttribute, KotlinJsCompilerAttribute.ir) + } +} + dependencies { embedded(project(":kotlinx-serialization-compiler-plugin.common")) { isTransitive = false } embedded(project(":kotlinx-serialization-compiler-plugin.k1")) { isTransitive = false } @@ -22,6 +43,7 @@ dependencies { testApi(projectTests(":compiler:tests-common-new")) testApi(project(":compiler:fir:plugin-utils")) testImplementation(projectTests(":generators:test-generator")) + testImplementation(projectTests(":js:js.tests")) testApiJUnit5() testImplementation(project(":kotlinx-serialization-compiler-plugin.common")) @@ -33,6 +55,9 @@ dependencies { testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.1") testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") + coreJsIrRuntimeForTests("org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.1") { isTransitive = false } + jsonJsIrRuntimeForTests("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") { isTransitive = false } + testRuntimeOnly(intellijCore()) testRuntimeOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false } testRuntimeOnly(project(":core:descriptors.runtime")) @@ -59,6 +84,28 @@ testsJar() projectTest(parallel = true, jUnitMode = JUnitMode.JUnit5) { workingDir = rootDir useJUnitPlatform() + setUpJsIrBoxTests() } val generateTests by generator("org.jetbrains.kotlinx.serialization.TestGeneratorKt") + +fun Test.setUpJsIrBoxTests() { + dependsOn(d8Plugin.setupTaskProvider) + dependsOn(":kotlin-stdlib-js-ir:compileKotlinJs") + dependsOn(":kotlin-test:kotlin-test-js-ir:compileKotlinJs") + + val localJsCoreRuntimeForTests: FileCollection = coreJsIrRuntimeForTests + val localJsJsonRuntimeForTests: FileCollection = jsonJsIrRuntimeForTests + val v8ExecutablePath = d8Plugin.requireConfigured().executablePath.absolutePath + + doFirst { + systemProperty("javascript.engine.path.V8", v8ExecutablePath) + systemProperty("serialization.core.path", localJsCoreRuntimeForTests.asPath) + systemProperty("serialization.json.path", localJsJsonRuntimeForTests.asPath) + } + + systemProperty("kotlin.js.test.root.out.dir", "$buildDir/") + systemProperty("kotlin.js.full.stdlib.path", "libraries/stdlib/js-ir/build/classes/kotlin/js/main") + systemProperty("kotlin.js.reduced.stdlib.path", "libraries/stdlib/js-ir-minimal-for-test/build/classes/kotlin/js/main") + systemProperty("kotlin.js.kotlin.test.path", "libraries/kotlin.test/js-ir/build/classes/kotlin/js/main") +} diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt index 5b6b49c9cbc..bd25e6e4ea3 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/BaseIrGenerator.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.jvm.functionByName import org.jetbrains.kotlin.backend.jvm.ir.fileParent import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.deepCopyWithVariables @@ -18,6 +19,7 @@ import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrVararg +import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol @@ -27,6 +29,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.platform.isJs import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext @@ -64,6 +67,25 @@ abstract class BaseIrGenerator(private val currentClass: IrClass, final override return throwMissedFieldExceptionFunc != null && throwMissedFieldExceptionArrayFunc != null } + fun IrDeclaration.excludeFromJsExport() { + if (!compilerContext.platform.isJs()) { + return + } + val jsExportIgnore = compilerContext.jsExportIgnoreClass ?: return + val jsExportIgnoreCtor = jsExportIgnore.primaryConstructor ?: return + + annotations += IrConstructorCallImpl( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + jsExportIgnore.defaultType, + jsExportIgnoreCtor.symbol, + jsExportIgnore.typeParameters.size, + jsExportIgnoreCtor.typeParameters.size, + jsExportIgnoreCtor.valueParameters.size, + ) + } + + private fun getClassListFromFileAnnotation(annotationFqName: FqName): List { val annotation = currentClass.fileParent.annotations.findAnnotation(annotationFqName) ?: return emptyList() val vararg = annotation.getValueArgument(0) as? IrVararg ?: return emptyList() diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrBuilderWithPluginContext.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrBuilderWithPluginContext.kt index 291f7789699..2f4ade9fb4a 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrBuilderWithPluginContext.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrBuilderWithPluginContext.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType -import org.jetbrains.kotlin.synthetic.syntheticVisibility import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginContext diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrPreGenerator.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrPreGenerator.kt index fae35953c99..bad4d1cdb7f 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrPreGenerator.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/IrPreGenerator.kt @@ -60,6 +60,7 @@ class IrPreGenerator( } method.apply { dispatchReceiverParameter = null // function is static + excludeFromJsExport() } val typeParams = irClass.typeParameters.map { @@ -108,7 +109,7 @@ class IrPreGenerator( val ctor = irClass.addConstructor { origin = SERIALIZATION_PLUGIN_ORIGIN visibility = DescriptorVisibilities.PUBLIC - } + }.apply { excludeFromJsExport() } val markerClassSymbol = compilerContext.getClassFromInternalSerializationPackage(SerialEntityNames.SERIAL_CTOR_MARKER_NAME.asString()) val serializableProperties = serializablePropertiesForIrBackend(irClass).serializableProperties diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt index 71840936ac3..9fe817dd4c5 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializableCompanionIrGenerator.kt @@ -178,7 +178,7 @@ class SerializableCompanionIrGenerator( type = compilerContext.irBuiltIns.arrayClass.typeWith(kSerializerStarType) origin = SERIALIZATION_PLUGIN_ORIGIN } - return f + return f.apply { excludeFromJsExport() } } private fun generateSerializerFactoryIfNeeded(getterDescriptor: IrSimpleFunction) { diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt index 91ff612f24c..883e6ece1bd 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationLoweringExtension.kt @@ -19,6 +19,8 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.findDeclaration +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.getPropertyGetter import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid @@ -33,6 +35,7 @@ import org.jetbrains.kotlinx.serialization.compiler.backend.ir.* import org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializationJvmIrIntrinsicSupport import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationDependencies +import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationJsDependenciesClassIds import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationPackages import java.util.concurrent.ConcurrentHashMap @@ -75,6 +78,16 @@ class SerializationPluginContext(baseContext: IrPluginContext, val metadataPlugi internal val lazyClass = referenceClass(ClassId.topLevel(SerializationDependencies.LAZY_FQ))!!.owner internal val lazyValueGetter = lazyClass.getPropertyGetter("value")!! + internal val jsExportIgnoreClass: IrClass? by lazy { + val pkg = SerializationJsDependenciesClassIds.jsExportIgnore.packageFqName + val jsExportName = SerializationJsDependenciesClassIds.jsExportIgnore.parentClassId!!.shortClassName + val jsExportIgnoreFqName = SerializationJsDependenciesClassIds.jsExportIgnore.asSingleFqName() + + getClassFromRuntimeOrNull(jsExportName.identifier, pkg) + ?.owner + ?.findDeclaration { it.fqNameWhenAvailable == jsExportIgnoreFqName } + } + // serialization runtime declarations internal val enumSerializerFactoryFunc = baseContext.referenceFunctions( CallableId( diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.common/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt b/plugins/kotlinx-serialization/kotlinx-serialization.common/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt index b9288f528a3..9de94409c1b 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.common/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.common/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt @@ -197,6 +197,10 @@ object SerializationDependencies { val LAZY_PUBLICATION_MODE_NAME = Name.identifier("PUBLICATION") } +object SerializationJsDependenciesClassIds { + val jsExportIgnore = ClassId.fromString("kotlin/js/JsExport.Ignore") +} + object SerializersClassIds { val kSerializerId = ClassId(SerializationPackages.packageFqName, SerialEntityNames.KSERIALIZER_NAME) val enumSerializerId = ClassId(SerializationPackages.internalPackageFqName, Name.identifier(SpecialBuiltins.enumSerializer)) diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt index a6c85042854..32d86355446 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationResolveExtension.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.platform.jvm.isJvm diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt index 05f4f65ea28..5258390a2c2 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -24,6 +25,7 @@ import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ANNOTATED_ENUM_SERIALIZER_FACTORY_FUNC_NAME +import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.ENUM_SERIALIZER_FACTORY_FUNC_NAME import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.inheritableSerialInfoFqName import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.metaSerializableAnnotationFqName @@ -275,6 +277,11 @@ fun ClassDescriptor.needSerializerFactory(): Boolean { return true } +fun DeclarationDescriptor.jsExportIgnore(): AnnotationDescriptor? { + val jsExportIgnore = runIf(platform.isJs()) { module.getJsExportIgnore() } ?: return null + return AnnotationDescriptorImpl(jsExportIgnore.defaultType, mapOf(), jsExportIgnore.source) +} + fun getSerializableClassDescriptorBySerializer(serializerDescriptor: ClassDescriptor): ClassDescriptor? { val serializerForClass = serializerDescriptor.serializerForClass if (serializerForClass != null) return serializerForClass.toClassDescriptor diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt index adb1eb48925..0c90fa66e05 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializerDescriptorResolver.kt @@ -7,10 +7,7 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.annotations.createDeprecatedAnnotation +import org.jetbrains.kotlin.descriptors.annotations.* import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.Name @@ -81,7 +78,7 @@ object KSerializerDescriptorResolver { thisDescriptor, SERIALIZER_CLASS_NAME, thisDescriptor.source, scope, Modality.FINAL, DescriptorVisibilities.PUBLIC, - Annotations.create(listOf(createDeprecatedHiddenAnnotation(thisDescriptor.module))), + Annotations.create(listOfNotNull(createDeprecatedHiddenAnnotation(thisDescriptor.module), thisDescriptor.jsExportIgnore())), DescriptorVisibilities.PRIVATE, serializerKind, false ) @@ -211,7 +208,7 @@ object KSerializerDescriptorResolver { needBackingField: Boolean = false ): PropertyDescriptor { val propertyDescriptor = PropertyDescriptorImpl.create( - thisDescriptor, Annotations.EMPTY, modality, visibility, false, name, + thisDescriptor, Annotations.create(listOfNotNull(thisDescriptor.jsExportIgnore())), modality, visibility, false, name, CallableMemberDescriptor.Kind.SYNTHESIZED, thisDescriptor.source, false, false, false, false, false, false ) @@ -225,12 +222,12 @@ object KSerializerDescriptorResolver { ) val propertyGetter = PropertyGetterDescriptorImpl( - propertyDescriptor, Annotations.EMPTY, modality, visibility, false, false, false, + propertyDescriptor, Annotations.create(listOfNotNull(thisDescriptor.jsExportIgnore())), modality, visibility, false, false, false, CallableMemberDescriptor.Kind.SYNTHESIZED, null, thisDescriptor.source ) propertyGetter.initialize(type) - val backingField = if (needBackingField) FieldDescriptorImpl(Annotations.EMPTY, propertyDescriptor) else null + val backingField = if (needBackingField) FieldDescriptorImpl(Annotations.create(listOfNotNull(thisDescriptor.jsExportIgnore())), propertyDescriptor) else null propertyDescriptor.initialize(propertyGetter, null, backingField, null) return propertyDescriptor } @@ -240,7 +237,11 @@ object KSerializerDescriptorResolver { name: Name ): SimpleFunctionDescriptor { val functionDescriptor = SimpleFunctionDescriptorImpl.create( - companionDescriptor, Annotations.EMPTY, name, CallableMemberDescriptor.Kind.SYNTHESIZED, companionDescriptor.source + companionDescriptor, + Annotations.create(listOfNotNull(companionDescriptor.jsExportIgnore())), + name, + CallableMemberDescriptor.Kind.SYNTHESIZED, + companionDescriptor.source ) val serializableClassOnImplSite = extractKSerializerArgumentFromImplementation(companionDescriptor) @@ -273,7 +274,7 @@ object KSerializerDescriptorResolver { ): PropertyDescriptor { val propertyDescriptor = PropertyDescriptorImpl.create( containingClassDescriptor, - Annotations.EMPTY, Modality.FINAL, visibility, false, name, + Annotations.create(listOfNotNull(containingClassDescriptor.jsExportIgnore())), Modality.FINAL, visibility, false, name, CallableMemberDescriptor.Kind.SYNTHESIZED, containingClassDescriptor.source, false, false, false, false, false, false ) val extensionReceiverParameter: ReceiverParameterDescriptor? = null // kludge to disambiguate call @@ -287,7 +288,7 @@ object KSerializerDescriptorResolver { val propertyGetter: PropertyGetterDescriptorImpl? = if (createGetter) { PropertyGetterDescriptorImpl( - propertyDescriptor, Annotations.EMPTY, Modality.FINAL, visibility, false, false, false, + propertyDescriptor, Annotations.create(listOfNotNull(containingClassDescriptor.jsExportIgnore())), Modality.FINAL, visibility, false, false, false, CallableMemberDescriptor.Kind.SYNTHESIZED, null, containingClassDescriptor.source ).apply { initialize(type) } } else { @@ -308,7 +309,7 @@ object KSerializerDescriptorResolver { val functionDescriptor = ClassConstructorDescriptorImpl.createSynthesized( classDescriptor, - Annotations.create(listOf(createDeprecatedHiddenAnnotation(classDescriptor.module))), + Annotations.create(listOfNotNull(createDeprecatedHiddenAnnotation(classDescriptor.module), classDescriptor.jsExportIgnore())), false, SourceElement.NO_SOURCE ) @@ -433,7 +434,7 @@ object KSerializerDescriptorResolver { private fun createSerializerFactoryVarargDescriptor(thisClass: ClassDescriptor): SimpleFunctionDescriptor { val f = SimpleFunctionDescriptorImpl.create( thisClass, - Annotations.EMPTY, + Annotations.create(listOfNotNull(thisClass.jsExportIgnore())), SerialEntityNames.SERIALIZER_PROVIDER_NAME, CallableMemberDescriptor.Kind.SYNTHESIZED, thisClass.source @@ -482,7 +483,7 @@ object KSerializerDescriptorResolver { ): SimpleFunctionDescriptor { val f = SimpleFunctionDescriptorImpl.create( thisClass, - Annotations.EMPTY, + Annotations.create(listOfNotNull(thisClass.jsExportIgnore())), SerialEntityNames.SERIALIZER_PROVIDER_NAME, CallableMemberDescriptor.Kind.SYNTHESIZED, thisClass.source @@ -500,7 +501,6 @@ object KSerializerDescriptorResolver { return f } - private fun KotlinType.makeNullableIfNotPrimitive() = if (KotlinBuiltIns.isPrimitiveType(this)) this else this.makeNullable() @@ -508,7 +508,7 @@ object KSerializerDescriptorResolver { fun createWriteSelfFunctionDescriptor(thisClass: ClassDescriptor): SimpleFunctionDescriptor { val jvmStaticClass = thisClass.module.findClassAcrossModuleDependencies(StandardClassIds.Annotations.JvmStatic)!! val jvmStaticAnnotation = AnnotationDescriptorImpl(jvmStaticClass.defaultType, mapOf(), jvmStaticClass.source) - val annotations = Annotations.create(listOf(jvmStaticAnnotation)) + val annotations = Annotations.create(listOfNotNull(jvmStaticAnnotation, thisClass.jsExportIgnore())) val f = SimpleFunctionDescriptorImpl.create( thisClass, diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SearchUtils.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SearchUtils.kt index a0a7a9a4afd..9d3ae7d7cf2 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SearchUtils.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SearchUtils.kt @@ -82,6 +82,9 @@ fun ClassDescriptor.getKSerializer(): ClassDescriptor = ) )!! +fun ModuleDescriptor.getJsExportIgnore(): ClassDescriptor? = + findClassAcrossModuleDependencies(SerializationJsDependenciesClassIds.jsExportIgnore) + fun getInternalPackageFqn(classSimpleName: String): FqName = SerializationPackages.internalPackageFqName.child(Name.identifier(classSimpleName)) diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirResolveExtension.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirResolveExtension.kt index ab91c67abe0..ce4956f42c4 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirResolveExtension.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirResolveExtension.kt @@ -175,8 +175,8 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene symbol = FirNamedFunctionSymbol(callableId) origin = SerializationPluginKey.origin status = original.status.copy(modality = Modality.FINAL) - } + copy.excludeFromJsExport() return listOf(copy.symbol) } @@ -208,6 +208,8 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene } } + function.excludeFromJsExport() + return function.symbol } @@ -224,6 +226,8 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene target.resolvedReturnType ) + property.excludeFromJsExport() + return listOf(property.symbol) } @@ -270,6 +274,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene } // TODO: add deprecate hidden // serializerFirClass.replaceAnnotations(listOf(Annotations.create(listOf(KSerializerDescriptorResolver.createDeprecatedHiddenAnnotation(thisDescriptor.module))))) + serializerFirClass.excludeFromJsExport() return serializerFirClass.symbol } @@ -282,6 +287,7 @@ class SerializationFirResolveExtension(session: FirSession) : FirDeclarationGene superType(serializerFactoryClassId.constructClassLikeType(emptyArray(), false)) } } + return companion.symbol } diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt index 0d142e86c9b..a65a1b4e835 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k2/src/org/jetbrains/kotlinx/serialization/compiler/fir/SerializationFirUtils.kt @@ -6,7 +6,9 @@ package org.jetbrains.kotlinx.serialization.compiler.fir import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.fir.FirAnnotationContainer import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.expressions.* @@ -14,15 +16,28 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.arguments import org.jetbrains.kotlin.fir.resolve.createSubstitutionForSupertype +import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall +import org.jetbrains.kotlin.fir.extensions.FirExtension import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider +import org.jetbrains.kotlin.fir.moduleData +import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference +import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.substitution.ChainedSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.scopes.platformSpecificOverridabilityRules +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.isJs +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlinx.serialization.compiler.fir.services.dependencySerializationInfoProvider import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations @@ -30,6 +45,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotat import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.metaSerializableAnnotationClassId import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialInfoClassId import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationAnnotations.serialNameAnnotationClassId +import org.jetbrains.kotlinx.serialization.compiler.resolve.SerializationJsDependenciesClassIds object AnnotationParameterNames { val VALUE = Name.identifier("value") @@ -217,3 +233,27 @@ val ConeKotlinType.isTypeParameter: Boolean context(FirSession) val ConeKotlinType.isGeneratedSerializableObject: Boolean get() = toRegularClassSymbol(this@FirSession)?.let { it.classKind.isObject && it.hasSerializableOrMetaAnnotationWithoutArgs } ?: false + + +context(FirExtension) +fun FirAnnotationContainer.excludeFromJsExport() { + if (!session.moduleData.platform.isJs()) { + return + } + val jsExportIgnore = session.symbolProvider.getClassLikeSymbolByClassId(SerializationJsDependenciesClassIds.jsExportIgnore) + val jsExportIgnoreAnnotation = jsExportIgnore as? FirRegularClassSymbol ?: return + val jsExportIgnoreConstructor = jsExportIgnoreAnnotation.declarationSymbols.firstIsInstanceOrNull() ?: return + + val jsExportIgnoreAnnotationCall = buildAnnotationCall { + argumentList = buildResolvedArgumentList(linkedMapOf()) + annotationTypeRef = buildResolvedTypeRef { + type = jsExportIgnoreAnnotation.defaultType() + } + calleeReference = buildResolvedNamedReference { + name = jsExportIgnoreAnnotation.name + resolvedSymbol = jsExportIgnoreConstructor + } + } + + replaceAnnotations(annotations + jsExportIgnoreAnnotationCall) +} diff --git a/plugins/kotlinx-serialization/testData/boxIr/excludedFromExport.kt b/plugins/kotlinx-serialization/testData/boxIr/excludedFromExport.kt new file mode 100644 index 00000000000..8446030e741 --- /dev/null +++ b/plugins/kotlinx-serialization/testData/boxIr/excludedFromExport.kt @@ -0,0 +1,47 @@ +// WITH_STDLIB +// TARGET_BACKEND: JS_IR +// TARGET_BACKEND: JS_IR_ES6 +// RUN_PLAIN_BOX_FUNCTION +// INFER_MAIN_MODULE + +// MODULE: lib +// FILE: lib.kt + +import kotlinx.serialization.* +import kotlinx.serialization.json.* +import kotlinx.serialization.descriptors.* + +@JsExport +@Serializable +class Basic(val name: String, val age: UInt) + +@JsExport +@Serializable +class WithCompanion(val name: String, val age: UInt) { + companion object { + fun foo() = "Test" + } +} + +// FILE: test.js +function box() { + const { Basic, WithCompanion } = this.lib; + + if (Basic.Companion === undefined) return "fail: Unfortunatly we can't exclude the companion from export because it would break logic of other plugins"; + + const basic = new Basic("Test", 44); + + if (basic.name !== "Test") return "fail: something wrong with a simple string field access"; + if (basic.age !== 44) return "fail: something wrong with a simple uint field access"; + + if (WithCompanion.Companion === undefined) return "fail: User defined companion should be exported"; + if (WithCompanion.Companion.serializer !== undefined) return "fail: serializer fabric should not be exported"; + + const withCompanion = new WithCompanion("Test", 44); + + if (withCompanion.name !== "Test") return "fail: something wrong with a simple string field access"; + if (withCompanion.age !== 44) return "fail: something wrong with a simple uint field access"; + if (WithCompanion.Companion.foo() !== "Test") return "fail: something wrong with user defined function inside companion" + + return "OK" +} diff --git a/plugins/kotlinx-serialization/testData/boxIr/excludedFromFileExport.kt b/plugins/kotlinx-serialization/testData/boxIr/excludedFromFileExport.kt new file mode 100644 index 00000000000..40705fdf775 --- /dev/null +++ b/plugins/kotlinx-serialization/testData/boxIr/excludedFromFileExport.kt @@ -0,0 +1,51 @@ +// WITH_STDLIB +// TARGET_BACKEND: JS_IR +// TARGET_BACKEND: JS_IR_ES6 +// RUN_PLAIN_BOX_FUNCTION +// INFER_MAIN_MODULE + +// MODULE: lib +// FILE: lib.kt +@file:JsExport + +import kotlinx.serialization.* +import kotlinx.serialization.json.* +import kotlinx.serialization.descriptors.* + +@Serializable +class Basic(val name: String, val age: UInt) + +@Serializable +class WithCompanion(val name: String, val age: UInt) { + companion object { + fun foo() = "Test" + } +} + +// FILE: test.js +function box() { + const pkg = this.lib; + const exportedDeclarationNames = Object.keys(pkg); + + if (exportedDeclarationNames.length != 2) return "fail: expect to have only 'Basic' and 'WithComapnion' names, but got: " + exportedDeclarationNames.join(", ") + + const { Basic, WithCompanion } = pkg; + + if (Basic.Companion === undefined) return "fail: Unfortunatly we can't exclude the companion from export because it would break logic of other plugins"; + + const basic = new Basic("Test", 44); + + if (basic.name !== "Test") return "fail: something wrong with a simple string field access"; + if (basic.age !== 44) return "fail: something wrong with a simple uint field access"; + + if (WithCompanion.Companion === undefined) return "fail: User defined companion should be exported"; + if (WithCompanion.Companion.serializer !== undefined) return "fail: serializer fabric should not be exported"; + + const withCompanion = new WithCompanion("Test", 44); + + if (withCompanion.name !== "Test") return "fail: something wrong with a simple string field access"; + if (withCompanion.age !== 44) return "fail: something wrong with a simple uint field access"; + if (WithCompanion.Companion.foo() !== "Test") return "fail: something wrong with user defined function inside companion" + + return "OK" +} diff --git a/plugins/kotlinx-serialization/testData/boxIr/serialInfo.kt b/plugins/kotlinx-serialization/testData/boxIr/serialInfo.kt index 61c890c2ee5..bda09f55655 100644 --- a/plugins/kotlinx-serialization/testData/boxIr/serialInfo.kt +++ b/plugins/kotlinx-serialization/testData/boxIr/serialInfo.kt @@ -1,3 +1,4 @@ +// TARGET_BACKEND: JVM_IR // WITH_STDLIB import kotlinx.serialization.* diff --git a/plugins/kotlinx-serialization/testData/diagnostics/Transients.txt b/plugins/kotlinx-serialization/testData/diagnostics/Transients.txt index 86d03badc42..348868f9b60 100644 --- a/plugins/kotlinx-serialization/testData/diagnostics/Transients.txt +++ b/plugins/kotlinx-serialization/testData/diagnostics/Transients.txt @@ -33,3 +33,4 @@ package public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } } + diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrJsBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrJsBoxTestGenerated.java new file mode 100644 index 00000000000..145a6d64053 --- /dev/null +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrJsBoxTestGenerated.java @@ -0,0 +1,45 @@ +/* + * 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.kotlinx.serialization.runners; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlinx.serialization.TestGeneratorKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("plugins/kotlinx-serialization/testData/boxIr") +@TestDataPath("$PROJECT_ROOT") +public class SerializationIrJsBoxTestGenerated extends AbstractSerializationIrJsBoxTest { + @Test + public void testAllFilesPresentInBoxIr() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/kotlinx-serialization/testData/boxIr"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @Test + @TestMetadata("constValInSerialName.kt") + public void testConstValInSerialName() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/constValInSerialName.kt"); + } + + @Test + @TestMetadata("excludedFromExport.kt") + public void testExcludedFromExport() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/excludedFromExport.kt"); + } + + @Test + @TestMetadata("excludedFromFileExport.kt") + public void testExcludedFromFileExport() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/excludedFromFileExport.kt"); + } +} diff --git a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt index ce3a36eb83c..19ab5efdc4e 100644 --- a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt +++ b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/TestGenerator.kt @@ -56,6 +56,10 @@ fun main(args: Array) { testClass { model("boxWithoutRuntime") } + + testClass { + model("boxIr") + } } } } diff --git a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt index 6c4a9c5740e..cecdd28d20a 100644 --- a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt +++ b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/runners/BoxTests.kt @@ -9,6 +9,8 @@ import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.runners.codegen.AbstractFirLightTreeBlackBoxCodegenTest import org.jetbrains.kotlin.test.runners.codegen.AbstractIrBlackBoxCodegenTest import org.jetbrains.kotlinx.serialization.configureForKotlinxSerialization +import org.jetbrains.kotlin.js.test.ir.AbstractJsIrTest; +import org.jetbrains.kotlin.test.TargetBackend open class AbstractSerializationIrBoxTest : AbstractIrBlackBoxCodegenTest() { override fun configure(builder: TestConfigurationBuilder) { @@ -30,3 +32,13 @@ open class AbstractSerializationFirLightTreeBlackBoxTest : AbstractFirLightTreeB builder.configureForKotlinxSerialization() } } + +open class AbstractSerializationIrJsBoxTest : AbstractJsIrTest( + pathToTestDir = "plugins/kotlinx-serialization/testData/boxIr/", + testGroupOutputDirPrefix = "codegen/serializationBoxIr/" +) { + override fun configure(builder: TestConfigurationBuilder) { + super.configure(builder) + builder.configureForKotlinxSerialization(target = TargetBackend.JS_IR) + } +} \ No newline at end of file diff --git a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt index 29abbf9f296..e2609859fb3 100644 --- a/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt +++ b/plugins/kotlinx-serialization/tests/org/jetbrains/kotlinx/serialization/serializationConfiguration.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter +import org.jetbrains.kotlin.test.TargetBackend import org.jetbrains.kotlin.test.bind import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.model.TestModule @@ -39,15 +40,32 @@ class SerializationEnvironmentConfigurator( } } -class SerializationRuntimeClasspathProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) { +class SerializationRuntimeClasspathJvmProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) { override fun runtimeClassPaths(module: TestModule): List { return librariesPaths } } -fun TestConfigurationBuilder.configureForKotlinxSerialization(noLibraries: Boolean = false) { - useConfigurators(::SerializationEnvironmentConfigurator.bind(noLibraries)) - if (!noLibraries) { - useCustomRuntimeClasspathProviders(::SerializationRuntimeClasspathProvider) +class SerializationRuntimeClasspathJsProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) { + override fun runtimeClassPaths(module: TestModule): List { + return listOf( + File(System.getProperty("serialization.core.path")!!), + File(System.getProperty("serialization.json.path")!!), + ) + } +} + +fun TestConfigurationBuilder.configureForKotlinxSerialization( + noLibraries: Boolean = false, + target: TargetBackend = TargetBackend.JVM +) { + useConfigurators(::SerializationEnvironmentConfigurator.bind(noLibraries)) + + if (!noLibraries) { + when (target) { + TargetBackend.JVM, TargetBackend.JVM_IR -> useCustomRuntimeClasspathProviders(::SerializationRuntimeClasspathJvmProvider) + TargetBackend.JS_IR, TargetBackend.JS_IR_ES6 -> useCustomRuntimeClasspathProviders(::SerializationRuntimeClasspathJsProvider) + else -> error("Unsupported backend") + } } }