[JS IR] Control an inheritance of non-external entity from external
Add a special annotation @JsExternalInheritorsOnly for marking external interfaces and classes. The marked interface or class can’t be a parent for non external interfaces, classes or objects. ^KT-57423 Fixed
This commit is contained in:
committed by
Space Team
parent
6e7b078873
commit
4813b659ab
+8
@@ -5021,6 +5021,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJsErrors.JS_EXTERNAL_INHERITORS_ONLY) { firDiagnostic ->
|
||||
JsExternalInheritorsOnlyImpl(
|
||||
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.a),
|
||||
firSymbolBuilder.classifierBuilder.buildClassLikeSymbol(firDiagnostic.b),
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJsErrors.NESTED_JS_EXPORT) { firDiagnostic ->
|
||||
NestedJsExportImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
|
||||
+6
@@ -3493,6 +3493,12 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = ExternalInterfaceAsClassLiteral::class
|
||||
}
|
||||
|
||||
abstract class JsExternalInheritorsOnly : KtFirDiagnostic<KtDeclaration>() {
|
||||
override val diagnosticClass get() = JsExternalInheritorsOnly::class
|
||||
abstract val parent: KtClassLikeSymbol
|
||||
abstract val kid: KtClassLikeSymbol
|
||||
}
|
||||
|
||||
abstract class NestedJsExport : KtFirDiagnostic<KtElement>() {
|
||||
override val diagnosticClass get() = NestedJsExport::class
|
||||
}
|
||||
|
||||
+7
@@ -4226,6 +4226,13 @@ internal class ExternalInterfaceAsClassLiteralImpl(
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.ExternalInterfaceAsClassLiteral(), KtAbstractFirDiagnostic<KtElement>
|
||||
|
||||
internal class JsExternalInheritorsOnlyImpl(
|
||||
override val parent: KtClassLikeSymbol,
|
||||
override val kid: KtClassLikeSymbol,
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.JsExternalInheritorsOnly(), KtAbstractFirDiagnostic<KtDeclaration>
|
||||
|
||||
internal class NestedJsExportImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
|
||||
+5
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.PositioningStrategy
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -94,6 +95,10 @@ object JS_DIAGNOSTICS_LIST : DiagnosticList("FirJsErrors") {
|
||||
parameter<ConeKotlinType>("targetType")
|
||||
}
|
||||
val EXTERNAL_INTERFACE_AS_CLASS_LITERAL by error<KtElement>()
|
||||
val JS_EXTERNAL_INHERITORS_ONLY by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<FirClassLikeSymbol<*>>("parent")
|
||||
parameter<FirClassLikeSymbol<*>>("kid")
|
||||
}
|
||||
}
|
||||
|
||||
val EXPORT by object : DiagnosticGroup("Export") {
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
|
||||
@@ -78,6 +79,7 @@ object FirJsErrors {
|
||||
val CANNOT_CHECK_FOR_EXTERNAL_INTERFACE by error1<KtElement, ConeKotlinType>()
|
||||
val UNCHECKED_CAST_TO_EXTERNAL_INTERFACE by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val EXTERNAL_INTERFACE_AS_CLASS_LITERAL by error0<KtElement>()
|
||||
val JS_EXTERNAL_INHERITORS_ONLY by error2<KtDeclaration, FirClassLikeSymbol<*>, FirClassLikeSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
|
||||
// Export
|
||||
val NESTED_JS_EXPORT by error0<KtElement>()
|
||||
|
||||
+7
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.IMPLEMENTING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.INLINE_CLASS_IN_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.ENUM_CLASS_IN_EXTERNAL_DECLARATION_WARNING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_EXTERNAL_INHERITORS_ONLY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.INLINE_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_MODULE_PROHIBITED_ON_NON_NATIVE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_MODULE_PROHIBITED_ON_VAR
|
||||
@@ -153,6 +154,12 @@ object FirJsErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"Can''t put non-external declarations in file marked with {0} annotation",
|
||||
FirDiagnosticRenderers.RENDER_TYPE
|
||||
)
|
||||
map.put(
|
||||
JS_EXTERNAL_INHERITORS_ONLY,
|
||||
"External {0} can''t be a parent of non-external {1}",
|
||||
FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME,
|
||||
FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME
|
||||
)
|
||||
map.put(JS_NAME_PROHIBITED_FOR_EXTENSION_PROPERTY, "@JsName is prohibited for extension properties")
|
||||
map.put(JS_NAME_IS_NOT_ON_ALL_ACCESSORS, "@JsName should be on all the property accessors")
|
||||
map.put(JS_NAME_PROHIBITED_FOR_NAMED_NATIVE, "@JsName is prohibited for external declaration with explicit name")
|
||||
|
||||
+1
@@ -36,6 +36,7 @@ object JsDeclarationCheckers : DeclarationCheckers() {
|
||||
FirJsMultipleInheritanceChecker,
|
||||
FirJsDynamicDeclarationChecker,
|
||||
FirJsInheritanceClassChecker,
|
||||
FirJsExternalInheritorOnlyChecker
|
||||
)
|
||||
|
||||
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.js.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds.Annotations.JsExternalInheritorsOnly
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.popLast
|
||||
|
||||
object FirJsExternalInheritorOnlyChecker : FirClassChecker() {
|
||||
private fun FirClass.forEachParents(context: CheckerContext, f: (FirRegularClassSymbol) -> Unit) {
|
||||
val todo = superConeTypes.toMutableList()
|
||||
val done = hashSetOf<FirRegularClassSymbol>()
|
||||
|
||||
while (todo.isNotEmpty()) {
|
||||
val classSymbol = todo.popLast().toRegularClassSymbol(context.session) ?: continue
|
||||
if (done.add(classSymbol)) {
|
||||
f(classSymbol)
|
||||
classSymbol.resolvedSuperTypeRefs.mapNotNullTo(todo) { it.type as? ConeClassLikeType }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.symbol.isEffectivelyExternal(context)) {
|
||||
declaration.forEachParents(context) { parent ->
|
||||
if (parent.hasAnnotation(JsExternalInheritorsOnly, context.session)) {
|
||||
reporter.reportOn(
|
||||
declaration.source,
|
||||
FirJsErrors.JS_EXTERNAL_INHERITORS_ONLY,
|
||||
parent,
|
||||
declaration.symbol,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
// FIR_IDENTICAL
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@JsExternalInheritorsOnly
|
||||
external interface ExternalInterfaceX {
|
||||
val x: String
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@JsExternalInheritorsOnly
|
||||
external open class ExternalOpenClassX {
|
||||
val x: String
|
||||
}
|
||||
|
||||
// check interfaces
|
||||
|
||||
external interface ExternalInterfaceXY : ExternalInterfaceX {
|
||||
val y: String
|
||||
}
|
||||
|
||||
interface <!JS_EXTERNAL_INHERITORS_ONLY!>InterfaceXY<!> : ExternalInterfaceX {
|
||||
val y: String
|
||||
}
|
||||
|
||||
interface <!JS_EXTERNAL_INHERITORS_ONLY!>InterfaceXYZ<!> : ExternalInterfaceXY {
|
||||
val z: String
|
||||
}
|
||||
|
||||
// check objects
|
||||
|
||||
external object ExternalObjectXY : ExternalInterfaceX {
|
||||
override val x: String
|
||||
val y: String
|
||||
}
|
||||
|
||||
external object ExternalObjectXYZ : ExternalInterfaceXY {
|
||||
override val x: String
|
||||
override val y: String
|
||||
val z: String
|
||||
}
|
||||
|
||||
external object ExternalObjectXZ : ExternalOpenClassX {
|
||||
val z: String
|
||||
}
|
||||
|
||||
<!JS_EXTERNAL_INHERITORS_ONLY!>object ObjectXY<!> : ExternalInterfaceX {
|
||||
override val x: String = "X"
|
||||
val y: String = "Y"
|
||||
}
|
||||
|
||||
<!JS_EXTERNAL_INHERITORS_ONLY!>object ObjectXYZ<!> : ExternalInterfaceXY {
|
||||
override val x: String = "X"
|
||||
override val y: String = "Y"
|
||||
val z: String = "Z"
|
||||
}
|
||||
|
||||
<!JS_EXTERNAL_INHERITORS_ONLY!>object ObjectXZ<!> : ExternalOpenClassX() {
|
||||
val z: String = "Z"
|
||||
}
|
||||
|
||||
// check classes
|
||||
|
||||
external class ExternalClassXY : ExternalInterfaceX {
|
||||
override val x: String
|
||||
val y: String
|
||||
}
|
||||
|
||||
external class ExternalClassXYZ : ExternalInterfaceXY {
|
||||
override val x: String
|
||||
override val y: String
|
||||
val z: String
|
||||
}
|
||||
|
||||
external open class ExternalOpenClassXZ : ExternalOpenClassX {
|
||||
val z: String
|
||||
}
|
||||
|
||||
class <!JS_EXTERNAL_INHERITORS_ONLY!>ClassXY<!> : ExternalInterfaceX {
|
||||
override val x: String = "X"
|
||||
val y: String = "Y"
|
||||
}
|
||||
|
||||
class <!JS_EXTERNAL_INHERITORS_ONLY!>ClassXYZ<!> : ExternalInterfaceXY {
|
||||
override val x: String = "X"
|
||||
override val y: String = "Y"
|
||||
val z: String = "Z"
|
||||
}
|
||||
|
||||
class <!JS_EXTERNAL_INHERITORS_ONLY!>ClassXZ<!> : ExternalOpenClassX() {
|
||||
val z: String = "Z"
|
||||
}
|
||||
|
||||
class <!JS_EXTERNAL_INHERITORS_ONLY!>ClassXZY<!> : ExternalOpenClassXZ() {
|
||||
val y: String = "Y"
|
||||
}
|
||||
|
||||
// check nested
|
||||
|
||||
external class ExternalClassNameSpace {
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@JsExternalInheritorsOnly
|
||||
interface NestedInterfaceX {
|
||||
val x: String
|
||||
}
|
||||
|
||||
interface NestedInterfaceXY : NestedInterfaceX {
|
||||
val y: String
|
||||
}
|
||||
}
|
||||
|
||||
external interface ExternalInterfaceXY2 : ExternalClassNameSpace.NestedInterfaceX {
|
||||
val y: String
|
||||
}
|
||||
|
||||
external interface ExternalInterfaceXYZ2 : ExternalClassNameSpace.NestedInterfaceXY {
|
||||
val z: String
|
||||
}
|
||||
|
||||
interface <!JS_EXTERNAL_INHERITORS_ONLY!>InterfaceXY2<!> : ExternalClassNameSpace.NestedInterfaceX {
|
||||
val y: String
|
||||
}
|
||||
|
||||
interface <!JS_EXTERNAL_INHERITORS_ONLY!>InterfaceXYZ2<!> : ExternalClassNameSpace.NestedInterfaceXY {
|
||||
val z: String
|
||||
}
|
||||
|
||||
// multiple inheritance
|
||||
|
||||
external class ExternalClassXY2 : ExternalInterfaceX, ExternalOpenClassX {
|
||||
val y: String
|
||||
}
|
||||
|
||||
class <!JS_EXTERNAL_INHERITORS_ONLY, JS_EXTERNAL_INHERITORS_ONLY!>ClassXY2<!> : ExternalInterfaceX, ExternalOpenClassX() {
|
||||
val y: String = "Y"
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
package
|
||||
|
||||
public final class ClassXY : ExternalInterfaceX {
|
||||
public constructor ClassXY()
|
||||
public open override /*1*/ val x: kotlin.String = "X"
|
||||
public final val y: kotlin.String = "Y"
|
||||
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 final class ClassXY2 : ExternalInterfaceX, ExternalOpenClassX {
|
||||
public constructor ClassXY2()
|
||||
public final override /*2*/ /*fake_override*/ val x: kotlin.String
|
||||
public final val y: kotlin.String = "Y"
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class ClassXYZ : ExternalInterfaceXY {
|
||||
public constructor ClassXYZ()
|
||||
public open override /*1*/ val x: kotlin.String = "X"
|
||||
public open override /*1*/ val y: kotlin.String = "Y"
|
||||
public final val z: kotlin.String = "Z"
|
||||
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 final class ClassXZ : ExternalOpenClassX {
|
||||
public constructor ClassXZ()
|
||||
public final override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public final val z: kotlin.String = "Z"
|
||||
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 final class ClassXZY : ExternalOpenClassXZ {
|
||||
public constructor ClassXZY()
|
||||
public final override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public final val y: kotlin.String = "Y"
|
||||
public final override /*1*/ /*fake_override*/ val z: kotlin.String
|
||||
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 final external class ExternalClassNameSpace {
|
||||
public constructor ExternalClassNameSpace()
|
||||
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
|
||||
|
||||
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) @kotlin.js.JsExternalInheritorsOnly public interface NestedInterfaceX {
|
||||
public abstract val x: kotlin.String
|
||||
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 interface NestedInterfaceXY : ExternalClassNameSpace.NestedInterfaceX {
|
||||
public abstract override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public abstract val y: kotlin.String
|
||||
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 final external class ExternalClassXY : ExternalInterfaceX {
|
||||
public constructor ExternalClassXY()
|
||||
public open override /*1*/ val x: kotlin.String
|
||||
public final val y: kotlin.String
|
||||
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 final external class ExternalClassXY2 : ExternalInterfaceX, ExternalOpenClassX {
|
||||
public constructor ExternalClassXY2()
|
||||
public final override /*2*/ /*fake_override*/ val x: kotlin.String
|
||||
public final val y: kotlin.String
|
||||
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final external class ExternalClassXYZ : ExternalInterfaceXY {
|
||||
public constructor ExternalClassXYZ()
|
||||
public open override /*1*/ val x: kotlin.String
|
||||
public open override /*1*/ val y: kotlin.String
|
||||
public final val z: kotlin.String
|
||||
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
|
||||
}
|
||||
|
||||
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) @kotlin.js.JsExternalInheritorsOnly public external interface ExternalInterfaceX {
|
||||
public abstract val x: kotlin.String
|
||||
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 external interface ExternalInterfaceXY : ExternalInterfaceX {
|
||||
public abstract override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public abstract val y: kotlin.String
|
||||
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 external interface ExternalInterfaceXY2 : ExternalClassNameSpace.NestedInterfaceX {
|
||||
public abstract override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public abstract val y: kotlin.String
|
||||
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 external interface ExternalInterfaceXYZ2 : ExternalClassNameSpace.NestedInterfaceXY {
|
||||
public abstract override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public abstract override /*1*/ /*fake_override*/ val y: kotlin.String
|
||||
public abstract val z: kotlin.String
|
||||
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 external object ExternalObjectXY : ExternalInterfaceX {
|
||||
private constructor ExternalObjectXY()
|
||||
public open override /*1*/ val x: kotlin.String
|
||||
public final val y: kotlin.String
|
||||
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 external object ExternalObjectXYZ : ExternalInterfaceXY {
|
||||
private constructor ExternalObjectXYZ()
|
||||
public open override /*1*/ val x: kotlin.String
|
||||
public open override /*1*/ val y: kotlin.String
|
||||
public final val z: kotlin.String
|
||||
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 external object ExternalObjectXZ : ExternalOpenClassX {
|
||||
private constructor ExternalObjectXZ()
|
||||
public final override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public final val z: kotlin.String
|
||||
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
|
||||
}
|
||||
|
||||
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) @kotlin.js.JsExternalInheritorsOnly public open external class ExternalOpenClassX {
|
||||
public constructor ExternalOpenClassX()
|
||||
public final val x: kotlin.String
|
||||
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 open external class ExternalOpenClassXZ : ExternalOpenClassX {
|
||||
public constructor ExternalOpenClassXZ()
|
||||
public final override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public final val z: kotlin.String
|
||||
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 interface InterfaceXY : ExternalInterfaceX {
|
||||
public abstract override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public abstract val y: kotlin.String
|
||||
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 interface InterfaceXY2 : ExternalClassNameSpace.NestedInterfaceX {
|
||||
public abstract override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public abstract val y: kotlin.String
|
||||
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 interface InterfaceXYZ : ExternalInterfaceXY {
|
||||
public abstract override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public abstract override /*1*/ /*fake_override*/ val y: kotlin.String
|
||||
public abstract val z: kotlin.String
|
||||
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 interface InterfaceXYZ2 : ExternalClassNameSpace.NestedInterfaceXY {
|
||||
public abstract override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public abstract override /*1*/ /*fake_override*/ val y: kotlin.String
|
||||
public abstract val z: kotlin.String
|
||||
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 object ObjectXY : ExternalInterfaceX {
|
||||
private constructor ObjectXY()
|
||||
public open override /*1*/ val x: kotlin.String = "X"
|
||||
public final val y: kotlin.String = "Y"
|
||||
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 object ObjectXYZ : ExternalInterfaceXY {
|
||||
private constructor ObjectXYZ()
|
||||
public open override /*1*/ val x: kotlin.String = "X"
|
||||
public open override /*1*/ val y: kotlin.String = "Y"
|
||||
public final val z: kotlin.String = "Z"
|
||||
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 object ObjectXZ : ExternalOpenClassX {
|
||||
private constructor ObjectXZ()
|
||||
public final override /*1*/ /*fake_override*/ val x: kotlin.String
|
||||
public final val z: kotlin.String = "Z"
|
||||
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
|
||||
}
|
||||
|
||||
+6
@@ -36,6 +36,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
|
||||
runTest("compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExternalInheritorsOnly.kt")
|
||||
public void testJsExternalInheritorsOnly() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJsStdLib/jsExternalInheritorsOnly.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("localClassMetadata.kt")
|
||||
public void testLocalClassMetadata() throws Exception {
|
||||
|
||||
@@ -41,6 +41,9 @@ object JsStandardClassIds {
|
||||
@JvmField
|
||||
val JsExport = "JsExport".jsId()
|
||||
|
||||
@JvmField
|
||||
val JsExternalInheritorsOnly = "JsExternalInheritorsOnly".jsId()
|
||||
|
||||
@JvmField
|
||||
val JsExportIgnore = JsExport.createNestedClassId(Name.identifier("Ignore"))
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ object JsPlatformConfigurator : PlatformConfiguratorBase(
|
||||
NativeInvokeChecker(), NativeGetterChecker(), NativeSetterChecker(),
|
||||
JsNameChecker, JsModuleChecker, JsExternalFileChecker,
|
||||
JsExternalChecker, JsInheritanceChecker, JsMultipleInheritanceChecker,
|
||||
JsExternalInheritorOnlyChecker,
|
||||
JsRuntimeAnnotationChecker,
|
||||
JsDynamicDeclarationChecker,
|
||||
JsExportAnnotationChecker,
|
||||
|
||||
+5
@@ -109,6 +109,11 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
||||
|
||||
put(ErrorsJs.NON_CONSUMABLE_EXPORTED_IDENTIFIER, "Exported declaration contains non-consumable identifier '${0}', that can't be represented inside TS definitions and ESM", STRING)
|
||||
|
||||
put(ErrorsJs.JS_EXTERNAL_INHERITORS_ONLY,
|
||||
"External {0} can''t be a parent of non-external {1}",
|
||||
Renderers.DECLARATION_NAME_WITH_KIND,
|
||||
Renderers.DECLARATION_NAME_WITH_KIND)
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,9 @@ public interface ErrorsJs {
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> NON_CONSUMABLE_EXPORTED_IDENTIFIER = DiagnosticFactory1.create(WARNING, DEFAULT);
|
||||
|
||||
DiagnosticFactory2<PsiElement, DeclarationDescriptor, DeclarationDescriptor> JS_EXTERNAL_INHERITORS_ONLY = DiagnosticFactory2.create(
|
||||
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
{
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.js.resolve.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
|
||||
|
||||
object JsExternalInheritorOnlyChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (descriptor is ClassDescriptor && !descriptor.isEffectivelyExternal()) {
|
||||
descriptor.getAllSuperClassifiers().forEach { parent ->
|
||||
if (parent is ClassDescriptor && AnnotationsUtils.isJsExternalInheritorsOnly(parent)) {
|
||||
context.trace.report(ErrorsJs.JS_EXTERNAL_INHERITORS_ONLY.on(declaration, parent, descriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ public final class AnnotationsUtils {
|
||||
private static final FqName JS_MODULE_ANNOTATION = Annotations.JsModule.asSingleFqName();
|
||||
private static final FqName JS_NON_MODULE_ANNOTATION = Annotations.JsNonModule.asSingleFqName();
|
||||
private static final FqName JS_QUALIFIER_ANNOTATION = Annotations.JsQualifier.asSingleFqName();
|
||||
private static final FqName JS_EXTERNAL_INHERITORS_ONLY = Annotations.JsExternalInheritorsOnly.asSingleFqName();
|
||||
|
||||
private AnnotationsUtils() {
|
||||
}
|
||||
@@ -258,6 +259,10 @@ public final class AnnotationsUtils {
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean isJsExternalInheritorsOnly(@NotNull ClassDescriptor declaration) {
|
||||
return declaration.getAnnotations().hasAnnotation(JS_EXTERNAL_INHERITORS_ONLY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String extractSingleStringArgument(@NotNull AnnotationDescriptor annotation) {
|
||||
if (annotation.getAllValueArguments().isEmpty()) return null;
|
||||
|
||||
+6
@@ -2457,6 +2457,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
|
||||
runTest("js/js.translator/testData/box/esModules/jsModule/interfaces.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExternalInheritorsOnly.kt")
|
||||
public void testJsExternalInheritorsOnly() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/jsModule/jsExternalInheritorsOnly.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevelVarargFun.kt")
|
||||
public void testTopLevelVarargFun() throws Exception {
|
||||
|
||||
+6
@@ -37,6 +37,12 @@ public class FirPsiJsOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiJ
|
||||
runTest("compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExternalInheritorsOnly.kt")
|
||||
public void testJsExternalInheritorsOnly() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJsStdLib/jsExternalInheritorsOnly.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("localClassMetadata.kt")
|
||||
public void testLocalClassMetadata() throws Exception {
|
||||
|
||||
+6
@@ -2563,6 +2563,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
||||
runTest("js/js.translator/testData/box/esModules/jsModule/interfaces.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExternalInheritorsOnly.kt")
|
||||
public void testJsExternalInheritorsOnly() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/jsModule/jsExternalInheritorsOnly.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevelVarargFun.kt")
|
||||
public void testTopLevelVarargFun() throws Exception {
|
||||
|
||||
+6
@@ -2457,6 +2457,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
||||
runTest("js/js.translator/testData/box/esModules/jsModule/interfaces.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jsExternalInheritorsOnly.kt")
|
||||
public void testJsExternalInheritorsOnly() throws Exception {
|
||||
runTest("js/js.translator/testData/box/esModules/jsModule/jsExternalInheritorsOnly.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevelVarargFun.kt")
|
||||
public void testTopLevelVarargFun() throws Exception {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
// DONT_TARGET_EXACT_BACKEND: JS
|
||||
// DONT_TARGET_EXACT_BACKEND: WASM
|
||||
// ES_MODULES
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@JsExternalInheritorsOnly
|
||||
external interface ExternalInterfaceX {
|
||||
val x: String
|
||||
}
|
||||
|
||||
external interface ExternalInterfaceXY : ExternalInterfaceX {
|
||||
val y: String
|
||||
}
|
||||
|
||||
external interface ExternalInterfaceXYZ : ExternalInterfaceXY {
|
||||
val z: String
|
||||
}
|
||||
|
||||
external class ExternalXYZ() : ExternalInterfaceXYZ {
|
||||
override val x: String
|
||||
override val y: String
|
||||
override val z: String
|
||||
}
|
||||
|
||||
external class ExternalClassNameSpace {
|
||||
interface NestedInterfaceXYZ : ExternalInterfaceXYZ {
|
||||
override val x: String
|
||||
override val y: String
|
||||
override val z: String
|
||||
}
|
||||
}
|
||||
|
||||
@JsModule("./jsExternalInheritorsOnly.mjs")
|
||||
external object Creator: ExternalInterfaceXYZ {
|
||||
fun createX(): ExternalInterfaceX
|
||||
fun createXY(): ExternalInterfaceXY
|
||||
fun createXYZ(): ExternalInterfaceXYZ
|
||||
fun createClassXYZ(): ExternalXYZ
|
||||
|
||||
fun createNestedInterfaceXYZ(): ExternalClassNameSpace.NestedInterfaceXYZ
|
||||
|
||||
override val x: String
|
||||
override val y: String
|
||||
override val z: String
|
||||
}
|
||||
|
||||
fun checkX(x: ExternalInterfaceX, id: Int) = x.x == "X$id"
|
||||
fun checkXY(xy: ExternalInterfaceXY, id: Int) = checkX(xy, id) && xy.y == "Y$id"
|
||||
fun checkXYZ(xyz: ExternalInterfaceXYZ, id: Int) = checkXY(xyz, id) && xyz.z == "Z$id"
|
||||
|
||||
fun box(): String {
|
||||
if (!checkX(Creator.createX(), 1)) return "Fail interface X"
|
||||
if (!checkXY(Creator.createXY(), 2)) return "Fail interface XY"
|
||||
if (!checkXYZ(Creator.createXYZ(), 3)) return "Fail interface XYZ"
|
||||
|
||||
if (!checkXYZ(Creator.createClassXYZ(), 4)) return "Fail class XYZ"
|
||||
|
||||
if (!checkXYZ(Creator.createNestedInterfaceXYZ(), 5)) return "Fail nested interface XYZ"
|
||||
|
||||
if (!checkXYZ(Creator, 6)) return "Fail object XYZ"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
export default {
|
||||
createX: function () {
|
||||
return {x: "X1"};
|
||||
},
|
||||
createXY: function () {
|
||||
return {x: "X2", y: "Y2"};
|
||||
},
|
||||
createXYZ: function () {
|
||||
return {x: "X3", y: "Y3", z: "Z3"};
|
||||
},
|
||||
createClassXYZ: function () {
|
||||
return {x: "X4", y: "Y4", z: "Z4"};
|
||||
},
|
||||
createNestedInterfaceXYZ: function () {
|
||||
return {x: "X5", y: "Y5", z: "Z5"};
|
||||
},
|
||||
|
||||
x: "X6",
|
||||
y: "Y6",
|
||||
z: "Z6"
|
||||
};
|
||||
@@ -250,6 +250,14 @@ public final annotation class JsExport : kotlin.Annotation {
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
|
||||
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS})
|
||||
@kotlin.SinceKotlin(version = "1.9")
|
||||
public final annotation class JsExternalInheritorsOnly : kotlin.Annotation {
|
||||
public constructor JsExternalInheritorsOnly()
|
||||
}
|
||||
|
||||
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
|
||||
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.FILE})
|
||||
public final annotation class JsModule : kotlin.Annotation {
|
||||
|
||||
@@ -249,6 +249,14 @@ public final annotation class JsExport : kotlin.Annotation {
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.ExperimentalStdlibApi
|
||||
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
|
||||
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS})
|
||||
@kotlin.SinceKotlin(version = "1.9")
|
||||
public final annotation class JsExternalInheritorsOnly : kotlin.Annotation {
|
||||
public constructor JsExternalInheritorsOnly()
|
||||
}
|
||||
|
||||
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
|
||||
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.FILE})
|
||||
public final annotation class JsModule : kotlin.Annotation {
|
||||
|
||||
@@ -211,4 +211,44 @@ public actual annotation class JsExport {
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@SinceKotlin("1.6")
|
||||
@Deprecated("This annotation is a temporal migration assistance and may be removed in the future releases, please consider filing an issue about the case where it is needed")
|
||||
public annotation class EagerInitialization
|
||||
public annotation class EagerInitialization
|
||||
|
||||
|
||||
/**
|
||||
* When placed on an external interface or class, requires all its child
|
||||
* interfaces, classes, and objects to be external as well.
|
||||
*
|
||||
* The compiler mangles identifiers of functions and properties from non-external interfaces and classes,
|
||||
* and doesn't mangle from external ones. Requiring external interfaces and classes inheritors being external
|
||||
* is necessary to avoid non-obvious bugs when identifier naming in an inheritor doesn't correspond to
|
||||
* naming in the base class or interface.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```kotlin
|
||||
* // From kotlin-wrappers
|
||||
* external interface Props {
|
||||
* var key: Key?
|
||||
* }
|
||||
*
|
||||
* // User code
|
||||
* @OptIn(ExperimentalStdlibApi::class)
|
||||
* @JsExternalInheritorsOnly
|
||||
* external interface LayoutProps : Props {
|
||||
* var layout: Layout?
|
||||
* }
|
||||
*
|
||||
* external interface ComponentProps : LayoutProps // OK
|
||||
*
|
||||
* external interface ComponentA : ComponentProps // OK
|
||||
*
|
||||
* interface ComponentB : ComponentProps // Compilation error!
|
||||
* ```
|
||||
*
|
||||
* This annotation is experimental, meaning that the restrictions mentioned above are subject to change.
|
||||
*/
|
||||
@ExperimentalStdlibApi
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(CLASS)
|
||||
@SinceKotlin("1.9")
|
||||
public annotation class JsExternalInheritorsOnly
|
||||
|
||||
Reference in New Issue
Block a user