[JS IR] Refactor export model generator
^KT-37916 fixed ^KT-44494 fixed
This commit is contained in:
+104
-38
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.ir.types.*
|
|||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import org.jetbrains.kotlin.utils.keysToMap
|
||||||
|
|
||||||
class ExportModelGenerator(
|
class ExportModelGenerator(
|
||||||
val context: JsIrBackendContext,
|
val context: JsIrBackendContext,
|
||||||
@@ -58,7 +59,13 @@ class ExportModelGenerator(
|
|||||||
return when (candidate) {
|
return when (candidate) {
|
||||||
is IrSimpleFunction -> exportFunction(candidate)
|
is IrSimpleFunction -> exportFunction(candidate)
|
||||||
is IrProperty -> exportProperty(candidate)
|
is IrProperty -> exportProperty(candidate)
|
||||||
is IrClass -> exportClass(candidate)
|
is IrClass -> {
|
||||||
|
if (candidate.isEnumClass) {
|
||||||
|
exportEnumClass(candidate)
|
||||||
|
} else {
|
||||||
|
exportClass(candidate)
|
||||||
|
}
|
||||||
|
}
|
||||||
is IrField -> null
|
is IrField -> null
|
||||||
else -> error("Can't export declaration $candidate")
|
else -> error("Can't export declaration $candidate")
|
||||||
}
|
}
|
||||||
@@ -135,37 +142,38 @@ class ExportModelGenerator(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exportEnumEntry(field: IrField, enumEntries: List<IrEnumEntry>): ExportedProperty {
|
private fun exportEnumEntry(field: IrField, enumEntries: Map<IrEnumEntry, Int>): ExportedProperty {
|
||||||
val irEnumEntry = context.mapping.fieldToEnumEntry[field]
|
val irEnumEntry = context.mapping.fieldToEnumEntry[field]
|
||||||
?: error("Unable to find enum entry for ${field.fqNameWhenAvailable}")
|
?: error("Unable to find enum entry for ${field.fqNameWhenAvailable}")
|
||||||
|
|
||||||
val parentClass = field.parent as IrClass
|
val parentClass = field.parent as IrClass
|
||||||
|
|
||||||
val name = irEnumEntry.getExportedIdentifier()
|
val name = irEnumEntry.getExportedIdentifier()
|
||||||
val ordinal = enumEntries.indexOf(irEnumEntry)
|
val ordinal = enumEntries.getValue(irEnumEntry)
|
||||||
|
|
||||||
val nameProperty = ExportedProperty(
|
fun fakeProperty(name: String, type: ExportedType) =
|
||||||
|
ExportedProperty(
|
||||||
|
name = name,
|
||||||
|
type = type,
|
||||||
|
mutable = false,
|
||||||
|
isMember = true,
|
||||||
|
isStatic = false,
|
||||||
|
isAbstract = false,
|
||||||
|
isProtected = false,
|
||||||
|
irGetter = null,
|
||||||
|
irSetter = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
val nameProperty = fakeProperty(
|
||||||
name = "name",
|
name = "name",
|
||||||
type = ExportedType.LiteralType.StringLiteralType(name),
|
type = ExportedType.LiteralType.StringLiteralType(name),
|
||||||
mutable = false,
|
|
||||||
isMember = true,
|
|
||||||
isStatic = false,
|
|
||||||
isAbstract = false,
|
|
||||||
isProtected = false,
|
|
||||||
irGetter = null,
|
|
||||||
irSetter = null,
|
|
||||||
)
|
)
|
||||||
val ordinalProperty = ExportedProperty(
|
|
||||||
|
val ordinalProperty = fakeProperty(
|
||||||
name = "ordinal",
|
name = "ordinal",
|
||||||
type = ExportedType.LiteralType.NumberLiteralType(ordinal),
|
type = ExportedType.LiteralType.NumberLiteralType(ordinal),
|
||||||
mutable = false,
|
|
||||||
isMember = true,
|
|
||||||
isStatic = false,
|
|
||||||
isAbstract = false,
|
|
||||||
isProtected = false,
|
|
||||||
irGetter = null,
|
|
||||||
irSetter = null,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val type = ExportedType.InlineInterfaceType(
|
val type = ExportedType.InlineInterfaceType(
|
||||||
listOf(nameProperty, ordinalProperty)
|
listOf(nameProperty, ordinalProperty)
|
||||||
)
|
)
|
||||||
@@ -213,25 +221,61 @@ class ExportModelGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val (members, nestedClasses) = exportClassDeclarations(klass)
|
||||||
|
|
||||||
|
return exportClass(
|
||||||
|
klass,
|
||||||
|
members,
|
||||||
|
nestedClasses
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exportEnumClass(
|
||||||
|
klass: IrClass
|
||||||
|
): ExportedDeclaration? {
|
||||||
|
when (val exportability = classExportability(klass)) {
|
||||||
|
is Exportability.Prohibited -> error(exportability.reason)
|
||||||
|
is Exportability.NotNeeded -> return null
|
||||||
|
Exportability.Allowed -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val enumEntries = klass
|
||||||
|
.declarations
|
||||||
|
.filterIsInstance<IrField>()
|
||||||
|
.mapNotNull { context.mapping.fieldToEnumEntry[it] }
|
||||||
|
|
||||||
|
val enumEntriesToOrdinal: Map<IrEnumEntry, Int> =
|
||||||
|
enumEntries
|
||||||
|
.keysToMap(enumEntries::indexOf)
|
||||||
|
|
||||||
|
val (members, nestedClasses) = exportClassDeclarations(klass) { candidate ->
|
||||||
|
val enumExportedMember = exportAsEnumMember(candidate, enumEntriesToOrdinal)
|
||||||
|
enumExportedMember
|
||||||
|
}
|
||||||
|
|
||||||
|
return exportClass(
|
||||||
|
klass,
|
||||||
|
members,
|
||||||
|
nestedClasses
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exportClassDeclarations(
|
||||||
|
klass: IrClass,
|
||||||
|
specialProcessing: (IrDeclarationWithName) -> ExportedDeclaration? = { null }
|
||||||
|
): ExportedClassDeclarationsInfo {
|
||||||
val members = mutableListOf<ExportedDeclaration>()
|
val members = mutableListOf<ExportedDeclaration>()
|
||||||
val nestedClasses = mutableListOf<ExportedClass>()
|
val nestedClasses = mutableListOf<ExportedClass>()
|
||||||
val enumEntries = if (klass.isEnumClass) {
|
|
||||||
klass
|
|
||||||
.declarations
|
|
||||||
.filterIsInstance<IrField>()
|
|
||||||
.mapNotNull { context.mapping.fieldToEnumEntry[it] }
|
|
||||||
} else null
|
|
||||||
|
|
||||||
for (declaration in klass.declarations) {
|
for (declaration in klass.declarations) {
|
||||||
val candidate = getExportCandidate(declaration) ?: continue
|
val candidate = getExportCandidate(declaration) ?: continue
|
||||||
if (!shouldDeclarationBeExported(candidate, context)) continue
|
if (!shouldDeclarationBeExported(candidate, context)) continue
|
||||||
|
|
||||||
if (enumEntries != null) {
|
val processingResult = specialProcessing(candidate)
|
||||||
val enumExportedMember = exportAsEnumMember(candidate, enumEntries)
|
if (processingResult != null) {
|
||||||
if (enumExportedMember != null) {
|
members.add(processingResult)
|
||||||
members.add(enumExportedMember)
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
when (candidate) {
|
when (candidate) {
|
||||||
@@ -256,8 +300,8 @@ class ExportModelGenerator(
|
|||||||
is IrField -> {
|
is IrField -> {
|
||||||
assert(
|
assert(
|
||||||
candidate.origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE ||
|
candidate.origin == IrDeclarationOrigin.FIELD_FOR_OBJECT_INSTANCE ||
|
||||||
candidate.origin == IrDeclarationOrigin.FIELD_FOR_OUTER_THIS
|
candidate.origin == IrDeclarationOrigin.FIELD_FOR_OUTER_THIS ||
|
||||||
|| candidate.correspondingPropertySymbol != null
|
candidate.correspondingPropertySymbol != null
|
||||||
) {
|
) {
|
||||||
"Unexpected field without property ${candidate.fqNameWhenAvailable}"
|
"Unexpected field without property ${candidate.fqNameWhenAvailable}"
|
||||||
}
|
}
|
||||||
@@ -267,6 +311,17 @@ class ExportModelGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ExportedClassDeclarationsInfo(
|
||||||
|
members,
|
||||||
|
nestedClasses
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exportClass(
|
||||||
|
klass: IrClass,
|
||||||
|
members: List<ExportedDeclaration>,
|
||||||
|
nestedClasses: List<ExportedClass>
|
||||||
|
): ExportedDeclaration {
|
||||||
val typeParameters = klass.typeParameters.map { it.name.identifier }
|
val typeParameters = klass.typeParameters.map { it.name.identifier }
|
||||||
|
|
||||||
// TODO: Handle non-exported super types
|
// TODO: Handle non-exported super types
|
||||||
@@ -317,7 +372,11 @@ class ExportModelGenerator(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exportAsEnumMember(candidate: IrDeclarationWithName, enumEntries: List<IrEnumEntry>): ExportedDeclaration? {
|
private fun exportAsEnumMember(
|
||||||
|
candidate: IrDeclarationWithName,
|
||||||
|
enumEntriesToOrdinal: Map<IrEnumEntry, Int>
|
||||||
|
): ExportedDeclaration? {
|
||||||
|
val enumEntries = enumEntriesToOrdinal.keys
|
||||||
return when (candidate) {
|
return when (candidate) {
|
||||||
is IrProperty -> {
|
is IrProperty -> {
|
||||||
if (candidate.isEnumFakeOverriddenDeclaration(context)) {
|
if (candidate.isEnumFakeOverriddenDeclaration(context)) {
|
||||||
@@ -326,9 +385,8 @@ class ExportModelGenerator(
|
|||||||
.map { it.getExportedIdentifier() }
|
.map { it.getExportedIdentifier() }
|
||||||
.map { ExportedType.LiteralType.StringLiteralType(it) }
|
.map { ExportedType.LiteralType.StringLiteralType(it) }
|
||||||
.reduce { acc: ExportedType, s: ExportedType -> ExportedType.UnionType(acc, s) }
|
.reduce { acc: ExportedType, s: ExportedType -> ExportedType.UnionType(acc, s) }
|
||||||
"ordinal" -> enumEntries
|
"ordinal" -> enumEntriesToOrdinal
|
||||||
.map { enumEntries.indexOf(it) }
|
.map { (_, ordinal) -> ExportedType.LiteralType.NumberLiteralType(ordinal) }
|
||||||
.map { ExportedType.LiteralType.NumberLiteralType(it) }
|
|
||||||
.reduce { acc: ExportedType, s: ExportedType -> ExportedType.UnionType(acc, s) }
|
.reduce { acc: ExportedType, s: ExportedType -> ExportedType.UnionType(acc, s) }
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -341,7 +399,7 @@ class ExportModelGenerator(
|
|||||||
|
|
||||||
is IrField -> {
|
is IrField -> {
|
||||||
if (candidate.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY) {
|
if (candidate.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY) {
|
||||||
exportEnumEntry(candidate, enumEntries)
|
exportEnumEntry(candidate, enumEntriesToOrdinal)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -490,6 +548,14 @@ sealed class Exportability {
|
|||||||
class Prohibited(val reason: String) : Exportability()
|
class Prohibited(val reason: String) : Exportability()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ExportedClassDeclarationsInfo(
|
||||||
|
val members: List<ExportedDeclaration>,
|
||||||
|
val nestedClasses: List<ExportedClass>
|
||||||
|
) {
|
||||||
|
operator fun component1() = members
|
||||||
|
operator fun component2() = nestedClasses
|
||||||
|
}
|
||||||
|
|
||||||
private val IrClassifierSymbol.isInterface
|
private val IrClassifierSymbol.isInterface
|
||||||
get() = (owner as? IrClass)?.isInterface == true
|
get() = (owner as? IrClass)?.isInterface == true
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user