[Wasm] Port WasmImport/WasmExport checker to K2 (KT-56849)
This commit is contained in:
committed by
Space Team
parent
28895a2613
commit
1c230c8f27
+11
@@ -23,6 +23,17 @@ object FirWasmErrors {
|
||||
val CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION by error0<PsiElement>()
|
||||
val WRONG_JS_INTEROP_TYPE by error2<KtElement, String, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
|
||||
// Wasm interop
|
||||
val NESTED_WASM_EXPORT by error0<KtElement>()
|
||||
val WASM_EXPORT_ON_EXTERNAL_DECLARATION by error0<KtElement>()
|
||||
val JS_AND_WASM_EXPORTS_ON_SAME_DECLARATION by error0<KtElement>()
|
||||
val NESTED_WASM_IMPORT by error0<KtElement>()
|
||||
val WASM_IMPORT_ON_NON_EXTERNAL_DECLARATION by error0<KtElement>()
|
||||
val WASM_IMPORT_EXPORT_PARAMETER_DEFAULT_VALUE by error0<KtElement>()
|
||||
val WASM_IMPORT_EXPORT_VARARG_PARAMETER by error0<KtElement>()
|
||||
val WASM_IMPORT_EXPORT_UNSUPPORTED_PARAMETER_TYPE by error1<KtElement, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val WASM_IMPORT_EXPORT_UNSUPPORTED_RETURN_TYPE by error1<KtElement, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
|
||||
init {
|
||||
RootDiagnosticRendererFactory.registerFactory(FirWasmErrorsDefaultMessages)
|
||||
}
|
||||
|
||||
+27
@@ -12,7 +12,16 @@ import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.CALL_TO_DEFINED_EXTERNALLY_FROM_NON_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.EXTERNAL_TYPE_EXTENDS_NON_EXTERNAL_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.JS_AND_WASM_EXPORTS_ON_SAME_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.NESTED_WASM_EXPORT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.NESTED_WASM_IMPORT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.NON_EXTERNAL_TYPE_EXTENDS_EXTERNAL_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_EXPORT_ON_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMPORT_EXPORT_PARAMETER_DEFAULT_VALUE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.wasm.FirWasmErrors.WASM_IMPORT_EXPORT_UNSUPPORTED_PARAMETER_TYPE
|
||||
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_INTEROP_TYPE
|
||||
|
||||
@Suppress("unused")
|
||||
@@ -34,5 +43,23 @@ object FirWasmErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"Type ''{0}'' cannot be used in {1}. Only external, primitive, string and function types are supported in Kotlin/Wasm JS interop.",
|
||||
TO_STRING, FirDiagnosticRenderers.RENDER_TYPE,
|
||||
)
|
||||
|
||||
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.")
|
||||
map.put(NESTED_WASM_IMPORT, "Only top-level functions can be imported with '@WasmImport'.")
|
||||
map.put(WASM_IMPORT_ON_NON_EXTERNAL_DECLARATION, "Functions annotated with '@WasmImport' must be external.")
|
||||
map.put(WASM_IMPORT_EXPORT_PARAMETER_DEFAULT_VALUE, "Default parameter values are not supported with '@WasmImport' and '@WasmExport'.")
|
||||
map.put(WASM_IMPORT_EXPORT_VARARG_PARAMETER, "Vararg parameters are not supported with '@WasmImport' and '@WasmExport'.")
|
||||
map.put(
|
||||
WASM_IMPORT_EXPORT_UNSUPPORTED_PARAMETER_TYPE,
|
||||
"Unsupported ''@WasmImport'' and ''@WasmExport'' parameter type ''{0}''.",
|
||||
FirDiagnosticRenderers.RENDER_TYPE
|
||||
)
|
||||
map.put(
|
||||
WASM_IMPORT_EXPORT_UNSUPPORTED_RETURN_TYPE,
|
||||
"Unsupported ''@WasmImport'' and ''@WasmExport'' return type ''{0}''.",
|
||||
FirDiagnosticRenderers.RENDER_TYPE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -17,5 +17,7 @@ object WasmDeclarationCheckers : DeclarationCheckers() {
|
||||
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
|
||||
get() = setOf(
|
||||
FirWasmJsInteropTypesChecker,
|
||||
FirWasmImportAnnotationChecker,
|
||||
FirWasmExportAnnotationChecker,
|
||||
)
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.analysis.wasm.checkers.hasValidJsCodeBody
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
|
||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.name.WasmStandardClassIds
|
||||
|
||||
object FirWasmExportAnnotationChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val annotation: FirAnnotation =
|
||||
declaration.annotations.getAnnotationByClassId(WasmStandardClassIds.Annotations.WasmExport, context.session) ?: return
|
||||
|
||||
if (!context.isTopLevel) {
|
||||
reporter.reportOn(annotation.source, FirWasmErrors.NESTED_WASM_EXPORT, context)
|
||||
}
|
||||
|
||||
if (declaration.annotations.hasAnnotation(WasmStandardClassIds.Annotations.JsExport, context.session)) {
|
||||
reporter.reportOn(declaration.source, FirWasmErrors.JS_AND_WASM_EXPORTS_ON_SAME_DECLARATION, context)
|
||||
}
|
||||
|
||||
if (declaration is FirSimpleFunction) {
|
||||
if (declaration.symbol.isEffectivelyExternal(context.session) || declaration.hasValidJsCodeBody()) {
|
||||
reporter.reportOn(annotation.source, FirWasmErrors.WASM_EXPORT_ON_EXTERNAL_DECLARATION, context)
|
||||
}
|
||||
|
||||
checkWasmInteropSignature(declaration, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.FirSession
|
||||
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.FirFunction
|
||||
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.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.WasmStandardClassIds
|
||||
|
||||
object FirWasmImportAnnotationChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val annotation: FirAnnotation =
|
||||
declaration.annotations.getAnnotationByClassId(WasmStandardClassIds.Annotations.WasmImport, context.session) ?: return
|
||||
|
||||
if (!context.isTopLevel) {
|
||||
reporter.reportOn(annotation.source, FirWasmErrors.NESTED_WASM_IMPORT, context)
|
||||
}
|
||||
|
||||
if (!declaration.symbol.isEffectivelyExternal(context.session)) {
|
||||
reporter.reportOn(annotation.source, FirWasmErrors.WASM_IMPORT_ON_NON_EXTERNAL_DECLARATION, context)
|
||||
}
|
||||
|
||||
if (declaration is FirFunction) {
|
||||
checkWasmInteropSignature(declaration, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkWasmInteropSignature(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
for (parameter in declaration.valueParameters) {
|
||||
val type = parameter.returnTypeRef.coneType
|
||||
if (parameter.defaultValue != null) {
|
||||
reporter.reportOn(parameter.source, FirWasmErrors.WASM_IMPORT_EXPORT_PARAMETER_DEFAULT_VALUE, context)
|
||||
}
|
||||
if (parameter.isVararg) {
|
||||
reporter.reportOn(parameter.source, FirWasmErrors.WASM_IMPORT_EXPORT_VARARG_PARAMETER, context)
|
||||
}
|
||||
if (!isTypeSupportedInWasmInterop(type, false, context.session)) {
|
||||
reporter.reportOn(parameter.source, FirWasmErrors.WASM_IMPORT_EXPORT_UNSUPPORTED_PARAMETER_TYPE, type, context)
|
||||
}
|
||||
}
|
||||
|
||||
val returnType = declaration.returnTypeRef.coneType
|
||||
if (!isTypeSupportedInWasmInterop(returnType, true, context.session)) {
|
||||
reporter.reportOn(declaration.source, FirWasmErrors.WASM_IMPORT_EXPORT_UNSUPPORTED_RETURN_TYPE, returnType, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isTypeSupportedInWasmInterop(
|
||||
unexpandedType: ConeKotlinType,
|
||||
isInFunctionReturnPosition: Boolean,
|
||||
session: FirSession,
|
||||
): Boolean {
|
||||
val type = unexpandedType.fullyExpandedType(session)
|
||||
|
||||
if (type.isUnit) {
|
||||
return isInFunctionReturnPosition
|
||||
}
|
||||
|
||||
// Primitive numbers and Boolean are supported
|
||||
return type.isPrimitive && !type.isChar
|
||||
}
|
||||
Reference in New Issue
Block a user