[K/JS] feat: add logic under the flag for strict implicit export generating inside d.ts files.

This commit is contained in:
Artem Kobzar
2022-08-09 16:48:59 +00:00
committed by Space
parent 8fcbe9902c
commit 87038e7d8a
23 changed files with 641 additions and 25 deletions
@@ -207,6 +207,13 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
)
var generateDts: Boolean by FreezableVar(false)
@Argument(
value = "-Xstrict-implicit-export-types",
description = "Generate strict types for implicitly exported entities inside d.ts files. Available in IR backend only."
)
var strictImplicitExportType: Boolean by FreezableVar(false)
@GradleOption(DefaultValues.BooleanTrueDefault::class)
@Argument(value = "-Xtyped-arrays", description = "Translate primitive arrays to JS typed arrays")
var typedArrays: Boolean by FreezableVar(true)
@@ -503,6 +503,9 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
configuration.put(JSConfigurationKeys.FRIEND_PATHS_DISABLED, arguments.friendModulesDisabled)
configuration.put(JSConfigurationKeys.GENERATE_STRICT_IMPLICIT_EXPORT, arguments.strictImplicitExportType)
val friendModules = arguments.friendModules
if (!arguments.friendModulesDisabled && friendModules != null) {
val friendPaths = friendModules
@@ -311,6 +311,8 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
val doNotIntrinsifyAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("DoNotIntrinsify"))
val jsFunAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("JsFun"))
val jsImplicitExportAnnotationSymbol = context.symbolTable.referenceClass(context.getJsInternalClass("JsImplicitExport"))
// TODO move CharSequence-related stiff to IntrinsifyCallsLowering
val charSequenceClassSymbol = context.symbolTable.referenceClass(context.getClass(FqName("kotlin.CharSequence")))
val charSequenceLengthPropertyGetterSymbol by context.lazy2 {
@@ -798,6 +798,12 @@ private val escapedIdentifiersLowering = makeBodyLoweringPhase(
description = "Convert global variables with invalid names access to globalThis member expression"
)
private val implicitlyExportedDeclarationsMarkingLowering = makeDeclarationTransformerPhase(
::ImplicitlyExportedDeclarationsMarkingLowering,
name = "ImplicitlyExportedDeclarationsMarkingLowering",
description = "Add @JsImplicitExport annotation to declarations which are not exported but are used inside other exported declarations as a type"
)
private val cleanupLoweringPhase = makeBodyLoweringPhase(
{ CleanupLowering() },
name = "CleanupLowering",
@@ -920,6 +926,7 @@ val loweringList = listOf<Lowering>(
captureStackTraceInThrowablesPhase,
callsLoweringPhase,
escapedIdentifiersLowering,
implicitlyExportedDeclarationsMarkingLowering,
cleanupLoweringPhase,
// Currently broken due to static members lowering making single-open-class
// files non-recognizable as single-class files
@@ -61,7 +61,6 @@ class ExportedProperty(
val irSetter: IrFunction? = null,
) : ExportedDeclaration()
// TODO: Cover all cases with frontend and disable error declarations
class ErrorDeclaration(val message: String) : ExportedDeclaration()
@@ -22,6 +22,8 @@ import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.runIf
@@ -53,7 +55,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
private fun exportDeclaration(declaration: IrDeclaration): ExportedDeclaration? {
val candidate = getExportCandidate(declaration) ?: return null
if (!shouldDeclarationBeExported(candidate, context)) return null
if (!shouldDeclarationBeExportedImplicitlyOrExplicitly(candidate, context)) return null
return when (candidate) {
is IrSimpleFunction -> exportFunction(candidate)
@@ -74,9 +76,10 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
}
}
private fun exportFunction(function: IrSimpleFunction): ExportedDeclaration? {
return when (val exportability = functionExportability(function)) {
is Exportability.NotNeeded -> null
is Exportability.NotNeeded, is Exportability.Implicit -> null
is Exportability.Prohibited -> ErrorDeclaration(exportability.reason)
is Exportability.Allowed -> {
val parent = function.parent
@@ -201,18 +204,44 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
}
}
if (klass.isJsImplicitExport()) {
return Exportability.Implicit
}
if (klass.isSingleFieldValueClass)
return Exportability.Prohibited("Inline class ${klass.fqNameWhenAvailable}")
return Exportability.Allowed
}
private fun exportDeclarationImplicitly(klass: IrClass, superTypes: Iterable<IrType>): ExportedDeclaration {
val typeParameters = klass.typeParameters.map(::exportTypeParameter)
val superInterfaces = superTypes
.filter { (it.classifierOrFail.owner as? IrDeclaration)?.isExportedImplicitlyOrExplicitly(context) ?: false }
.map { exportType(it) }
.filter { it !is ExportedType.ErrorType }
val name = klass.getExportedIdentifier()
val (members, nestedClasses) = exportClassDeclarations(klass, superTypes)
return ExportedRegularClass(
name = name,
isInterface = true,
isAbstract = false,
superClasses = emptyList(),
superInterfaces = superInterfaces,
typeParameters = typeParameters,
members = members,
nestedClasses = nestedClasses,
ir = klass
)
}
private fun exportOrdinaryClass(klass: IrClass, superTypes: Iterable<IrType>): ExportedDeclaration? {
when (val exportability = classExportability(klass)) {
is Exportability.Prohibited -> error(exportability.reason)
is Exportability.NotNeeded -> return null
Exportability.Allowed -> {
}
Exportability.NotNeeded -> return null
Exportability.Implicit -> return exportDeclarationImplicitly(klass, superTypes)
Exportability.Allowed -> {}
}
val (members, nestedClasses) = exportClassDeclarations(klass, superTypes)
@@ -228,9 +257,9 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
private fun exportEnumClass(klass: IrClass, superTypes: Iterable<IrType>): ExportedDeclaration? {
when (val exportability = classExportability(klass)) {
is Exportability.Prohibited -> error(exportability.reason)
is Exportability.NotNeeded -> return null
Exportability.Allowed -> {
}
Exportability.NotNeeded -> return null
Exportability.Implicit -> return exportDeclarationImplicitly(klass, superTypes)
Exportability.Allowed -> {}
}
val enumEntries = klass
@@ -267,10 +296,12 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
): ExportedClassDeclarationsInfo {
val members = mutableListOf<ExportedDeclaration>()
val nestedClasses = mutableListOf<ExportedClass>()
val isImplicitlyExportedClass = klass.isJsImplicitExport()
for (declaration in klass.declarations) {
val candidate = getExportCandidate(declaration) ?: continue
if (!shouldDeclarationBeExported(candidate, context)) continue
if (isImplicitlyExportedClass && candidate !is IrClass) continue
if (!shouldDeclarationBeExportedImplicitlyOrExplicitly(candidate, context)) continue
val processingResult = specialProcessing(candidate)
if (processingResult != null) {
@@ -324,13 +355,13 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
}
private fun IrClass.shouldNotBeImplemented(): Boolean {
return isInterface && !isExternal
return isInterface && !isExternal || isJsImplicitExport()
}
private fun IrClass.shouldContainImplementationOfMagicProperty(superTypes: Iterable<IrType>): Boolean {
return !isExternal && superTypes.any {
val superClass = it.classOrNull?.owner ?: return@any false
superClass.isInterface && superClass.isExported(context)
superClass.isInterface && superClass.isExported(context) || superClass.isJsImplicitExport()
}
}
@@ -339,11 +370,13 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
}
private fun MutableList<ExportedDeclaration>.addMagicPropertyForInterfaceImplementation(klass: IrClass, superTypes: Iterable<IrType>) {
val superTypesToInheritanceMagicProperty = superTypes.filter { it.shouldAddMagicPropertyOfSuper() }
val allSuperTypesWithMagicProperty = superTypes.filter { it.shouldAddMagicPropertyOfSuper() }
if (superTypesToInheritanceMagicProperty.isEmpty()) return
if (allSuperTypesWithMagicProperty.isEmpty()) {
return
}
val intersectionOfTypes = superTypesToInheritanceMagicProperty
val intersectionOfTypes = allSuperTypesWithMagicProperty
.map { ExportedType.PropertyType(exportType(it), ExportedType.LiteralType.StringLiteralType(magicPropertyName)) }
.reduce(ExportedType::IntersectionType)
.let { if (klass.shouldNotBeImplemented()) ExportedType.IntersectionType(klass.generateTagType(), it) else it }
@@ -356,8 +389,11 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
}
private fun IrClass.isOwnMagicPropertyAdded(): Boolean {
if (isJsImplicitExport()) return true
if (!isExported(context)) return false
return isInterface && !isExternal || superTypes.any { it.classOrNull?.owner?.isOwnMagicPropertyAdded() ?: false }
return isInterface && !isExternal || superTypes.any {
it.classOrNull?.owner?.isOwnMagicPropertyAdded() == true
}
}
private fun IrClass.generateTagType(): ExportedType {
@@ -388,7 +424,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
.filter { it !is ExportedType.ErrorType }
val superInterfaces = superTypes
.filter { it.classifierOrFail.isInterface }
.filter { it.shouldPresentInsideImplementsClause() }
.map { exportType(it, false) }
.filter { it !is ExportedType.ErrorType }
@@ -419,9 +455,14 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
}
}
private fun IrSimpleType.collectSuperTransitiveHierarchy() =
private fun IrSimpleType.collectSuperTransitiveHierarchy(): Set<IrType> =
transitiveExportCollector.collectSuperTypesTransitiveHierarchyFor(this)
private fun IrType.shouldPresentInsideImplementsClause(): Boolean {
val classifier = classifierOrFail
return classifier.isInterface || (classifier.owner as? IrDeclaration)?.isJsImplicitExport() == true
}
private fun exportAsEnumMember(
candidate: IrDeclarationWithName,
enumEntriesToOrdinal: Map<IrEnumEntry, Int>
@@ -460,7 +501,9 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
}
private fun IrType.canBeUsedAsSuperTypeOfExportedClasses(): Boolean =
!this.isAny() && classifierOrNull != context.irBuiltIns.enumClass
!isAny() &&
classifierOrNull != context.irBuiltIns.enumClass &&
(classifierOrNull?.owner as? IrDeclaration)?.isJsImplicitExport() != true
private fun exportTypeArgument(type: IrTypeArgument): ExportedType {
if (type is IrTypeProjection)
@@ -541,7 +584,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
classifier is IrClassSymbol -> {
val klass = classifier.owner
val isExported = klass.isExported(context)
val isExported = klass.isExportedImplicitlyOrExplicitly(context)
val isImplicitlyExported = !isExported && !klass.isExternal
val isNonExportedExternal = klass.isExternal && !isExported
val name = klass.getFqNameWithJsNameWhenAvailable(!isNonExportedExternal && generateNamespacesForPackages).asString()
@@ -630,6 +673,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
sealed class Exportability {
object Allowed : Exportability()
object NotNeeded : Exportability()
object Implicit : Exportability()
class Prohibited(val reason: String) : Exportability()
}
@@ -670,6 +714,10 @@ private fun getExportCandidate(declaration: IrDeclaration): IrDeclarationWithNam
return declaration
}
private fun shouldDeclarationBeExportedImplicitlyOrExplicitly(declaration: IrDeclarationWithName, context: JsIrBackendContext): Boolean {
return declaration.isJsImplicitExport() || shouldDeclarationBeExported(declaration, context)
}
private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, context: JsIrBackendContext): Boolean {
if (context.additionalExportedDeclarationNames.contains(declaration.fqNameWhenAvailable))
return true
@@ -727,6 +775,11 @@ fun IrDeclaration.isExported(context: JsIrBackendContext): Boolean {
return shouldDeclarationBeExported(candidate, context)
}
fun IrDeclaration.isExportedImplicitlyOrExplicitly(context: JsIrBackendContext): Boolean {
val candidate = getExportCandidate(this) ?: return false
return shouldDeclarationBeExportedImplicitlyOrExplicitly(candidate, context)
}
private fun DescriptorVisibility.toExportedVisibility() =
when (this) {
DescriptorVisibilities.PROTECTED -> ExportedVisibility.PROTECTED
@@ -12,6 +12,10 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.superTypes
private typealias SubstitutionMap = Map<IrTypeParameterSymbol, IrType>
@@ -34,13 +38,26 @@ class TransitiveExportCollector(val context: JsIrBackendContext) {
.toSet()
}
private fun IrSimpleType.findNearestExportedClass(typeSubstitutionMap: SubstitutionMap): IrSimpleType? {
val classifier = classifier as? IrClassSymbol ?: return null
if (classifier.owner.isExported(context)) return substitute(typeSubstitutionMap) as IrSimpleType
return classifier.superTypes()
.firstNotNullOfOrNull { (it as? IrSimpleType)?.findNearestExportedClass(typeSubstitutionMap) }
}
private fun IrSimpleType.collectTransitiveHierarchy(typeSubstitutionMap: SubstitutionMap): Set<IrType> {
val owner = classifier.owner as? IrClass ?: return emptySet()
val substitutionMap = calculateTypeSubstitutionMap(typeSubstitutionMap)
return when {
isBuiltInClass(owner) || isStdLibClass(owner) -> emptySet()
owner.isExported(context) -> setOf(substitute(typeSubstitutionMap))
owner.isExported(context) -> setOf(substitute(substitutionMap))
owner.isJsImplicitExport() -> setOfNotNull(
substitute(typeSubstitutionMap),
takeIf { !owner.isInterface }?.findNearestExportedClass(substitutionMap)
)
else -> collectSuperTypesTransitiveHierarchy(substitutionMap)
}
}
@@ -62,4 +79,4 @@ class TransitiveExportCollector(val context: JsIrBackendContext) {
}
private data class ClassWithAppliedArguments(val classSymbol: IrClassSymbol, val appliedArguments: List<IrTypeArgument>)
}
}
@@ -0,0 +1,93 @@
/*
* Copyright 2010-2021 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.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.export.isExported
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.isPrimitiveArray
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
class ImplicitlyExportedDeclarationsMarkingLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
private val strictImplicitExport = context.configuration.getBoolean(JSConfigurationKeys.GENERATE_STRICT_IMPLICIT_EXPORT)
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (!strictImplicitExport || !declaration.isExported(context)) return null
val implicitlyExportedDeclarations = when (declaration) {
is IrFunction -> declaration.collectImplicitlyExportedDeclarations()
is IrClass -> declaration.collectImplicitlyExportedDeclarations()
is IrProperty -> declaration.collectImplicitlyExportedDeclarations()
else -> emptySet()
}
implicitlyExportedDeclarations.forEach { it.markWithJsImplicitExport() }
return null
}
private fun IrClass.collectImplicitlyExportedDeclarations(): Set<IrDeclaration> {
return typeParameters
.flatMap { it.superTypes }.toSet()
.flatMap { it.collectImplicitlyExportedDeclarations() }.toSet()
}
private fun IrFunction.collectImplicitlyExportedDeclarations(): Set<IrDeclaration> {
val types = buildSet {
add(returnType)
addAll(valueParameters.map { it.type })
addAll(typeParameters.flatMap { it.superTypes })
}
return types.flatMap { it.collectImplicitlyExportedDeclarations() }.toSet()
}
private fun IrProperty.collectImplicitlyExportedDeclarations(): Set<IrDeclaration> {
val getterImplicitlyExportedDeclarations = getter?.collectImplicitlyExportedDeclarations() ?: emptySet()
val setterImplicitlyExportedDeclarations = setter?.collectImplicitlyExportedDeclarations() ?: emptySet()
val fieldImplicitlyExportedDeclarations = backingField?.type?.collectImplicitlyExportedDeclarations() ?: emptySet()
return getterImplicitlyExportedDeclarations + setterImplicitlyExportedDeclarations + fieldImplicitlyExportedDeclarations
}
private fun IrType.collectImplicitlyExportedDeclarations(): Set<IrDeclaration> {
if (this is IrDynamicType || this !is IrSimpleType)
return emptySet()
val nonNullType = makeNotNull() as IrSimpleType
val classifier = nonNullType.classifier
return when {
nonNullType.isPrimitiveType() || nonNullType.isPrimitiveArray() || nonNullType.isAny() || nonNullType.isUnit() -> emptySet()
classifier is IrTypeParameterSymbol -> classifier.owner.superTypes.flatMap { it.collectImplicitlyExportedDeclarations() }
.toSet()
classifier is IrClassSymbol -> setOfNotNull(classifier.owner.takeIf { it.shouldBeMarkedWithImplicitExport() })
else -> emptySet()
}
}
private fun IrDeclaration.shouldBeMarkedWithImplicitExport(): Boolean {
return this is IrClass && !isExternal && !isExported(context) && !isJsImplicitExport()
}
private fun IrDeclaration.markWithJsImplicitExport() {
val jsImplicitExportCtor = context.intrinsics.jsImplicitExportAnnotationSymbol.constructors.single()
annotations += context.createIrBuilder(symbol).irCall(jsImplicitExportCtor)
parentClassOrNull?.takeIf { it.shouldBeMarkedWithImplicitExport() }?.markWithJsImplicitExport()
}
}
@@ -23,6 +23,7 @@ object JsAnnotations {
val jsNameFqn = FqName("kotlin.js.JsName")
val jsQualifierFqn = FqName("kotlin.js.JsQualifier")
val jsExportFqn = FqName("kotlin.js.JsExport")
val jsImplicitExportFqn = FqName("kotlin.js.JsImplicitExport")
val jsNativeGetter = FqName("kotlin.js.nativeGetter")
val jsNativeSetter = FqName("kotlin.js.nativeSetter")
val jsNativeInvoke = FqName("kotlin.js.nativeInvoke")
@@ -34,6 +35,10 @@ object JsAnnotations {
fun IrConstructorCall.getSingleConstStringArgument() =
(getValueArgument(0) as IrConst<String>).value
@Suppress("UNCHECKED_CAST")
fun IrConstructorCall.getSingleConstBooleanArgument() =
(getValueArgument(0) as IrConst<Boolean>).value
fun IrAnnotationContainer.getJsModule(): String? =
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
@@ -58,6 +63,9 @@ fun IrAnnotationContainer.getJsFunAnnotation(): String? =
fun IrAnnotationContainer.isJsExport(): Boolean =
hasAnnotation(JsAnnotations.jsExportFqn)
fun IrAnnotationContainer.isJsImplicitExport(): Boolean =
hasAnnotation(JsAnnotations.jsImplicitExportFqn)
fun IrAnnotationContainer.isJsNativeGetter(): Boolean = hasAnnotation(JsAnnotations.jsNativeGetter)
fun IrAnnotationContainer.isJsNativeSetter(): Boolean = hasAnnotation(JsAnnotations.jsNativeSetter)
+1
View File
@@ -38,6 +38,7 @@ where advanced options include:
-Xmetadata-only Generate *.meta.js and *.kjsm files only
-Xpartial-linkage Allow unlinked symbols
-Xrepositories=<path> Paths to additional places where libraries could be found
-Xstrict-implicit-export-types Generate strict types for implicitly exported entities inside d.ts files. Available in IR backend only.
-Xtyped-arrays Translate primitive arrays to JS typed arrays
-Xwasm Use experimental WebAssembly compiler backend
-Xwasm-debug-info Add debug info to WebAssembly compiled module
@@ -117,6 +117,11 @@ object JsEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
applicability = DirectiveApplicability.Global
)
val GENERATE_STRICT_IMPLICIT_EXPORT by directive(
description = "enable strict implicitly exported entities types inside d.ts files",
applicability = DirectiveApplicability.Global
)
val SAFE_EXTERNAL_BOOLEAN by directive(
description = "",
applicability = DirectiveApplicability.Global
@@ -125,6 +125,11 @@ fun TargetPlatform.platformToEnvironmentConfigFiles() = when {
fun createCompilerConfiguration(module: TestModule, configurators: List<AbstractEnvironmentConfigurator>): CompilerConfiguration {
val configuration = CompilerConfiguration()
configuration[CommonConfigurationKeys.MODULE_NAME] = module.name
if (JsEnvironmentConfigurationDirectives.GENERATE_STRICT_IMPLICIT_EXPORT in module.directives) {
configuration.put(JSConfigurationKeys.GENERATE_STRICT_IMPLICIT_EXPORT, true)
}
if (module.frontendKind == FrontendKinds.FIR) {
configuration[CommonConfigurationKeys.USE_FIR] = true
}
@@ -103,6 +103,9 @@ public class JSConfigurationKeys {
public static final CompilerConfigurationKey<Boolean> GENERATE_INLINE_ANONYMOUS_FUNCTIONS =
CompilerConfigurationKey.create("translate lambdas into in-line anonymous functions");
public static final CompilerConfigurationKey<Boolean> GENERATE_STRICT_IMPLICIT_EXPORT =
CompilerConfigurationKey.create("enable strict implicitly exported entities types inside d.ts files");
public static final CompilerConfigurationKey<Boolean> WASM_ENABLE_ARRAY_RANGE_CHECKS =
CompilerConfigurationKey.create("enable array range checks");
@@ -373,6 +373,22 @@ public class IrJsTypeScriptExportTestGenerated extends AbstractIrJsTypeScriptExp
}
}
@Nested
@TestMetadata("js/js.translator/testData/typescript-export/strictImplicitExport")
@TestDataPath("$PROJECT_ROOT")
public class StrictImplicitExport {
@Test
public void testAllFilesPresentInStrictImplicitExport() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/typescript-export/strictImplicitExport"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("declarations.kt")
public void testDeclarations() throws Exception {
runTest("js/js.translator/testData/typescript-export/strictImplicitExport/declarations.kt");
}
}
@Nested
@TestMetadata("js/js.translator/testData/typescript-export/visibility")
@TestDataPath("$PROJECT_ROOT")
@@ -41,5 +41,6 @@ declare namespace JS_TESTS {
function bar(): Error;
const console: Console;
const error: WebAssembly.CompileError;
function functionWithTypeAliasInside(x: any/* foo.NonExportedGenericInterface<foo.NonExportedType> */): any/* foo.NonExportedGenericInterface<foo.NonExportedType> */;
}
}
@@ -85,4 +85,11 @@ val console: Console
@JsExport
val error: CompileError
get() = js("{}")
get() = js("{}")
typealias NotExportedTypeAlias = NonExportedGenericInterface<NonExportedType>
@JsExport
fun functionWithTypeAliasInside(x: NotExportedTypeAlias): NotExportedTypeAlias {
return x
}
@@ -18,4 +18,4 @@ declare namespace JS_TESTS {
inlineFun(x: number, callback: (p0: number) => void): void;
}
}
}
}
@@ -0,0 +1,147 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
namespace foo {
const forth: foo.Forth;
interface ExportedInterface {
readonly __doNotUseOrImplementIt: {
readonly "foo.ExportedInterface": unique symbol;
};
}
function producer(value: number): foo.NonExportedType;
function consumer(value: foo.NonExportedType): number;
function childProducer(value: number): foo.NotExportedChildClass;
function childConsumer(value: foo.NotExportedChildClass): number;
function genericChildProducer<T extends foo.NonExportedGenericType<number>>(value: T): foo.NotExportedChildGenericClass<T>;
function genericChildConsumer<T extends foo.NonExportedGenericType<number>>(value: foo.NotExportedChildGenericClass<T>): T;
class A implements foo.NonExportedParent.NonExportedSecond.NonExportedUsedChild {
constructor(value: foo.NonExportedType);
get value(): foo.NonExportedType;
set value(value: foo.NonExportedType);
increment<T extends foo.NonExportedType>(t: T): foo.NonExportedType;
getNonExportedUserChild(): foo.NonExportedParent.NonExportedSecond.NonExportedUsedChild;
readonly __doNotUseOrImplementIt: foo.NonExportedParent.NonExportedSecond.NonExportedUsedChild["__doNotUseOrImplementIt"];
}
class B implements foo.NonExportedType {
constructor(v: number);
readonly __doNotUseOrImplementIt: foo.NonExportedType["__doNotUseOrImplementIt"];
}
class C implements foo.NonExportedInterface {
constructor();
readonly __doNotUseOrImplementIt: foo.NonExportedInterface["__doNotUseOrImplementIt"];
}
class D implements foo.NonExportedInterface, foo.ExportedInterface {
constructor();
readonly __doNotUseOrImplementIt: foo.NonExportedInterface["__doNotUseOrImplementIt"] & foo.ExportedInterface["__doNotUseOrImplementIt"];
}
class E implements foo.NonExportedType, foo.ExportedInterface {
constructor();
readonly __doNotUseOrImplementIt: foo.NonExportedType["__doNotUseOrImplementIt"] & foo.ExportedInterface["__doNotUseOrImplementIt"];
}
class F extends foo.A implements foo.NonExportedInterface {
constructor();
readonly __doNotUseOrImplementIt: foo.A["__doNotUseOrImplementIt"] & foo.NonExportedInterface["__doNotUseOrImplementIt"];
}
class G implements foo.NonExportedGenericInterface<foo.NonExportedType> {
constructor();
readonly __doNotUseOrImplementIt: foo.NonExportedGenericInterface<foo.NonExportedType>["__doNotUseOrImplementIt"];
}
class H implements foo.NonExportedGenericType<foo.NonExportedType> {
constructor();
readonly __doNotUseOrImplementIt: foo.NonExportedGenericType<foo.NonExportedType>["__doNotUseOrImplementIt"];
}
class I implements foo.NotExportedChildClass {
constructor();
readonly __doNotUseOrImplementIt: foo.NotExportedChildClass["__doNotUseOrImplementIt"];
}
class J implements foo.NotExportedChildGenericClass<foo.NonExportedType> {
constructor();
readonly __doNotUseOrImplementIt: foo.NotExportedChildGenericClass<foo.NonExportedType>["__doNotUseOrImplementIt"];
}
function baz(a: number): Promise<number>;
function bar(): Error;
function pep<T extends foo.NonExportedInterface & foo.NonExportedGenericInterface<number>>(x: T): void;
const console: Console;
const error: WebAssembly.CompileError;
interface IA {
readonly __doNotUseOrImplementIt: {
readonly "foo.IA": unique symbol;
};
}
class Third extends /* foo.Second */ foo.First {
constructor();
}
class Sixth extends /* foo.Fifth */ foo.Third implements foo.Forth, foo.IC {
constructor();
readonly __doNotUseOrImplementIt: foo.Forth["__doNotUseOrImplementIt"] & foo.IC["__doNotUseOrImplementIt"];
}
class First {
constructor();
}
function acceptForthLike<T extends foo.Forth>(forth: T): void;
function acceptMoreGenericForthLike<T extends foo.IB & foo.IC & foo.Third>(forth: T): void;
interface NonExportedParent {
readonly __doNotUseOrImplementIt: {
readonly "foo.NonExportedParent": unique symbol;
};
}
namespace NonExportedParent {
interface NonExportedSecond {
readonly __doNotUseOrImplementIt: {
readonly "foo.NonExportedParent.NonExportedSecond": unique symbol;
};
}
namespace NonExportedSecond {
interface NonExportedUsedChild {
readonly __doNotUseOrImplementIt: {
readonly "foo.NonExportedParent.NonExportedSecond.NonExportedUsedChild": unique symbol;
};
}
}
}
interface NonExportedInterface {
readonly __doNotUseOrImplementIt: {
readonly "foo.NonExportedInterface": unique symbol;
};
}
interface NonExportedGenericInterface<T> {
readonly __doNotUseOrImplementIt: {
readonly "foo.NonExportedGenericInterface": unique symbol;
};
}
interface NonExportedType {
readonly __doNotUseOrImplementIt: {
readonly "foo.NonExportedType": unique symbol;
};
}
interface NonExportedGenericType<T> {
readonly __doNotUseOrImplementIt: {
readonly "foo.NonExportedGenericType": unique symbol;
};
}
interface NotExportedChildClass extends foo.NonExportedInterface, foo.NonExportedType {
readonly __doNotUseOrImplementIt: {
readonly "foo.NotExportedChildClass": unique symbol;
} & foo.NonExportedInterface["__doNotUseOrImplementIt"] & foo.NonExportedType["__doNotUseOrImplementIt"];
}
interface NotExportedChildGenericClass<T> extends foo.NonExportedInterface, foo.NonExportedGenericInterface<T>, foo.NonExportedGenericType<T> {
readonly __doNotUseOrImplementIt: {
readonly "foo.NotExportedChildGenericClass": unique symbol;
} & foo.NonExportedInterface["__doNotUseOrImplementIt"] & foo.NonExportedGenericInterface<T>["__doNotUseOrImplementIt"] & foo.NonExportedGenericType<T>["__doNotUseOrImplementIt"];
}
interface IB extends foo.IA {
readonly __doNotUseOrImplementIt: {
readonly "foo.IB": unique symbol;
} & foo.IA["__doNotUseOrImplementIt"];
}
interface IC extends foo.IB {
readonly __doNotUseOrImplementIt: {
readonly "foo.IC": unique symbol;
} & foo.IB["__doNotUseOrImplementIt"];
}
interface Forth extends foo.Third, foo.IB, foo.IC {
readonly __doNotUseOrImplementIt: {
readonly "foo.Forth": unique symbol;
} & foo.IB["__doNotUseOrImplementIt"] & foo.IC["__doNotUseOrImplementIt"];
}
}
}
@@ -0,0 +1,169 @@
// CHECK_TYPESCRIPT_DECLARATIONS
// RUN_PLAIN_BOX_FUNCTION
// SKIP_MINIFICATION
// SKIP_NODE_JS
// KJS_WITH_FULL_RUNTIME
// INFER_MAIN_MODULE
// GENERATE_STRICT_IMPLICIT_EXPORT
// MODULE: JS_TESTS
// FILE: qualified.kt
@file:JsQualifier("WebAssembly")
package qualified
external interface CompileError
// FILE: notQualified.kt
package notQualified
external interface Console
// FILE: declarations.kt
package foo
import notQualified.Console
import qualified.CompileError
interface NeverUsedInsideExportedDeclarationsType
open class NonExportedParent {
open class NonExportedSecond {
open class NonExportedUsedChild
open class NonExportedUnusedChild
}
}
interface NonExportedInterface
interface NonExportedGenericInterface<T>
open class NonExportedType(val value: Int)
open class NonExportedGenericType<T>(val value: T)
open class NotExportedChildClass : NonExportedInterface, NeverUsedInsideExportedDeclarationsType, NonExportedType(322)
open class NotExportedChildGenericClass<T>(value: T) : NonExportedInterface, NeverUsedInsideExportedDeclarationsType, NonExportedGenericInterface<T>, NonExportedGenericType<T>(value)
@JsExport
interface ExportedInterface
@JsExport
fun producer(value: Int): NonExportedType {
return NonExportedType(value)
}
@JsExport
fun consumer(value: NonExportedType): Int {
return value.value
}
@JsExport
fun childProducer(value: Int): NotExportedChildClass {
return NotExportedChildClass()
}
@JsExport
fun childConsumer(value: NotExportedChildClass): Int {
return value.value
}
@JsExport
fun <T: NonExportedGenericType<Int>> genericChildProducer(value: T): NotExportedChildGenericClass<T> {
return NotExportedChildGenericClass<T>(value)
}
@JsExport
fun <T: NonExportedGenericType<Int>> genericChildConsumer(value: NotExportedChildGenericClass<T>): T {
return value.value
}
@JsExport
open class A(var value: NonExportedType): NonExportedParent.NonExportedSecond.NonExportedUsedChild() {
fun <T: NonExportedType> increment(t: T): NonExportedType {
return NonExportedType(value = t.value + 1)
}
fun getNonExportedUserChild(): NonExportedParent.NonExportedSecond.NonExportedUsedChild {
return this
}
}
@JsExport
class B(v: Int) : NonExportedType(v)
@JsExport
class C : NonExportedInterface
@JsExport
class D : NonExportedInterface, ExportedInterface
@JsExport
class E : NonExportedType(42), ExportedInterface
@JsExport
class F : A(NonExportedType(42)), NonExportedInterface
@JsExport
class G : NonExportedGenericInterface<NonExportedType>
@JsExport
class H : NonExportedGenericType<NonExportedType>(NonExportedType(42))
@JsExport
class I : NotExportedChildClass()
@JsExport
class J : NotExportedChildGenericClass<NonExportedType>(NonExportedType(322))
@JsExport
fun baz(a: Int): kotlin.js.Promise<Int> {
return kotlin.js.Promise<Int> { res, rej -> res(a) }
}
@JsExport
fun bar(): Throwable {
return Throwable("Test Error")
}
@JsExport
fun <T> pep(x: T) where T: NonExportedInterface,
T: NonExportedGenericInterface<Int>
{}
@JsExport
val console: Console
get() = js("console")
@JsExport
val error: CompileError
get() = js("{}")
// Save hierarhy
@JsExport
interface IA
interface IB : IA
interface IC : IB
@JsExport
open class Third: Second()
open class Forth: Third(), IB, IC
open class Fifth: Forth()
@JsExport
class Sixth: Fifth(), IC
@JsExport
open class First
open class Second: First()
@JsExport
fun <T : Forth> acceptForthLike(forth: T) {}
@JsExport
fun <T> acceptMoreGenericForthLike(forth: T) where T: IB, T: IC, T: Third {}
@JsExport
val forth = Forth()
@@ -0,0 +1,28 @@
"use strict";
var producer = JS_TESTS.foo.producer;
var consumer = JS_TESTS.foo.consumer;
var A = JS_TESTS.foo.A;
var B = JS_TESTS.foo.B;
var childProducer = JS_TESTS.foo.childProducer;
var childConsumer = JS_TESTS.foo.childConsumer;
var genericChildProducer = JS_TESTS.foo.genericChildProducer;
var genericChildConsumer = JS_TESTS.foo.genericChildConsumer;
function assert(condition) {
if (!condition) {
throw "Assertion failed";
}
}
function box() {
var nonExportedType = producer(42);
var a = new A(nonExportedType);
var b = new B(43);
assert(consumer(nonExportedType) == 42);
a.value = producer(24);
assert(consumer(b) == 43);
assert(consumer(a.value) == 24);
assert(consumer(a.increment(nonExportedType)) == 43);
var oneMoreNonExportedType = childProducer(322);
assert(consumer(oneMoreNonExportedType) == 322);
assert(childConsumer(oneMoreNonExportedType) == 322);
return "OK";
}
@@ -0,0 +1,33 @@
import producer = JS_TESTS.foo.producer;
import consumer = JS_TESTS.foo.consumer;
import A = JS_TESTS.foo.A;
import B = JS_TESTS.foo.B;
import childProducer = JS_TESTS.foo.childProducer;
import childConsumer = JS_TESTS.foo.childConsumer;
import genericChildProducer = JS_TESTS.foo.genericChildProducer;
import genericChildConsumer = JS_TESTS.foo.genericChildConsumer;
function assert(condition: boolean) {
if (!condition) {
throw "Assertion failed";
}
}
function box(): string {
const nonExportedType = producer(42)
const a = new A(nonExportedType)
const b = new B(43)
assert(consumer(nonExportedType) == 42)
a.value = producer(24)
assert(consumer(b) == 43)
assert(consumer(a.value) == 24)
assert(consumer(a.increment(nonExportedType)) == 43)
const oneMoreNonExportedType = childProducer(322)
assert(consumer(oneMoreNonExportedType) == 322)
assert(childConsumer(oneMoreNonExportedType) == 322)
return "OK";
}
@@ -0,0 +1,4 @@
{
"include": [ "./*" ],
"extends": "../common.tsconfig.json"
}
@@ -42,4 +42,12 @@ internal fun safePropertySet(self: dynamic, setterName: String, propName: String
* Code gets inserted as is without syntax verification.
*/
@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()