Skip to content

Commit 70d73fc

Browse files
JSMonkSpace Team
authored andcommitted
[K/JS] Rework exporting of interfaces with Companion to be the same as for class
1 parent 871fb95 commit 70d73fc

File tree

22 files changed

+101
-271
lines changed

22 files changed

+101
-271
lines changed

compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, private val configuration
383383

384384
val jsOutlinedFunctionAnnotationSymbol: IrClassSymbol = symbolFinder.topLevelClass(JsStandardClassIds.Annotations.JsOutlinedFunction)
385385
val jsNameAnnotationSymbol: IrClassSymbol = symbolFinder.topLevelClass(JsStandardClassIds.Annotations.JsName)
386+
val jsStaticAnnotationSymbol: IrClassSymbol = symbolFinder.topLevelClass(JsStandardClassIds.Annotations.JsStatic)
386387
val jsExportAnnotationSymbol: IrClassSymbol = symbolFinder.topLevelClass(JsStandardClassIds.Annotations.JsExport)
387388
val jsGeneratorAnnotationSymbol: IrClassSymbol = symbolFinder.topLevelClass(JsStandardClassIds.Annotations.JsGenerator)
388389

compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/jsexport/ExportModelGenerator.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
260260
members: List<ExportedDeclaration>,
261261
nestedClasses: List<ExportedClass>,
262262
): ExportedDeclaration {
263-
val name = klass.getExportedIdentifierForClass()
263+
val name = klass.getExportedIdentifier()
264264

265265
return if (klass.kind == ClassKind.OBJECT) {
266266
return ExportedObject(
@@ -518,13 +518,6 @@ val strictModeReservedWords = setOf(
518518

519519
private val allReservedWords = reservedWords + strictModeReservedWords
520520

521-
fun IrClass.getExportedIdentifierForClass(): String {
522-
val parentClass = parentClassOrNull
523-
return if (parentClass != null && isCompanion && parentClass.isInterface) {
524-
parentClass.getExportedIdentifierForClass()
525-
} else getExportedIdentifier()
526-
}
527-
528521
fun IrDeclarationWithName.getExportedIdentifier(): String =
529522
with(getJsNameOrKotlinName()) {
530523
if (isSpecial)

compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/jsexport/ExportModelToJsStatements.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,15 @@ class ExportModelToJsStatements(
152152
}
153153

154154
is ExportedRegularClass -> {
155-
if (declaration.isInterface) {
156-
return declaration.nestedClasses.flatMap { generateDeclarationExport(it, namespace, esModules, parentClass) }
155+
// These are used when @JsStatic is used or exporting secondary constructors annotated with @JsName
156+
val staticFunctions = declaration.members
157+
.filter { it is ExportedFunction && it.isStatic && !it.ir.isEs6ConstructorReplacement }
158+
.takeIf { !declaration.ir.isInner }.orEmpty()
159+
160+
if (declaration.isInterface && staticFunctions.isEmpty() && declaration.nestedClasses.isEmpty()) {
161+
return emptyList()
157162
}
163+
158164
val (name, classInitialization) = declaration.getNameAndInitialization()
159165
val newNameSpace = when {
160166
namespace != null -> jsElementAccess(declaration.name, namespace)
@@ -167,11 +173,6 @@ class ExportModelToJsStatements(
167173
else -> null
168174
}
169175

170-
// These are only used when exporting secondary constructors annotated with @JsName
171-
val staticFunctions = declaration.members
172-
.filter { it is ExportedFunction && it.isStatic && !it.ir.isEs6ConstructorReplacement }
173-
.takeIf { !declaration.ir.isInner }.orEmpty()
174-
175176
val enumEntries = declaration.members.filter { it is ExportedProperty && it.isStatic }
176177

177178
val innerClassesAssignments = declaration.nestedClasses
@@ -255,7 +256,8 @@ class ExportModelToJsStatements(
255256
}
256257

257258
private fun ExportedClass.getNameAndInitialization(): Pair<JsName, JsStatement?> {
258-
return when (val classRef = ir.getClassRef(staticContext)) {
259+
val classRef = if (this is ExportedRegularClass && isInterface) JsObjectLiteral() else ir.getClassRef(staticContext)
260+
return when (classRef) {
259261
is JsNameRef -> classRef.name!! to null
260262
else -> {
261263
val stableName = JsName(sanitizeName(name), true)

compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/PrepareCollectionsToExportLowering.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class PrepareCollectionsToExportLowering(private val context: JsIrBackendContext
6363

6464
private val exportedCollectionsInfo = ExportedCollectionsInfo(context)
6565

66+
private val jsStatic by lazy(LazyThreadSafetyMode.NONE) {
67+
context.intrinsics.jsStaticAnnotationSymbol.primaryConstructorSymbol
68+
}
6669
private val jsNameCtor by lazy(LazyThreadSafetyMode.NONE) {
6770
context.intrinsics.jsNameAnnotationSymbol.primaryConstructorSymbol
6871
}
@@ -121,6 +124,7 @@ class PrepareCollectionsToExportLowering(private val context: JsIrBackendContext
121124
companionObject.parent = this
122125
companionObject.createThisReceiverParameter()
123126
companionObject.thisReceiver!!.origin = FACTORY_FOR_KOTLIN_COLLECTIONS
127+
companionObject.excludeFromJsExport()
124128
}
125129

126130
val factoryMethod = context.irFactory.createSimpleFunction(
@@ -140,6 +144,7 @@ class PrepareCollectionsToExportLowering(private val context: JsIrBackendContext
140144
isInfix = false,
141145
isExternal = false
142146
).also {
147+
it.addJsStatic()
143148
it.parent = companionObject
144149
it.copyValueAndTypeParametersFrom(factoryMethodForTheCollectionSymbol.owner)
145150
it.parameters = listOfNotNull(companionObject.thisReceiver?.copyTo(it)) + it.nonDispatchParameters
@@ -194,6 +199,10 @@ class PrepareCollectionsToExportLowering(private val context: JsIrBackendContext
194199
}
195200
}
196201

202+
private fun IrDeclarationWithName.addJsStatic() {
203+
annotations = annotations memoryOptimizedPlus JsIrBuilder.buildConstructorCall(jsStatic)
204+
}
205+
197206
private fun IrDeclaration.markWithJsImplicitExport() {
198207
annotations = annotations memoryOptimizedPlus JsIrBuilder.buildConstructorCall(jsImplicitExportCtor).apply {
199208
arguments[0] = true.toIrConst(context.irBuiltIns.booleanType)

compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/tsexport/ExportModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ data class ExportedObject(
109109
override val originalClassId: ClassId?,
110110
override val isExternal: Boolean,
111111
override val isCompanion: Boolean,
112-
val isInsideInterface: Boolean,
112+
val isTopLevel: Boolean,
113113
) : ExportedClass()
114114

115115
class ExportedParameter(

compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/tsexport/ExportModelGenerator.kt

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
452452
.map { exportType(it, shouldCalculateExportedSupertypeForImplicit = false) }
453453
.memoryOptimizedFilter { it !is ExportedType.ErrorType }
454454

455-
val name = klass.getExportedIdentifierForClass()
455+
val name = klass.getExportedIdentifier()
456456

457457
return if (klass.kind == ClassKind.OBJECT) {
458458
return ExportedObject(
@@ -464,7 +464,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
464464
originalClassId = klass.classId,
465465
isCompanion = klass.isCompanion,
466466
isExternal = klass.isExternal,
467-
isInsideInterface = (klass.parent as? IrClass)?.isInterface == true,
467+
isTopLevel = klass.isTopLevel
468468
)
469469
} else {
470470
ExportedRegularClass(
@@ -912,13 +912,6 @@ fun <T : ExportedDeclaration> T.withAttributesFor(declaration: IrDeclaration): T
912912
return this
913913
}
914914

915-
fun IrClass.getExportedIdentifierForClass(): String {
916-
val parentClass = parentClassOrNull
917-
return if (parentClass != null && isCompanion && parentClass.isInterface) {
918-
parentClass.getExportedIdentifierForClass()
919-
} else getExportedIdentifier()
920-
}
921-
922915
fun IrDeclarationWithName.getExportedIdentifier(): String =
923916
with(getJsNameOrKotlinName()) {
924917
if (isSpecial)

compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/tsexport/ExportModelToTsDeclarations.kt

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class ExportModelToTsDeclarations(private val moduleKind: ModuleKind) {
192192
}
193193

194194
private fun ExportedObject.generateTypeScriptString(indent: String, prefix: String): String {
195-
val shouldGenerateObjectWithGetInstance = isEsModules && !isExternal
195+
val shouldGenerateObjectWithGetInstance = isEsModules && !isExternal && isTopLevel
196196
val constructorTypeReference =
197197
if (shouldGenerateObjectWithGetInstance) MetadataConstructor else "$name.$Metadata.$MetadataConstructor"
198198

@@ -276,29 +276,31 @@ class ExportModelToTsDeclarations(private val moduleKind: ModuleKind) {
276276
}
277277

278278
private fun ExportedRegularClass.generateTypeScriptString(indent: String, prefix: String): String {
279+
val isInner = innerClassReference != null
279280
val keyword = if (isInterface) "interface" else "class"
280-
val (interfaceCompanions, allNestedClasses) = nestedClasses.partition { isInterface && it.isCompanion }
281281
val superInterfacesKeyword = if (isInterface) "extends" else "implements"
282282

283283
val superClassClause = superClasses.toExtendsClause(indent)
284284
val superInterfacesClause = superInterfaces.toImplementsClause(superInterfacesKeyword, indent)
285285

286-
val members = members.map {
287-
if (innerClassReference == null || it !is ExportedFunction || !it.isStatic) {
288-
it
289-
} else {
286+
val (membersForNamespace, membersForClassItself) = members.partition { isInterface && it is ExportedFunction && it.isStatic }
287+
val namespaceMembers = membersForNamespace.map { (it as ExportedFunction).copy(isMember = false) }
288+
val classMembers = membersForClassItself.map {
289+
if (isInner && it is ExportedFunction && it.isStatic) {
290290
// Remove $outer argument from secondary constructors of inner classes
291291
it.copy(parameters = it.parameters.drop(1))
292+
} else {
293+
it
292294
}
293295
}
294296

295-
val (innerClasses, nonInnerClasses) = allNestedClasses.partition { it is ExportedRegularClass && it.innerClassReference != null }
297+
val (innerClasses, nonInnerClasses) = nestedClasses.partition { it is ExportedRegularClass && it.innerClassReference != null }
296298
val innerClassesProperties = innerClasses.map { (it as ExportedRegularClass).toReadonlyProperty() }
297-
val membersString = (members + innerClassesProperties)
299+
val membersString = (classMembers + innerClassesProperties)
298300
.joinToString("") { it.toTypeScript("$indent ") + "\n" }
299301

300302
// If there are no exported constructors, add a private constructor to disable default one
301-
val privateCtorString = if (!isInterface && !isAbstract && members.none { it is ExportedConstructor }) {
303+
val privateCtorString = if (!isInterface && !isAbstract && classMembers.none { it is ExportedConstructor }) {
302304
"$indent private constructor();\n"
303305
} else {
304306
""
@@ -333,19 +335,15 @@ class ExportModelToTsDeclarations(private val moduleKind: ModuleKind) {
333335
generateMetadataNamespace(listOf(constructorProperty))
334336
})
335337

336-
val realNestedClasses = metadataNamespace + nonInnerClasses + innerClasses.map { it.withProtectedConstructors() }
338+
val realNestedDeclarations = metadataNamespace + namespaceMembers + nonInnerClasses + innerClasses.map { it.withProtectedConstructors() }
337339

338340
val klassExport =
339341
"$prefix$modifiers$keyword $name$renderedTypeParameters$superClassClause$superInterfacesClause {\n$bodyString}"
340342

341343
val staticsExport =
342-
if (realNestedClasses.isNotEmpty()) "\n" + ExportedNamespace(name, realNestedClasses).toTypeScript(indent, prefix) else ""
343-
344-
val interfaceCompanionsString = if (interfaceCompanions.isNotEmpty()) "\n" + interfaceCompanions.joinToString("\n") {
345-
(it as ExportedObject).copy(typeParameters = typeParameters).toTypeScript(indent, prefix)
346-
} else ""
344+
if (realNestedDeclarations.isNotEmpty()) "\n" + ExportedNamespace(name, realNestedDeclarations).toTypeScript(indent, prefix) else ""
347345

348-
return if (name.isValidES5Identifier()) klassExport + staticsExport + interfaceCompanionsString else ""
346+
return if (name.isValidES5Identifier()) klassExport + staticsExport else ""
349347
}
350348

351349
private fun List<ExportedType>.toExtendsClause(indent: String): String {

compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/export/ExportModelGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ class ExportModelGenerator(val context: WasmBackendContext) {
315315
originalClassId = declaration.classId,
316316
isExternal = declaration.isEffectivelyExternal(),
317317
isCompanion = declaration.isCompanion,
318-
isInsideInterface = (declaration.parent as? IrClass)?.isInterface == true,
318+
isTopLevel = declaration.isTopLevel
319319
)
320320
} else {
321321
ExportedRegularClass(

js/js.translator/testData/box/esModules/jsExport/interfaceWithCompanion.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import * as api from "./interfaceWithCompanion_v5.mjs";
22

33
export default function() {
44
return {
5-
"res": api.A.getInstance().ok()
5+
"res": api.A.Companion.ok()
66
};
77
};

js/js.translator/testData/box/jsExport/interfaceWithCompanion.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module.exports = function() {
44
var { A } = require("main").api
55

66
return {
7-
"res": A.ok()
7+
"res": A.Companion.ok()
88
};
99
};
1010

0 commit comments

Comments
 (0)