diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWasmDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWasmDiagnosticsList.kt index bb12a9d54d0..937452a8d5d 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWasmDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirWasmDiagnosticsList.kt @@ -29,6 +29,10 @@ object WASM_DIAGNOSTICS_LIST : DiagnosticList("FirWasmErrors") { } } + val JS_FUN by object : DiagnosticGroup("JsFun") { + val WRONG_JS_FUN_TARGET by error() + } + val WASM_INTEROP by object : DiagnosticGroup("Wasm interop") { val NESTED_WASM_EXPORT by error() val WASM_EXPORT_ON_EXTERNAL_DECLARATION by error() diff --git a/compiler/fir/checkers/checkers.wasm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrors.kt b/compiler/fir/checkers/checkers.wasm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrors.kt index f267ac62124..5b9247542cd 100644 --- a/compiler/fir/checkers/checkers.wasm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrors.kt +++ b/compiler/fir/checkers/checkers.wasm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrors.kt @@ -23,6 +23,9 @@ object FirWasmErrors { val CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION by error0() val WRONG_JS_INTEROP_TYPE by error2(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) + // JsFun + val WRONG_JS_FUN_TARGET by error0() + // Wasm interop val NESTED_WASM_EXPORT by error0() val WASM_EXPORT_ON_EXTERNAL_DECLARATION by error0() diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrorsDefaultMessages.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrorsDefaultMessages.kt index bebf0e21407..a45e3da41d0 100644 --- a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/wasm/FirWasmErrorsDefaultMessages.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMP import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMPORT_EXPORT_UNSUPPORTED_RETURN_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMPORT_EXPORT_VARARG_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMPORT_ON_NON_EXTERNAL_DECLARATION +import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WRONG_JS_FUN_TARGET import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WRONG_JS_INTEROP_TYPE @Suppress("unused") @@ -45,6 +46,8 @@ object FirWasmErrorsDefaultMessages : BaseDiagnosticRendererFactory() { TO_STRING, FirDiagnosticRenderers.RENDER_TYPE, ) + map.put(WRONG_JS_FUN_TARGET, "Only top-level external functions can be implemented using '@JsFun'.") + map.put(NESTED_WASM_EXPORT, "Only top-level functions can be exported with '@WasmExport'.") map.put(WASM_EXPORT_ON_EXTERNAL_DECLARATION, "Functions annotated with '@WasmExport' must not be external.") map.put(JS_AND_WASM_EXPORTS_ON_SAME_DECLARATION, "Cannot use '@WasmExport' and '@JsExport' for same function.") diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt index a33d7d9ea17..b1075f872b6 100644 --- a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt +++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/WasmDeclarationCheckers.kt @@ -20,5 +20,6 @@ object WasmDeclarationCheckers : DeclarationCheckers() { FirWasmImportAnnotationChecker, FirWasmExportAnnotationChecker, FirWasmExternalChecker, + FirWasmJsFunAnnotationChecker, ) } diff --git a/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmJsFunAnnotationChecker.kt b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmJsFunAnnotationChecker.kt new file mode 100644 index 00000000000..c623d8dcbfb --- /dev/null +++ b/compiler/fir/checkers/checkers.wasm/src/org/jetbrains/kotlin/fir/analysis/wasm/checkers/declaration/FirWasmJsFunAnnotationChecker.kt @@ -0,0 +1,29 @@ +/* + * 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.wasm.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.FirBasicDeclarationChecker +import org.jetbrains.kotlin.fir.analysis.checkers.isTopLevel +import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId +import org.jetbrains.kotlin.fir.declarations.utils.isEffectivelyExternal +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.name.WasmStandardClassIds + +object FirWasmJsFunAnnotationChecker : FirBasicDeclarationChecker() { + override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) { + val annotation: FirAnnotation = + declaration.annotations.getAnnotationByClassId(WasmStandardClassIds.Annotations.JsFun, context.session) ?: return + + if (!context.isTopLevel || !declaration.symbol.isEffectivelyExternal(context.session)) { + reporter.reportOn(annotation.source, FirWasmErrors.WRONG_JS_FUN_TARGET, context) + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/wasmTests/jsInterop/jsFun.fir.kt b/compiler/testData/diagnostics/wasmTests/jsInterop/jsFun.fir.kt deleted file mode 100644 index a7efd05a3ed..00000000000 --- a/compiler/testData/diagnostics/wasmTests/jsInterop/jsFun.fir.kt +++ /dev/null @@ -1,15 +0,0 @@ -@JsFun("() => {}") -external fun topLevelExternalFun(): Unit - -external class ExternalClass { - @JsFun("() => {}") - fun memberFun(): Unit -} - -@JsFun("() => {}") -fun topLevelNonExternalFun(): Unit {} - -class NonExternalClass { - @JsFun("() => {}") - fun memberFun(): Unit {} -} diff --git a/compiler/testData/diagnostics/wasmTests/jsInterop/jsFun.kt b/compiler/testData/diagnostics/wasmTests/jsInterop/jsFun.kt index 7ae2cad609e..805c81a15e7 100644 --- a/compiler/testData/diagnostics/wasmTests/jsInterop/jsFun.kt +++ b/compiler/testData/diagnostics/wasmTests/jsInterop/jsFun.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL @JsFun("() => {}") external fun topLevelExternalFun(): Unit diff --git a/core/compiler.common.wasm/src/org/jetbrains/kotlin/name/WasmStandardClassIds.kt b/core/compiler.common.wasm/src/org/jetbrains/kotlin/name/WasmStandardClassIds.kt index a19d7413b90..5af6ba489c0 100644 --- a/core/compiler.common.wasm/src/org/jetbrains/kotlin/name/WasmStandardClassIds.kt +++ b/core/compiler.common.wasm/src/org/jetbrains/kotlin/name/WasmStandardClassIds.kt @@ -29,6 +29,9 @@ object WasmStandardClassIds { @JvmField val WasmExport = "WasmExport".wasmId() + + @JvmField + val JsFun = "JsFun".baseId() } object Callables { @@ -40,6 +43,8 @@ object WasmStandardClassIds { } } +private fun String.baseId() = ClassId(StandardClassIds.BASE_KOTLIN_PACKAGE, Name.identifier(this)) + private fun String.jsId() = ClassId(WasmStandardClassIds.BASE_JS_PACKAGE, Name.identifier(this)) private fun String.wasmId() = ClassId(WasmStandardClassIds.BASE_WASM_PACKAGE, Name.identifier(this)) diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmJsFunAnnotationChecker.kt b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmJsFunAnnotationChecker.kt index 521f350085b..6afd08d5f67 100644 --- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmJsFunAnnotationChecker.kt +++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmJsFunAnnotationChecker.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal import org.jetbrains.kotlin.resolve.source.getPsi -// TODO: Implement in K2: KT-56849 object WasmJsFunAnnotationChecker : DeclarationChecker { private val jsFunFqName = FqName("kotlin.JsFun")