Enum implementing exported interface

[JS IR] Not export get instance enum function

[JS IR] Enum corresponding class is not considered in export

[JS IR] All enums are abstract and with private constructor

[JS IR] Any methods is left in d.ts

[JS IR] Make enum with declarations inside corresponding class

[JS IR] Export of interface through fake override

[JS IR] Include enum entry corresponding class members into export model

Merge-request: KT-MR-5031

^KT-49779 fixed
^KT-49773 fixed
This commit is contained in:
Ilya Goncharov
2021-11-24 12:25:50 +00:00
committed by Space
parent 4181429c7e
commit 1481ad21f5
17 changed files with 440 additions and 41 deletions
@@ -405,7 +405,7 @@ fun usefulDeclarations(
// https://youtrack.jetbrains.com/issue/KT-46672
// TODO: Possibly solution with origin is not so good
// There is option with applying this hack to jsGetKClass
if (expression.origin == JsLoweredDeclarationOrigin.CLASS_REFERENCE) {
if (expression.origin == JsStatementOrigins.CLASS_REFERENCE) {
// Maybe we need to filter primary constructor
// Although at this time, we should have only primary constructor
(ref as IrClass)
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
object JS_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB")
@@ -16,5 +15,5 @@ object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
object BRIDGE_WITHOUT_STABLE_NAME : IrDeclarationOriginImpl("BRIDGE_WITHOUT_STABLE_NAME")
object OBJECT_GET_INSTANCE_FUNCTION : IrDeclarationOriginImpl("OBJECT_GET_INSTANCE_FUNCTION")
object JS_SHADOWED_EXPORT : IrDeclarationOriginImpl("JS_SHADOWED_EXPORT")
object CLASS_REFERENCE : IrStatementOriginImpl("CLASS_REFERENCE")
object ENUM_GET_INSTANCE_FUNCTION : IrDeclarationOriginImpl("ENUM_GET_INSTANCE_FUNCTION")
}
@@ -37,8 +37,11 @@ data class ExportedFunction(
data class ExportedConstructor(
val parameters: List<ExportedParameter>,
val visibility: ExportedVisibility
) : ExportedDeclaration() {
val isProtected: Boolean
) : ExportedDeclaration()
get() = visibility == ExportedVisibility.PROTECTED
}
data class ExportedConstructSignature(
val parameters: List<ExportedParameter>,
@@ -131,3 +134,9 @@ sealed class ExportedType {
fun withImplicitlyExported(implicitlyExportedType: Boolean) =
if (implicitlyExportedType) ImplicitlyExportedType(this) else this
}
enum class ExportedVisibility(val keyword: String) {
DEFAULT(""),
PRIVATE("private "),
PROTECTED("protected ")
}
@@ -10,12 +10,14 @@ import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_RESULT_TYPE_PARAMETER
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
import org.jetbrains.kotlin.ir.backend.js.utils.isExportedInterface
import org.jetbrains.kotlin.ir.backend.js.utils.isJsExport
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
import org.jetbrains.kotlin.ir.declarations.*
@@ -71,8 +73,12 @@ class ExportModelGenerator(
}
}
private fun exportFunction(function: IrSimpleFunction): ExportedDeclaration? =
when (val exportability = functionExportability(function)) {
private fun exportFunction(function: IrSimpleFunction): ExportedDeclaration? {
if (function.origin == JsLoweredDeclarationOrigin.ENUM_GET_INSTANCE_FUNCTION) {
return null
}
return when (val exportability = functionExportability(function)) {
is Exportability.NotNeeded -> null
is Exportability.Prohibited -> ErrorDeclaration(exportability.reason)
is Exportability.Allowed -> {
@@ -90,6 +96,7 @@ class ExportModelGenerator(
)
}
}
}
private fun exportConstructor(constructor: IrConstructor): ExportedDeclaration? {
if (!constructor.isPrimary) return null
@@ -97,7 +104,7 @@ class ExportModelGenerator(
constructor.valueParameters.filterNot { it.origin === ES6_RESULT_TYPE_PARAMETER || it.origin === ES6_INIT_BOX_PARAMETER }
return ExportedConstructor(
parameters = allValueParameters.map { exportParameter(it) },
isProtected = constructor.visibility == DescriptorVisibilities.PROTECTED
visibility = constructor.visibility.toExportedVisibility()
)
}
@@ -115,7 +122,7 @@ class ExportModelGenerator(
// TODO: Report a frontend error
if (accessor.extensionReceiverParameter != null)
return null
if (accessor.isFakeOverride && !accessor.isEnumFakeOverriddenDeclaration(context)) {
if (accessor.isFakeOverride && !accessor.isAllowedFakeOverriddenDeclaration(context)) {
return null
}
}
@@ -254,11 +261,20 @@ class ExportModelGenerator(
enumExportedMember
}
val privateConstructor = ExportedConstructor(
parameters = emptyList(),
visibility = ExportedVisibility.PRIVATE
)
return exportClass(
klass,
members,
listOf(privateConstructor) + members,
nestedClasses
)
).let {
(it as ExportedClass).copy(
isAbstract = true,
)
}
}
private fun exportClassDeclarations(
@@ -382,7 +398,7 @@ class ExportModelGenerator(
val enumEntries = enumEntriesToOrdinal.keys
return when (candidate) {
is IrProperty -> {
if (candidate.isEnumFakeOverriddenDeclaration(context)) {
if (candidate.isAllowedFakeOverriddenDeclaration(context)) {
val type: ExportedType? = when (candidate.getExportedIdentifier()) {
"name" -> enumEntries
.map { it.getExportedIdentifier() }
@@ -507,7 +523,7 @@ class ExportModelGenerator(
return Exportability.Prohibited("Inline reified function")
if (function.isSuspend)
return Exportability.Prohibited("Suspend function")
if (function.isFakeOverride)
if (function.isFakeOverride && !function.isAllowedFakeOverriddenDeclaration(context))
return Exportability.NotNeeded
if (function.origin == JsLoweredDeclarationOrigin.BRIDGE_WITHOUT_STABLE_NAME ||
function.origin == JsLoweredDeclarationOrigin.BRIDGE_WITH_STABLE_NAME ||
@@ -524,9 +540,6 @@ class ExportModelGenerator(
return Exportability.NotNeeded
}
if (function.isFakeOverriddenFromAny())
return Exportability.NotNeeded
val nameString = function.name.asString()
if (nameString.endsWith("-impl"))
return Exportability.NotNeeded
@@ -605,7 +618,7 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont
if (overriddenNonEmpty) {
return declaration.isOverriddenExported(context) ||
(declaration as? IrSimpleFunction)?.isMethodOfAny() == true // Handle names for special functions
|| declaration.isEnumFakeOverriddenDeclaration(context)
|| declaration.isAllowedFakeOverriddenDeclaration(context)
}
}
@@ -619,12 +632,17 @@ private fun shouldDeclarationBeExported(declaration: IrDeclarationWithName, cont
}
}
fun IrOverridableDeclaration<*>.isEnumFakeOverriddenDeclaration(context: JsIrBackendContext?): Boolean {
fun IrOverridableDeclaration<*>.isAllowedFakeOverriddenDeclaration(context: JsIrBackendContext?): Boolean {
if (this.resolveFakeOverride(allowAbstract = true)?.parentClassOrNull.isExportedInterface()) {
return true
}
return context?.irBuiltIns?.enumClass?.let { enumClass ->
overriddenSymbols
.asSequence()
.map { it.owner }
.filterIsInstance<IrDeclaration>()
.filterIsInstance<IrOverridableDeclaration<*>>()
.filter { it.overriddenSymbols.isEmpty() }
.mapNotNull { it.parentClassOrNull }
.map { it.symbol }
.any { it == enumClass }
@@ -640,6 +658,12 @@ fun IrDeclaration.isExported(context: JsIrBackendContext?): Boolean {
return shouldDeclarationBeExported(candidate, context)
}
private fun DescriptorVisibility.toExportedVisibility() =
when (this) {
DescriptorVisibilities.PROTECTED -> ExportedVisibility.PROTECTED
else -> ExportedVisibility.DEFAULT
}
private val reservedWords = setOf(
"break",
"case",
@@ -93,9 +93,8 @@ fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): Strin
}
is ExportedConstructor -> {
val visibility = if (isProtected) "protected " else ""
val renderedParameters = parameters.joinToString(", ") { it.toTypeScript(indent) }
"${visibility}constructor($renderedParameters);"
"${visibility.keyword}constructor($renderedParameters);"
}
is ExportedConstructSignature -> {
@@ -220,7 +219,7 @@ fun ExportedClass.withProtectedConstructors(): ExportedClass {
if (it !is ExportedConstructor || it.isProtected) {
it
} else {
it.copy(isProtected = true)
it.copy(visibility = ExportedVisibility.PROTECTED)
}
})
}
@@ -142,7 +142,7 @@ class ClassReferenceLowering(val context: JsCommonBackendContext) : BodyLowering
JsIrBuilder.buildCall(
reflectionSymbols.getClassData,
typeArguments = listOf(type),
origin = JsLoweredDeclarationOrigin.CLASS_REFERENCE
origin = JsStatementOrigins.CLASS_REFERENCE
)
private fun buildCall(name: IrSimpleFunctionSymbol, vararg args: IrExpression): IrExpression =
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities.PRIVATE
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
@@ -445,7 +446,7 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsCommonBackendContex
context.irFactory.buildFun {
name = Name.identifier(createEntryAccessorName(irClass.name.identifier, enumEntry))
returnType = enumEntry.getType(irClass)
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
origin = JsLoweredDeclarationOrigin.ENUM_GET_INSTANCE_FUNCTION
}.apply {
parent = irClass
}
@@ -6,9 +6,8 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.backend.js.export.isEnumFakeOverriddenDeclaration
import org.jetbrains.kotlin.ir.backend.js.export.isAllowedFakeOverriddenDeclaration
import org.jetbrains.kotlin.ir.backend.js.export.isExported
import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported
import org.jetbrains.kotlin.ir.backend.js.utils.*
@@ -102,7 +101,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
classBlock.statements += generateClassMetadata()
if (!irClass.isInterface && !irClass.isEnumEntry) {
if (!irClass.isInterface) {
for (property in properties) {
if (property.getter?.extensionReceiverParameter != null || property.setter?.extensionReceiverParameter != null)
continue
@@ -110,7 +109,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
if (!property.visibility.isPublicAPI)
continue
if (property.isFakeOverride && !property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext))
if (
property.isFakeOverride &&
!property.isAllowedFakeOverriddenDeclaration(context.staticContext.backendContext)
)
continue
fun IrSimpleFunction.propertyAccessorForwarder(
@@ -145,7 +147,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
val noOverriddenExportedSetter = property.setter?.isOverriddenExported(context.staticContext.backendContext) == false
val needsOverride = (overriddenExportedGetter && noOverriddenExportedSetter) ||
property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext)
property.isAllowedFakeOverriddenDeclaration(context.staticContext.backendContext)
if (irClass.isExported(context.staticContext.backendContext) &&
(overriddenSymbols.isEmpty() || needsOverride) ||
@@ -18,4 +18,5 @@ interface JsStatementOrigins {
object FACTORY_ORIGIN : IrDeclarationOriginImpl("FACTORY_ORIGIN")
object COROUTINE_ROOT_LOOP : IrStatementOriginImpl("COROUTINE_ROOT_LOOP")
object COROUTINE_SWITCH : IrStatementOriginImpl("COROUTINE_SWITCH")
object CLASS_REFERENCE : IrStatementOriginImpl("CLASS_REFERENCE")
}