[JS IR] Allow restriction of function argument by external type

Add a special annotation @JsExternalTypeArgument for
 marking function parameters. The marked parameter
 accepts an argument with an external type only.

^KT-57479 Fixed
This commit is contained in:
Alexander Korepanov
2023-03-21 15:35:52 +01:00
committed by Space Team
parent 4819593bf4
commit e8be3043cc
21 changed files with 394 additions and 1 deletions
@@ -5047,6 +5047,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirJsErrors.JS_EXTERNAL_ARGUMENT) { firDiagnostic ->
JsExternalArgumentImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirJsErrors.NESTED_JS_EXPORT) { firDiagnostic ->
NestedJsExportImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -3513,6 +3513,11 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val kid: KtClassLikeSymbol
}
abstract class JsExternalArgument : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = JsExternalArgument::class
abstract val argType: KtType
}
abstract class NestedJsExport : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = NestedJsExport::class
}
@@ -4249,6 +4249,12 @@ internal class JsExternalInheritorsOnlyImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.JsExternalInheritorsOnly(), KtAbstractFirDiagnostic<KtDeclaration>
internal class JsExternalArgumentImpl(
override val argType: KtType,
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.JsExternalArgument(), KtAbstractFirDiagnostic<KtExpression>
internal class NestedJsExportImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
@@ -99,6 +99,9 @@ object JS_DIAGNOSTICS_LIST : DiagnosticList("FirJsErrors") {
parameter<FirClassLikeSymbol<*>>("parent")
parameter<FirClassLikeSymbol<*>>("kid")
}
val JS_EXTERNAL_ARGUMENT by error<KtExpression>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
parameter<ConeKotlinType>("argType")
}
}
val EXPORT by object : DiagnosticGroup("Export") {
@@ -80,6 +80,7 @@ object FirJsErrors {
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)
val JS_EXTERNAL_ARGUMENT by error1<KtExpression, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
// Export
val NESTED_JS_EXPORT by error0<KtElement>()
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.INLINE_CLASS
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_EXTERNAL_ARGUMENT
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
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NESTED_JS_MODULE_PROHIBITED
@@ -163,6 +164,11 @@ object FirJsErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME,
FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME
)
map.put(
JS_EXTERNAL_ARGUMENT,
"Expected argument with external type, but type {0} is non-external",
FirDiagnosticRenderers.RENDER_TYPE
)
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")
@@ -25,4 +25,9 @@ object JsExpressionCheckers : ExpressionCheckers() {
get() = setOf(
FirJsDynamicCallChecker,
)
override val callCheckers: Set<FirCallChecker>
get() = setOf(
FirJsExternalArgumentCallChecker
)
}
@@ -0,0 +1,42 @@
/*
* 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.expression.FirCallChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
import org.jetbrains.kotlin.fir.expressions.FirCall
import org.jetbrains.kotlin.fir.expressions.resolvedArgumentMapping
import org.jetbrains.kotlin.fir.expressions.unwrapArgument
import org.jetbrains.kotlin.fir.types.ConeDynamicType
import org.jetbrains.kotlin.fir.types.coneTypeOrNull
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
import org.jetbrains.kotlin.name.JsStandardClassIds.Annotations.JsExternalArgument
object FirJsExternalArgumentCallChecker : FirCallChecker() {
override fun check(expression: FirCall, context: CheckerContext, reporter: DiagnosticReporter) {
val arguments = expression.resolvedArgumentMapping ?: return
for ((argument, parameter) in arguments) {
if (parameter.hasAnnotation(JsExternalArgument, context.session)) {
val unwrappedArg = argument.unwrapArgument()
val type = unwrappedArg.typeRef.coneTypeOrNull ?: continue
val symbol = type.toRegularClassSymbol(context.session)
if (symbol?.isEffectivelyExternal(context.session) == false || type is ConeDynamicType) {
reporter.reportOn(
unwrappedArg.source,
FirJsErrors.JS_EXTERNAL_ARGUMENT,
type,
context
)
}
}
}
}
}
@@ -0,0 +1,143 @@
// FIR_IDENTICAL
@OptIn(ExperimentalStdlibApi::class)
fun anyExample(@JsExternalArgument x : Any) = x
@OptIn(ExperimentalStdlibApi::class)
fun anyOrNullExample(@JsExternalArgument x : Any?) = x
@OptIn(ExperimentalStdlibApi::class)
fun <T> genericExample(@JsExternalArgument x : T) = x
@OptIn(ExperimentalStdlibApi::class)
fun <T> genericOrNullExample(@JsExternalArgument x : T?) = x
@OptIn(ExperimentalStdlibApi::class)
fun dynamicExample(@JsExternalArgument x : dynamic) = x
@OptIn(ExperimentalStdlibApi::class)
fun severalParams(@JsExternalArgument x : Any?, @JsExternalArgument y : Any?, @JsExternalArgument z : dynamic) = x ?: y ?: z
external interface ExternalInterface
fun boxExternalInterface(i: ExternalInterface) {
anyExample(i)
anyOrNullExample(i)
genericExample(i)
genericOrNullExample(i)
dynamicExample(i)
}
fun boxExternalInterfaceOrNull(iOrNull: ExternalInterface?) {
anyOrNullExample(iOrNull)
genericExample(iOrNull)
genericOrNullExample(iOrNull)
dynamicExample(iOrNull)
}
external class ExternalClass
fun boxExternalClass(c: ExternalClass) {
anyExample(c)
anyOrNullExample(c)
genericExample(c)
genericOrNullExample(c)
dynamicExample(c)
}
external object ExternalObject
fun boxExternalObject() {
anyExample(ExternalObject)
anyOrNullExample(ExternalObject)
genericExample(ExternalObject)
genericOrNullExample(ExternalObject)
dynamicExample(ExternalObject)
}
interface Interface
fun boxInterface(i: Interface) {
anyExample(<!JS_EXTERNAL_ARGUMENT!>i<!>)
anyOrNullExample(<!JS_EXTERNAL_ARGUMENT!>i<!>)
genericExample(<!JS_EXTERNAL_ARGUMENT!>i<!>)
genericOrNullExample(<!JS_EXTERNAL_ARGUMENT!>i<!>)
dynamicExample(<!JS_EXTERNAL_ARGUMENT!>i<!>)
}
fun boxInterfaceOrNull(iOrNull: Interface?) {
anyOrNullExample(<!JS_EXTERNAL_ARGUMENT!>iOrNull<!>)
genericExample(<!JS_EXTERNAL_ARGUMENT!>iOrNull<!>)
genericOrNullExample(<!JS_EXTERNAL_ARGUMENT!>iOrNull<!>)
dynamicExample(<!JS_EXTERNAL_ARGUMENT!>iOrNull<!>)
}
class Class
fun boxInterface(c: Class) {
anyExample(<!JS_EXTERNAL_ARGUMENT!>c<!>)
anyOrNullExample(<!JS_EXTERNAL_ARGUMENT!>c<!>)
genericExample(<!JS_EXTERNAL_ARGUMENT!>c<!>)
genericOrNullExample(<!JS_EXTERNAL_ARGUMENT!>c<!>)
dynamicExample(<!JS_EXTERNAL_ARGUMENT!>c<!>)
}
object Object
fun boxObject() {
anyExample(<!JS_EXTERNAL_ARGUMENT!>Object<!>)
anyOrNullExample(<!JS_EXTERNAL_ARGUMENT!>Object<!>)
genericExample(<!JS_EXTERNAL_ARGUMENT!>Object<!>)
genericOrNullExample(<!JS_EXTERNAL_ARGUMENT!>Object<!>)
dynamicExample(<!JS_EXTERNAL_ARGUMENT!>Object<!>)
}
fun boxDynamic(d: dynamic) {
anyExample(<!JS_EXTERNAL_ARGUMENT!>d<!>)
anyOrNullExample(<!JS_EXTERNAL_ARGUMENT!>d<!>)
genericExample(<!JS_EXTERNAL_ARGUMENT!>d<!>)
genericOrNullExample(<!JS_EXTERNAL_ARGUMENT!>d<!>)
dynamicExample(<!JS_EXTERNAL_ARGUMENT!>d<!>)
}
fun boxPrimitiveTypes() {
anyExample(<!JS_EXTERNAL_ARGUMENT!>1<!>)
anyExample(<!JS_EXTERNAL_ARGUMENT!>1.2<!>)
anyExample(<!JS_EXTERNAL_ARGUMENT!>true<!>)
anyExample(<!JS_EXTERNAL_ARGUMENT!>"hello"<!>)
anyExample(<!JS_EXTERNAL_ARGUMENT!>{}<!>)
anyExample(<!JS_EXTERNAL_ARGUMENT!>{}()<!>)
anyOrNullExample(<!JS_EXTERNAL_ARGUMENT!>null<!>)
}
fun boxArgExpression(i: Interface, iOrNull: Interface?) {
anyExample(<!JS_EXTERNAL_ARGUMENT!>iOrNull ?: i<!>)
}
fun boxNamedArgExpression(i: Interface, iOrNull: Interface?, d: dynamic) {
anyExample(x = <!JS_EXTERNAL_ARGUMENT!>iOrNull ?: i<!>)
severalParams(
x = <!JS_EXTERNAL_ARGUMENT!>i<!>,
y = <!JS_EXTERNAL_ARGUMENT!>iOrNull ?: i<!>,
z = <!JS_EXTERNAL_ARGUMENT!>iOrNull ?: d<!>
)
severalParams(
z = <!JS_EXTERNAL_ARGUMENT!>iOrNull ?: d<!>,
x = <!JS_EXTERNAL_ARGUMENT!>i<!>,
y = <!JS_EXTERNAL_ARGUMENT!>iOrNull ?: i<!>
)
severalParams(
<!JS_EXTERNAL_ARGUMENT!>i<!>,
z = <!JS_EXTERNAL_ARGUMENT!>iOrNull ?: d<!>,
y = <!JS_EXTERNAL_ARGUMENT!>iOrNull ?: i<!>
)
severalParams(
x = <!JS_EXTERNAL_ARGUMENT!>i<!>,
y = ExternalObject,
z = <!JS_EXTERNAL_ARGUMENT!>iOrNull ?: d<!>
)
}
@@ -0,0 +1,61 @@
package
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public fun anyExample(/*0*/ @kotlin.js.JsExternalArgument x: kotlin.Any): kotlin.Any
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public fun anyOrNullExample(/*0*/ @kotlin.js.JsExternalArgument x: kotlin.Any?): kotlin.Any?
public fun boxArgExpression(/*0*/ i: Interface, /*1*/ iOrNull: Interface?): kotlin.Unit
public fun boxDynamic(/*0*/ d: dynamic): kotlin.Unit
public fun boxExternalClass(/*0*/ c: ExternalClass): kotlin.Unit
public fun boxExternalInterface(/*0*/ i: ExternalInterface): kotlin.Unit
public fun boxExternalInterfaceOrNull(/*0*/ iOrNull: ExternalInterface?): kotlin.Unit
public fun boxExternalObject(): kotlin.Unit
public fun boxInterface(/*0*/ c: Class): kotlin.Unit
public fun boxInterface(/*0*/ i: Interface): kotlin.Unit
public fun boxInterfaceOrNull(/*0*/ iOrNull: Interface?): kotlin.Unit
public fun boxNamedArgExpression(/*0*/ i: Interface, /*1*/ iOrNull: Interface?, /*2*/ d: dynamic): kotlin.Unit
public fun boxObject(): kotlin.Unit
public fun boxPrimitiveTypes(): kotlin.Unit
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public fun dynamicExample(/*0*/ @kotlin.js.JsExternalArgument x: dynamic): dynamic
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public fun </*0*/ T> genericExample(/*0*/ @kotlin.js.JsExternalArgument x: T): T
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public fun </*0*/ T> genericOrNullExample(/*0*/ @kotlin.js.JsExternalArgument x: T?): T?
@kotlin.OptIn(markerClass = {kotlin.ExperimentalStdlibApi::class}) public fun severalParams(/*0*/ @kotlin.js.JsExternalArgument x: kotlin.Any?, /*1*/ @kotlin.js.JsExternalArgument y: kotlin.Any?, /*2*/ @kotlin.js.JsExternalArgument z: dynamic): dynamic
public final class Class {
public constructor Class()
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 ExternalClass {
public constructor ExternalClass()
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 ExternalInterface {
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 ExternalObject {
private constructor ExternalObject()
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 Interface {
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 Object {
private constructor Object()
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
}
@@ -48,6 +48,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
runTest("compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt");
}
@Test
@TestMetadata("jsExternalArgument.kt")
public void testJsExternalArgument() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/jsExternalArgument.kt");
}
@Test
@TestMetadata("jsExternalInheritorsOnly.kt")
public void testJsExternalInheritorsOnly() throws Exception {
@@ -44,6 +44,9 @@ object JsStandardClassIds {
@JvmField
val JsExternalInheritorsOnly = "JsExternalInheritorsOnly".jsId()
@JvmField
val JsExternalArgument = "JsExternalArgument".jsId()
@JvmField
val JsExportIgnore = JsExport.createNestedClassId(Name.identifier("Ignore"))
@@ -32,7 +32,8 @@ object JsPlatformConfigurator : PlatformConfiguratorBase(
JsModuleCallChecker,
JsDynamicCallChecker,
JsDefinedExternallyCallChecker,
LateinitIntrinsicApplicabilityChecker(isWarningInPre19 = true)
LateinitIntrinsicApplicabilityChecker(isWarningInPre19 = true),
JsExternalArgumentCallChecker
),
) {
override fun configureModuleComponents(container: StorageComponentContainer) {
@@ -114,6 +114,10 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
Renderers.DECLARATION_NAME_WITH_KIND,
Renderers.DECLARATION_NAME_WITH_KIND)
put(ErrorsJs.JS_EXTERNAL_ARGUMENT,
"Expected argument with external type, but type {0} is non-external",
Renderers.RENDER_TYPE)
this
}
}
@@ -117,6 +117,9 @@ public interface ErrorsJs {
DiagnosticFactory2<PsiElement, DeclarationDescriptor, DeclarationDescriptor> JS_EXTERNAL_INHERITORS_ONLY = DiagnosticFactory2.create(
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory1<PsiElement, KotlinType> JS_EXTERNAL_ARGUMENT = DiagnosticFactory1.create(
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
{
@@ -0,0 +1,32 @@
/*
* 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 com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.util.getParameterForArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
object JsExternalArgumentCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
for (argument in resolvedCall.call.valueArguments) {
val parameter = resolvedCall.getParameterForArgument(argument) ?: continue
if (AnnotationsUtils.isJsExternalArgument(parameter)) {
val argExpression = argument.getArgumentExpression() ?: continue
val argumentType = context.trace.bindingContext.getType(argExpression) ?: continue
val declaration = argumentType.makeNotNullable().constructor.declarationDescriptor as? ClassDescriptor ?: continue
if (!declaration.isEffectivelyExternal()) {
context.trace.report(ErrorsJs.JS_EXTERNAL_ARGUMENT.on(argExpression, argumentType))
}
}
}
}
}
@@ -47,6 +47,7 @@ public final class AnnotationsUtils {
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 static final FqName JS_EXTERNAL_ARGUMENT = Annotations.JsExternalArgument.asSingleFqName();
private AnnotationsUtils() {
}
@@ -263,6 +264,10 @@ public final class AnnotationsUtils {
return declaration.getAnnotations().hasAnnotation(JS_EXTERNAL_INHERITORS_ONLY);
}
public static boolean isJsExternalArgument(@NotNull ValueParameterDescriptor declaration) {
return declaration.getAnnotations().hasAnnotation(JS_EXTERNAL_ARGUMENT);
}
@Nullable
private static String extractSingleStringArgument(@NotNull AnnotationDescriptor annotation) {
if (annotation.getAllValueArguments().isEmpty()) return null;
@@ -49,6 +49,12 @@ public class FirPsiJsOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiJ
runTest("compiler/testData/diagnostics/testsWithJsStdLib/implementingFunction.kt");
}
@Test
@TestMetadata("jsExternalArgument.kt")
public void testJsExternalArgument() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/jsExternalArgument.kt");
}
@Test
@TestMetadata("jsExternalInheritorsOnly.kt")
public void testJsExternalInheritorsOnly() throws Exception {
+8
View File
@@ -250,6 +250,14 @@ public final annotation class JsExport : kotlin.Annotation {
}
}
@kotlin.ExperimentalStdlibApi
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.VALUE_PARAMETER})
@kotlin.SinceKotlin(version = "1.9")
public final annotation class JsExternalArgument : kotlin.Annotation {
public constructor JsExternalArgument()
}
@kotlin.ExperimentalStdlibApi
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS})
+8
View File
@@ -249,6 +249,14 @@ public final annotation class JsExport : kotlin.Annotation {
}
}
@kotlin.ExperimentalStdlibApi
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.VALUE_PARAMETER})
@kotlin.SinceKotlin(version = "1.9")
public final annotation class JsExternalArgument : kotlin.Annotation {
public constructor JsExternalArgument()
}
@kotlin.ExperimentalStdlibApi
@kotlin.annotation.Retention(value = AnnotationRetention.BINARY)
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS})
@@ -252,3 +252,41 @@ public annotation class EagerInitialization
@Target(CLASS)
@SinceKotlin("1.9")
public annotation class JsExternalInheritorsOnly
/**
* When placed on a function parameter, requires the type of the passed argument to be external.
*
* The compiler mangles identifiers of properties from non-external interfaces and classes,
* and doesn't mangle from external ones. Requiring a type of the passing argument being external is necessary
* to avoid non-obvious bugs when identifier has an unstable and unpredictable name in generated JS code.
*
* Example:
*
* ```kotlin
*
* @OptIn(ExperimentalStdlibApi::class)
* fun extractUuid(@JsExternalArgument x: dynamic) = x.uuid as String
*
* external interface User {
* val uuid: String
* }
*
* interface Owner {
* val uuid: String
* }
*
* fun checkUser(user: User, owner: Owner): Boolean {
* val userUuid = extractUuid(user) // OK
* val ownerUuid = extractUuid(owner) // Compilation error! Possible bug
* return userUuid == ownerUuid
* }
* ```
*
* This annotation is experimental, meaning that the restrictions mentioned above are subject to change.
*/
@ExperimentalStdlibApi
@Retention(AnnotationRetention.BINARY)
@Target(VALUE_PARAMETER)
@SinceKotlin("1.9")
public annotation class JsExternalArgument