[K/JS] Support companion objects in external and exported declarations
This commit is contained in:
+1
@@ -113,6 +113,7 @@ object JS_DIAGNOSTICS_LIST : DiagnosticList("FirJsErrors") {
|
||||
val NON_CONSUMABLE_EXPORTED_IDENTIFIER by warning<KtElement>(PositioningStrategy.DEFAULT) {
|
||||
parameter<String>("name")
|
||||
}
|
||||
val NAMED_COMPANION_IN_EXPORTED_INTERFACE by error<KtElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
}
|
||||
|
||||
val DYNAMICS by object : DiagnosticGroup("Dynamics") {
|
||||
|
||||
+1
@@ -44,6 +44,7 @@ object WEB_COMMON_DIAGNOSTICS_LIST : DiagnosticList("FirWebCommonErrors") {
|
||||
val EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT by error<KtElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<ConeKotlinType>("typeArgument")
|
||||
}
|
||||
val NAMED_COMPANION_IN_EXTERNAL_INTERFACE by error<KtElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
}
|
||||
|
||||
val EXPORT by object : DiagnosticGroup("Export") {
|
||||
|
||||
+1
@@ -78,6 +78,7 @@ object FirJsErrors {
|
||||
val WRONG_EXPORTED_DECLARATION: KtDiagnosticFactory1<String> by error1<KtElement, String>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val NON_EXPORTABLE_TYPE: KtDiagnosticFactory2<String, ConeKotlinType> by warning2<KtElement, String, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val NON_CONSUMABLE_EXPORTED_IDENTIFIER: KtDiagnosticFactory1<String> by warning1<KtElement, String>()
|
||||
val NAMED_COMPANION_IN_EXPORTED_INTERFACE: KtDiagnosticFactory0 by error0<KtElement>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
|
||||
// Dynamics
|
||||
val DELEGATION_BY_DYNAMIC: KtDiagnosticFactory0 by error0<KtElement>()
|
||||
|
||||
+2
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_NAME_ON_P
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_NAME_PROHIBITED_FOR_EXTENSION_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_NAME_PROHIBITED_FOR_NAMED_NATIVE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_NAME_PROHIBITED_FOR_OVERRIDE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NAMED_COMPANION_IN_EXPORTED_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NAME_CONTAINS_ILLEGAL_CHARS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NATIVE_ANNOTATIONS_ALLOWED_ONLY_ON_MEMBER_OR_EXTENSION_FUN
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NATIVE_GETTER_RETURN_TYPE_SHOULD_BE_NULLABLE
|
||||
@@ -189,5 +190,6 @@ object FirJsErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"Exported declaration contains non-consumable identifier ''{0}'', which cannot be represented inside TS definitions and ESM.",
|
||||
CommonRenderers.STRING,
|
||||
)
|
||||
map.put(NAMED_COMPANION_IN_EXPORTED_INTERFACE, "Named companions are not allowed inside exported interfaces.")
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.js.common.RESERVED_KEYWORDS
|
||||
import org.jetbrains.kotlin.js.common.SPECIAL_KEYWORDS
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds
|
||||
import org.jetbrains.kotlin.name.SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
|
||||
|
||||
object FirJsExportDeclarationChecker : FirBasicDeclarationChecker(MppCheckerKind.Common) {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -135,11 +136,15 @@ object FirJsExportDeclarationChecker : FirBasicDeclarationChecker(MppCheckerKind
|
||||
declaration.isInline -> "value class"
|
||||
else -> null
|
||||
}
|
||||
else -> if (context.isInsideInterface) {
|
||||
"${if (declaration.status.isCompanion) "companion object" else "nested/inner declaration"} inside exported interface"
|
||||
else -> if (context.isInsideInterface && !declaration.status.isCompanion) {
|
||||
"nested/inner declaration inside exported interface"
|
||||
} else null
|
||||
}
|
||||
|
||||
if (context.isInsideInterface && declaration.status.isCompanion && declaration.nameOrSpecialName != DEFAULT_NAME_FOR_COMPANION_OBJECT) {
|
||||
reporter.reportOn(declaration.source, FirJsErrors.NAMED_COMPANION_IN_EXPORTED_INTERFACE, context)
|
||||
}
|
||||
|
||||
if (wrongDeclaration != null) {
|
||||
reportWrongExportedDeclaration(wrongDeclaration)
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.name.JsStandardClassIds
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds.Annotations.JsNative
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
|
||||
object FirJsExternalChecker : FirWebCommonExternalChecker() {
|
||||
object FirJsExternalChecker : FirWebCommonExternalChecker(allowCompanionInInterface = true) {
|
||||
override fun isNativeOrEffectivelyExternal(symbol: FirBasedSymbol<*>, session: FirSession): Boolean {
|
||||
return symbol.isNativeObject(session)
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.WebCommonStandardClassIds
|
||||
|
||||
object FirWasmExternalChecker : FirWebCommonExternalChecker() {
|
||||
object FirWasmExternalChecker : FirWebCommonExternalChecker(allowCompanionInInterface = false) {
|
||||
override fun isNativeOrEffectivelyExternal(symbol: FirBasedSymbol<*>, session: FirSession): Boolean {
|
||||
return symbol.isEffectivelyExternal(session)
|
||||
}
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ object FirWebCommonErrors {
|
||||
val UNCHECKED_CAST_TO_EXTERNAL_INTERFACE: KtDiagnosticFactory2<ConeKotlinType, ConeKotlinType> by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val EXTERNAL_INTERFACE_AS_CLASS_LITERAL: KtDiagnosticFactory0 by error0<KtElement>()
|
||||
val EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT: KtDiagnosticFactory1<ConeKotlinType> by error1<KtElement, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val NAMED_COMPANION_IN_EXTERNAL_INTERFACE: KtDiagnosticFactory0 by error0<KtElement>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
|
||||
// Export
|
||||
val NESTED_JS_EXPORT: KtDiagnosticFactory0 by error0<KtElement>()
|
||||
|
||||
+2
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErro
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.INLINE_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.JSCODE_ARGUMENT_NON_CONST_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NAMED_COMPANION_IN_EXTERNAL_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NESTED_CLASS_IN_EXTERNAL_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NESTED_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NESTED_JS_EXPORT
|
||||
@@ -76,5 +77,6 @@ object FirWebCommonErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
map.put(NESTED_JS_EXPORT, "'@JsExport' is only allowed on files and top-level declarations.")
|
||||
|
||||
map.put(JSCODE_ARGUMENT_NON_CONST_EXPRESSION, "An argument for the 'js()' function must be a constant string expression.")
|
||||
map.put(NAMED_COMPANION_IN_EXTERNAL_INTERFACE, "Named companions are not allowed inside external interfaces.")
|
||||
}
|
||||
}
|
||||
+17
-6
@@ -6,9 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
@@ -30,9 +28,10 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
|
||||
abstract class FirWebCommonExternalChecker : FirBasicDeclarationChecker(MppCheckerKind.Common) {
|
||||
abstract class FirWebCommonExternalChecker(private val allowCompanionInInterface: Boolean) : FirBasicDeclarationChecker(MppCheckerKind.Common) {
|
||||
abstract fun isNativeOrEffectivelyExternal(symbol: FirBasedSymbol<*>, session: FirSession): Boolean
|
||||
|
||||
abstract fun reportExternalEnum(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter)
|
||||
@@ -87,12 +86,24 @@ abstract class FirWebCommonExternalChecker : FirBasicDeclarationChecker(MppCheck
|
||||
|
||||
if (
|
||||
declaration is FirClass &&
|
||||
declaration.classKind != ClassKind.INTERFACE &&
|
||||
container is FirClass && container.classKind == ClassKind.INTERFACE
|
||||
!declaration.classKind.isInterface && (!allowCompanionInInterface || !declaration.status.isCompanion) &&
|
||||
container is FirClass && container.classKind.isInterface
|
||||
) {
|
||||
reporter.reportOn(declaration.source, FirWebCommonErrors.NESTED_CLASS_IN_EXTERNAL_INTERFACE, context)
|
||||
}
|
||||
|
||||
if (
|
||||
allowCompanionInInterface &&
|
||||
declaration is FirClass &&
|
||||
declaration.status.isCompanion &&
|
||||
container is FirClass &&
|
||||
container.isInterface &&
|
||||
declaration.nameOrSpecialName != DEFAULT_NAME_FOR_COMPANION_OBJECT
|
||||
) {
|
||||
reporter.reportOn(declaration.source, FirWebCommonErrors.NAMED_COMPANION_IN_EXTERNAL_INTERFACE, context)
|
||||
}
|
||||
|
||||
|
||||
if (declaration !is FirPropertyAccessor && declaration is FirCallableDeclaration && declaration.isExtension) {
|
||||
val target = when (declaration) {
|
||||
is FirFunction -> "extension function"
|
||||
|
||||
+2
@@ -645,6 +645,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
|
||||
"JS_EXTERNAL_INHERITORS_ONLY",
|
||||
"JS_EXTERNAL_ARGUMENT",
|
||||
"WRONG_EXPORTED_DECLARATION",
|
||||
"NAMED_COMPANION_IN_EXPORTED_INTERFACE",
|
||||
"NESTED_JS_EXPORT",
|
||||
"DELEGATION_BY_DYNAMIC",
|
||||
"PROPERTY_DELEGATION_BY_DYNAMIC",
|
||||
@@ -700,6 +701,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
|
||||
"CANNOT_CHECK_FOR_EXTERNAL_INTERFACE",
|
||||
"EXTERNAL_INTERFACE_AS_CLASS_LITERAL",
|
||||
"EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT",
|
||||
"NAMED_COMPANION_IN_EXTERNAL_INTERFACE",
|
||||
"JSCODE_ARGUMENT_NON_CONST_EXPRESSION",
|
||||
"SYNTAX",
|
||||
)
|
||||
|
||||
+18
-7
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.utils.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
@@ -328,12 +329,15 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
||||
members.addIfNotNull(exportProperty(candidate)?.withAttributesFor(candidate))
|
||||
|
||||
is IrClass -> {
|
||||
if (klass.isInterface) continue
|
||||
val ec = exportClass(candidate)?.withAttributesFor(candidate)
|
||||
if (ec is ExportedClass) {
|
||||
nestedClasses.add(ec)
|
||||
if (klass.isInterface) {
|
||||
nestedClasses.addIfNotNull(klass.companionObject()?.let { exportClass(it) as? ExportedClass }?.withAttributesFor(candidate))
|
||||
} else {
|
||||
members.addIfNotNull(ec)
|
||||
val ec = exportClass(candidate)?.withAttributesFor(candidate)
|
||||
if (ec is ExportedClass) {
|
||||
nestedClasses.add(ec)
|
||||
} else {
|
||||
members.addIfNotNull(ec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,7 +445,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
||||
.map { exportType(it, false) }
|
||||
.memoryOptimizedFilter { it !is ExportedType.ErrorType }
|
||||
|
||||
val name = klass.getExportedIdentifier()
|
||||
val name = klass.getExportedIdentifierForClass()
|
||||
|
||||
return if (klass.kind == ClassKind.OBJECT) {
|
||||
return ExportedObject(
|
||||
@@ -862,12 +866,19 @@ val strictModeReservedWords = setOf(
|
||||
|
||||
private val allReservedWords = reservedWords + strictModeReservedWords
|
||||
|
||||
fun ExportedDeclaration.withAttributesFor(declaration: IrDeclaration): ExportedDeclaration {
|
||||
fun <T : ExportedDeclaration> T.withAttributesFor(declaration: IrDeclaration): T {
|
||||
declaration.getDeprecated()?.let { attributes.add(ExportedAttribute.DeprecatedAttribute(it)) }
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun IrClass.getExportedIdentifierForClass(): String {
|
||||
val parentClass = parentClassOrNull
|
||||
return if (parentClass != null && isCompanion && parentClass.isInterface) {
|
||||
parentClass.getExportedIdentifierForClass()
|
||||
} else getExportedIdentifier()
|
||||
}
|
||||
|
||||
fun IrDeclarationWithName.getExportedIdentifier(): String =
|
||||
with(getJsNameOrKotlinName()) {
|
||||
if (isSpecial)
|
||||
|
||||
+5
-3
@@ -33,7 +33,7 @@ class ExportModelToJsStatements(
|
||||
fun generateModuleExport(
|
||||
module: ExportedModule,
|
||||
internalModuleName: JsName?,
|
||||
esModules: Boolean
|
||||
esModules: Boolean,
|
||||
): List<JsStatement> {
|
||||
return module.declarations.flatMap {
|
||||
generateDeclarationExport(it, internalModuleName?.makeRef(), esModules)
|
||||
@@ -44,7 +44,7 @@ class ExportModelToJsStatements(
|
||||
declaration: ExportedDeclaration,
|
||||
namespace: JsExpression?,
|
||||
esModules: Boolean,
|
||||
parentClass: IrClass? = null
|
||||
parentClass: IrClass? = null,
|
||||
): List<JsStatement> {
|
||||
return when (declaration) {
|
||||
is ExportedNamespace -> {
|
||||
@@ -155,7 +155,9 @@ class ExportModelToJsStatements(
|
||||
}
|
||||
|
||||
is ExportedRegularClass -> {
|
||||
if (declaration.isInterface) return emptyList()
|
||||
if (declaration.isInterface) {
|
||||
return declaration.nestedClasses.flatMap { generateDeclarationExport(it, namespace, esModules, parentClass) }
|
||||
}
|
||||
val (name, classInitialization) = declaration.getNameAndInitialization()
|
||||
val newNameSpace = when {
|
||||
namespace != null -> jsElementAccess(declaration.name, namespace)
|
||||
|
||||
+19
-13
@@ -14,10 +14,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.isObject
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
@@ -106,7 +103,7 @@ class ExportModelToTsDeclarations {
|
||||
is ExportedConstructSignature -> generateTypeScriptString(indent)
|
||||
is ExportedNamespace -> generateTypeScriptString(indent, prefix)
|
||||
is ExportedFunction -> generateTypeScriptString(indent, prefix)
|
||||
is ExportedRegularClass -> generateTypeScriptString(indent, prefix)
|
||||
is ExportedRegularClass -> generateTypeScriptString(indent, prefix, esModules)
|
||||
is ExportedProperty -> generateTypeScriptString(indent, prefix, esModules)
|
||||
is ExportedObject -> generateTypeScriptString(indent, prefix, esModules)
|
||||
}
|
||||
@@ -235,7 +232,7 @@ class ExportModelToTsDeclarations {
|
||||
t = ExportedType.IntersectionType(t, ExportedType.InlineInterfaceType(listOf(constructor)))
|
||||
}
|
||||
|
||||
val maybeParentClass = ir.parent as? IrClass
|
||||
val maybeParentClass = (ir.parent as? IrClass)?.takeIf { !it.isInterface }
|
||||
|
||||
val propertyName = ir
|
||||
.takeIf { shouldRenderSeparatedAbstractClass }
|
||||
@@ -275,21 +272,22 @@ class ExportModelToTsDeclarations {
|
||||
|
||||
if (esModules && !property.isMember) {
|
||||
property.copy(type = ExportedType.TypeOf(className), name = name)
|
||||
.generateTypeScriptString(indent, prefix, esModules) + "\n${classForRender.generateTypeScriptString(indent, declare)}"
|
||||
.generateTypeScriptString(indent, prefix, esModules) + "\n${classForRender.generateTypeScriptString(indent, declare, esModules)}"
|
||||
} else {
|
||||
classForRender.generateTypeScriptString(indent, prefix)
|
||||
classForRender.generateTypeScriptString(indent, prefix, esModules)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExportedRegularClass.generateTypeScriptString(indent: String, prefix: String): String {
|
||||
private fun ExportedRegularClass.generateTypeScriptString(indent: String, prefix: String, esModules: Boolean): String {
|
||||
val keyword = if (isInterface) "interface" else "class"
|
||||
val (interfaceCompanions, allNestedClasses) = nestedClasses.partition { isInterface && it.ir.isCompanion }
|
||||
val superInterfacesKeyword = if (isInterface) "extends" else "implements"
|
||||
|
||||
val superClassClause = superClasses.toExtendsClause(indent)
|
||||
val superInterfacesClause = superInterfaces.toImplementsClause(superInterfacesKeyword, indent)
|
||||
|
||||
val (memberObjects, nestedDeclarations) = nestedClasses.partition { it.couldBeProperty() }
|
||||
val (memberObjects, nestedDeclarations) = allNestedClasses.partition { it.couldBeProperty() }
|
||||
|
||||
val members = members.map {
|
||||
if (!ir.isInner || it !is ExportedFunction || !it.isStatic) {
|
||||
@@ -321,7 +319,7 @@ class ExportModelToTsDeclarations {
|
||||
|
||||
val bodyString = privateCtorString + membersString + indent
|
||||
|
||||
val nestedClasses = nonInnerClasses + innerClasses.map { it.withProtectedConstructors() }
|
||||
val realNestedClasses = nonInnerClasses + innerClasses.map { it.withProtectedConstructors() }
|
||||
val tsIgnoreForPrivateConstructorInheritance = if (hasSuperClassWithPrivateConstructor()) {
|
||||
tsIgnore("extends class with private primary constructor") + "\n$indent"
|
||||
} else ""
|
||||
@@ -329,9 +327,17 @@ class ExportModelToTsDeclarations {
|
||||
val klassExport =
|
||||
"$prefix$modifiers$keyword $name$renderedTypeParameters$superClassClause$superInterfacesClause {\n$bodyString}"
|
||||
val staticsExport =
|
||||
if (nestedClasses.isNotEmpty()) "\n" + ExportedNamespace(name, nestedClasses).toTypeScript(indent, prefix) else ""
|
||||
if (realNestedClasses.isNotEmpty()) "\n" + ExportedNamespace(name, realNestedClasses).toTypeScript(indent, prefix) else ""
|
||||
|
||||
return if (name.isValidES5Identifier()) tsIgnoreForPrivateConstructorInheritance + klassExport + staticsExport else ""
|
||||
val interfaceCompanionsString = if (interfaceCompanions.isNotEmpty()) "\n" + interfaceCompanions.joinToString("\n") {
|
||||
it.toTypeScript(
|
||||
indent,
|
||||
prefix,
|
||||
esModules
|
||||
)
|
||||
} else ""
|
||||
|
||||
return if (name.isValidES5Identifier()) tsIgnoreForPrivateConstructorInheritance + klassExport + staticsExport + interfaceCompanionsString else ""
|
||||
}
|
||||
|
||||
private fun ExportedRegularClass.hasSuperClassWithPrivateConstructor(): Boolean {
|
||||
|
||||
+3
-3
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.constant
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
|
||||
import org.jetbrains.kotlin.utils.memoryOptimizedMap
|
||||
@@ -148,9 +149,8 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
assert(obj.kind == ClassKind.OBJECT)
|
||||
assert(obj.isEffectivelyExternal()) { "Non external IrGetObjectValue must be lowered" }
|
||||
|
||||
return when {
|
||||
obj.isCompanion && obj.parentAsClass.let { it.isInterface && it.isExternal } -> JsNullLiteral()
|
||||
else -> context.getRefForExternalClass(obj).withSource(expression, context)
|
||||
return context.getRefForExternalClass(obj).withSource(expression, context).apply {
|
||||
sideEffects = SideEffectKind.PURE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -25,7 +25,14 @@ external interface GoodInterface
|
||||
|
||||
@JsExport
|
||||
interface InterfaceWithCompanion {
|
||||
companion <!WRONG_EXPORTED_DECLARATION("companion object inside exported interface")!>object<!> {
|
||||
companion object {
|
||||
fun foo() = 42
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
interface InterfaceWithNamedCompanion {
|
||||
companion <!NAMED_COMPANION_IN_EXPORTED_INTERFACE!>object Named<!> {
|
||||
fun foo() = 42
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -25,7 +25,14 @@ external interface GoodInterface
|
||||
|
||||
@JsExport
|
||||
interface InterfaceWithCompanion {
|
||||
companion <!WRONG_EXPORTED_DECLARATION("companion object inside exported interface")!>object<!> {
|
||||
companion object {
|
||||
fun foo() = 42
|
||||
}
|
||||
}
|
||||
|
||||
@JsExport
|
||||
interface InterfaceWithNamedCompanion {
|
||||
companion <!NAMED_COMPANION_IN_EXPORTED_INTERFACE!>object Named<!> {
|
||||
fun foo() = 42
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -64,6 +64,20 @@ package foo {
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.js.JsExport public interface InterfaceWithNamedCompanion {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public companion object Named {
|
||||
private constructor Named()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final fun foo(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.js.JsExport public interface OuterInterface {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
|
||||
+6
-2
@@ -9,5 +9,9 @@ external interface I {
|
||||
|
||||
enum class <!ENUM_CLASS_IN_EXTERNAL_DECLARATION_WARNING, NESTED_CLASS_IN_EXTERNAL_INTERFACE!>E<!>
|
||||
|
||||
companion <!NESTED_CLASS_IN_EXTERNAL_INTERFACE!>object<!>
|
||||
}
|
||||
companion object
|
||||
}
|
||||
|
||||
external interface I2 {
|
||||
companion <!NAMED_COMPANION_IN_EXTERNAL_INTERFACE!>object Named<!>
|
||||
}
|
||||
|
||||
+14
@@ -47,3 +47,17 @@ public external interface I {
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
|
||||
public external interface I2 {
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public companion object Named {
|
||||
private constructor Named()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user