[JS IR BE] Support nested external classes
This commit is contained in:
@@ -57,6 +57,7 @@ class JsIrBackendContext(
|
|||||||
val phaseConfig = PhaseConfig(jsPhases, configuration)
|
val phaseConfig = PhaseConfig(jsPhases, configuration)
|
||||||
override var inVerbosePhase: Boolean = false
|
override var inVerbosePhase: Boolean = false
|
||||||
|
|
||||||
|
val externalNestedClasses = mutableListOf<IrClass>()
|
||||||
val packageLevelJsModules = mutableListOf<IrFile>()
|
val packageLevelJsModules = mutableListOf<IrFile>()
|
||||||
val declarationLevelJsModules = mutableListOf<IrDeclaration>()
|
val declarationLevelJsModules = mutableListOf<IrDeclaration>()
|
||||||
|
|
||||||
|
|||||||
+14
@@ -58,8 +58,22 @@ fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, module:
|
|||||||
}
|
}
|
||||||
}, FqName.ROOT)
|
}, FqName.ROOT)
|
||||||
|
|
||||||
|
fun collectExternalClasses(container: IrDeclarationContainer, includeCurrentLevel: Boolean): List<IrClass> {
|
||||||
|
val externalClasses =
|
||||||
|
container.declarations.filterIsInstance<IrClass>().filter { it.isEffectivelyExternal() }
|
||||||
|
|
||||||
|
val nestedExternalClasses =
|
||||||
|
externalClasses.flatMap { collectExternalClasses(it, true) }
|
||||||
|
|
||||||
|
return if (includeCurrentLevel)
|
||||||
|
externalClasses + nestedExternalClasses
|
||||||
|
else
|
||||||
|
nestedExternalClasses
|
||||||
|
}
|
||||||
|
|
||||||
fun lowerFile(irFile: IrFile): IrFile? {
|
fun lowerFile(irFile: IrFile): IrFile? {
|
||||||
|
context.externalNestedClasses += collectExternalClasses(irFile, includeCurrentLevel = false)
|
||||||
|
|
||||||
if (irFile.getJsModule() != null || irFile.getJsQualifier() != null) {
|
if (irFile.getJsModule() != null || irFile.getJsQualifier() != null) {
|
||||||
context.packageLevelJsModules.add(irFile)
|
context.packageLevelJsModules.add(irFile)
|
||||||
return null
|
return null
|
||||||
|
|||||||
+16
-5
@@ -9,14 +9,12 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ModuleType
|
import org.jetbrains.kotlin.ir.backend.js.ModuleType
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsModule
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsQualifier
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithVisibility
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithVisibility
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
||||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
import org.jetbrains.kotlin.utils.DFS
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
@@ -106,7 +104,7 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
|||||||
val qualifiedReference: JsNameRef
|
val qualifiedReference: JsNameRef
|
||||||
|
|
||||||
if (jsModule != null) {
|
if (jsModule != null) {
|
||||||
val internalName = rootFunction.scope.declareFreshName("moduleImport")
|
val internalName = rootFunction.scope.declareFreshName(sanitizeName("\$module\$$jsModule"))
|
||||||
packageLevelJsModules += JsImportedModule(jsModule, internalName, null)
|
packageLevelJsModules += JsImportedModule(jsModule, internalName, null)
|
||||||
|
|
||||||
qualifiedReference =
|
qualifiedReference =
|
||||||
@@ -131,6 +129,19 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (externalClass in backendContext.externalNestedClasses) {
|
||||||
|
val declName = rootContext.getNameForDeclaration(externalClass)
|
||||||
|
val parentName = rootContext.getNameForDeclaration(externalClass.parentAsClass)
|
||||||
|
importStatements.add(
|
||||||
|
JsExpressionStatement(
|
||||||
|
jsAssignment(
|
||||||
|
declName.makeRef(),
|
||||||
|
JsNameRef(externalClass.name.identifier, parentName.makeRef())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val importedJsModules = declarationLevelJsModules + packageLevelJsModules
|
val importedJsModules = declarationLevelJsModules + packageLevelJsModules
|
||||||
rootFunction.parameters += importedJsModules.map { JsParameter(it.internalName) }
|
rootFunction.parameters += importedJsModules.map { JsParameter(it.internalName) }
|
||||||
|
|
||||||
|
|||||||
+17
-9
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.types.classifierOrFail
|
|||||||
import org.jetbrains.kotlin.ir.util.isDynamic
|
import org.jetbrains.kotlin.ir.util.isDynamic
|
||||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||||
import org.jetbrains.kotlin.ir.util.isInlined
|
import org.jetbrains.kotlin.ir.util.isInlined
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||||
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
|
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
|
||||||
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
|
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
|
||||||
@@ -107,12 +108,19 @@ class SimpleNameGenerator : NameGenerator {
|
|||||||
|
|
||||||
if (declaration.isEffectivelyExternal()) {
|
if (declaration.isEffectivelyExternal()) {
|
||||||
// TODO: descriptors are still used here due to the corresponding declaration doesn't have enough information yet
|
// TODO: descriptors are still used here due to the corresponding declaration doesn't have enough information yet
|
||||||
val descriptorForName = when (descriptor) {
|
val descriptorName = when (descriptor) {
|
||||||
is ConstructorDescriptor -> descriptor.constructedClass
|
is ConstructorDescriptor -> descriptor.constructedClass
|
||||||
is PropertyAccessorDescriptor -> descriptor.correspondingProperty
|
is PropertyAccessorDescriptor -> descriptor.correspondingProperty
|
||||||
else -> descriptor
|
else -> descriptor
|
||||||
|
}.name
|
||||||
|
|
||||||
|
if (declaration is IrConstructor) return@getOrPut getNameForDeclaration(declaration.parentAsClass, context)
|
||||||
|
|
||||||
|
if (declaration is IrClass && declaration.parent is IrClass) {
|
||||||
|
val parentName = getNameForDeclaration(declaration.parentAsClass, context).ident
|
||||||
|
return@getOrPut context.currentScope.declareFreshName(parentName + "$" + descriptorName.identifier)
|
||||||
}
|
}
|
||||||
return@getOrPut context.staticContext.rootScope.declareName(descriptorForName.name.asString())
|
return@getOrPut context.staticContext.rootScope.declareName(descriptorName.identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (declaration) {
|
when (declaration) {
|
||||||
@@ -224,11 +232,11 @@ class SimpleNameGenerator : NameGenerator {
|
|||||||
|
|
||||||
nameDeclarator(sanitizeName(nameBuilder.toString()))
|
nameDeclarator(sanitizeName(nameBuilder.toString()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private fun sanitizeName(name: String): String {
|
|
||||||
if (name.isEmpty()) return "_"
|
fun sanitizeName(name: String): String {
|
||||||
|
if (name.isEmpty()) return "_"
|
||||||
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
|
||||||
return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("")
|
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
||||||
}
|
return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1288
|
// EXPECTED_REACHABLE_NODES: 1288
|
||||||
// FILE: foo.kt
|
// FILE: foo.kt
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1290
|
// EXPECTED_REACHABLE_NODES: 1290
|
||||||
// FILE: a.kt
|
// FILE: a.kt
|
||||||
// MODULE_KIND: AMD
|
// MODULE_KIND: AMD
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1289
|
// EXPECTED_REACHABLE_NODES: 1289
|
||||||
// FILE: a.kt
|
// FILE: a.kt
|
||||||
@file:JsModule("lib")
|
@file:JsModule("lib")
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1288
|
// EXPECTED_REACHABLE_NODES: 1288
|
||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1288
|
// EXPECTED_REACHABLE_NODES: 1288
|
||||||
// MODULE: module1
|
// MODULE: module1
|
||||||
// FILE: module1.kt
|
// FILE: module1.kt
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1282
|
// EXPECTED_REACHABLE_NODES: 1282
|
||||||
// MODULE: lib
|
// MODULE: lib
|
||||||
// FILE: lib.kt
|
// FILE: lib.kt
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1282
|
// EXPECTED_REACHABLE_NODES: 1282
|
||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1281
|
// EXPECTED_REACHABLE_NODES: 1281
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user