[JS IR BE] Support nested external classes

This commit is contained in:
Svyatoslav Kuzmich
2019-02-10 19:00:20 +03:00
parent 0ff23544fc
commit cfde97a7a0
12 changed files with 48 additions and 22 deletions
@@ -57,6 +57,7 @@ class JsIrBackendContext(
val phaseConfig = PhaseConfig(jsPhases, configuration)
override var inVerbosePhase: Boolean = false
val externalNestedClasses = mutableListOf<IrClass>()
val packageLevelJsModules = mutableListOf<IrFile>()
val declarationLevelJsModules = mutableListOf<IrDeclaration>()
@@ -58,8 +58,22 @@ fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, module:
}
}, 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? {
context.externalNestedClasses += collectExternalClasses(irFile, includeCurrentLevel = false)
if (irFile.getJsModule() != null || irFile.getJsQualifier() != null) {
context.packageLevelJsModules.add(irFile)
return null
@@ -9,14 +9,12 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
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.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.getJsModule
import org.jetbrains.kotlin.ir.backend.js.utils.getJsQualifier
import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithVisibility
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
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.config.JSConfigurationKeys
import org.jetbrains.kotlin.utils.DFS
@@ -106,7 +104,7 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
val qualifiedReference: JsNameRef
if (jsModule != null) {
val internalName = rootFunction.scope.declareFreshName("moduleImport")
val internalName = rootFunction.scope.declareFreshName(sanitizeName("\$module\$$jsModule"))
packageLevelJsModules += JsImportedModule(jsModule, internalName, null)
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
rootFunction.parameters += importedJsModules.map { JsParameter(it.internalName) }
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.isDynamic
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
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.naming.isES5IdentifierPart
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
@@ -107,12 +108,19 @@ class SimpleNameGenerator : NameGenerator {
if (declaration.isEffectivelyExternal()) {
// 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 PropertyAccessorDescriptor -> descriptor.correspondingProperty
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) {
@@ -224,11 +232,11 @@ class SimpleNameGenerator : NameGenerator {
nameDeclarator(sanitizeName(nameBuilder.toString()))
}
private 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("")
}
}
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("")
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1288
// FILE: foo.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1290
// FILE: a.kt
// MODULE_KIND: AMD
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1289
// FILE: a.kt
@file:JsModule("lib")
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1288
// FILE: main.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1288
// MODULE: module1
// FILE: module1.kt
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1282
// MODULE: lib
// FILE: lib.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1282
// FILE: main.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1281
package foo