From 60d35200f68276e9841f2561ecf3e882087f66a6 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Fri, 14 Jul 2023 17:48:14 +0200 Subject: [PATCH] [Wasm] Wasi frontend diagnostics --- .../project/structure/impl/KtModuleUtils.kt | 4 +- .../jetbrains/kotlin/cli/js/K2JsIrCompiler.kt | 6 ++- .../js/klib/TopDownAnalyzerFacadeForWasm.kt | 22 ++++++++-- .../kotlin/cli/js/klib/compilerPipeline.kt | 12 ++++-- .../cli/common/FirSessionConstructionUtils.kt | 11 ++++- .../jetbrains/kotlin/test/TestSetupUtils.kt | 4 +- .../classic/ClassicFrontend2IrConverter.kt | 3 +- .../frontend/classic/ClassicFrontendFacade.kt | 6 ++- .../WasmEnvironmentConfigurator.kt | 3 ++ .../resolve/WasmPlatformAnalyzerServices.kt | 16 +++++++- .../wasm/resolve/WasmPlatformConfigurator.kt | 40 +++++++++++++++++-- .../diagnostics/DefaultErrorMessagesWasm.kt | 2 + .../wasm/resolve/diagnostics/ErrorsWasm.java | 3 ++ .../diagnostics/WasmInteropTypesChecker.kt | 18 ++++++--- .../WasmWasiExternalDeclarationChecker.kt | 37 +++++++++++++++++ 15 files changed, 161 insertions(+), 26 deletions(-) create mode 100644 wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmWasiExternalDeclarationChecker.kt diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleUtils.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleUtils.kt index b83c912f373..4c0d25f4a10 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleUtils.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/project/structure/impl/KtModuleUtils.kt @@ -28,7 +28,6 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices import org.jetbrains.kotlin.parsing.KotlinParserDefinition -import org.jetbrains.kotlin.wasm.resolve.WasmPlatformAnalyzerServices import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.platform.isJs @@ -40,6 +39,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices +import org.jetbrains.kotlin.wasm.resolve.WasmJsPlatformAnalyzerServices import java.io.IOException import java.nio.file.* import java.nio.file.attribute.BasicFileAttributes @@ -49,7 +49,7 @@ internal fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServ return when { isJvm() -> JvmPlatformAnalyzerServices isJs() -> JsPlatformAnalyzerServices - isWasm() -> WasmPlatformAnalyzerServices + isWasm() -> WasmJsPlatformAnalyzerServices isNative() -> NativePlatformAnalyzerServices isCommon() -> CommonPlatformAnalyzerServices else -> error("Unknown target platform: $this") diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index 725b48ad1a2..dca692b62b9 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -420,6 +420,10 @@ class K2JsIrCompiler : CLICompiler() { ): ModulesStructure { lateinit var sourceModule: ModulesStructure do { + val analyzerFacade = when (arguments.wasm) { + true -> TopDownAnalyzerFacadeForWasm.facadeFor(environmentForJS.configuration.get(JSConfigurationKeys.WASM_TARGET)) + else -> TopDownAnalyzerFacadeForJSIR + } sourceModule = prepareAnalyzedSourceModule( environmentForJS.project, environmentForJS.getSourceFiles(), @@ -427,7 +431,7 @@ class K2JsIrCompiler : CLICompiler() { libraries, friendLibraries, AnalyzerWithCompilerReport(environmentForJS.configuration), - analyzerFacade = if (arguments.wasm) TopDownAnalyzerFacadeForWasm else TopDownAnalyzerFacadeForJSIR + analyzerFacade = analyzerFacade ) val result = sourceModule.jsFrontEndResult.jsAnalysisResult if (result is JsAnalysisResult.RetryWithAdditionalRoots) { diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/TopDownAnalyzerFacadeForWasm.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/TopDownAnalyzerFacadeForWasm.kt index 7a0d37e9b30..96ae59af1b9 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/TopDownAnalyzerFacadeForWasm.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/TopDownAnalyzerFacadeForWasm.kt @@ -12,14 +12,15 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider import org.jetbrains.kotlin.ir.backend.js.JsFactories import org.jetbrains.kotlin.js.analyze.AbstractTopDownAnalyzerFacadeForWeb +import org.jetbrains.kotlin.js.config.WasmTarget import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.wasm.WasmPlatforms import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices -import org.jetbrains.kotlin.wasm.resolve.WasmPlatformAnalyzerServices +import org.jetbrains.kotlin.wasm.resolve.WasmJsPlatformAnalyzerServices +import org.jetbrains.kotlin.wasm.resolve.WasmWasiPlatformAnalyzerServices -object TopDownAnalyzerFacadeForWasm : AbstractTopDownAnalyzerFacadeForWeb() { - override val analyzerServices: PlatformDependentAnalyzerServices = WasmPlatformAnalyzerServices +abstract class TopDownAnalyzerFacadeForWasm : AbstractTopDownAnalyzerFacadeForWeb() { override val platform: TargetPlatform = WasmPlatforms.Default override fun loadIncrementalCacheMetadata( @@ -36,4 +37,19 @@ object TopDownAnalyzerFacadeForWasm : AbstractTopDownAnalyzerFacadeForWeb() { lookupTracker ) } + + companion object { + fun facadeFor(target: WasmTarget?): TopDownAnalyzerFacadeForWasm = when (target) { + WasmTarget.WASI -> TopDownAnalyzerFacadeForWasmWasi + else -> TopDownAnalyzerFacadeForWasmJs + } + } +} + +object TopDownAnalyzerFacadeForWasmJs : TopDownAnalyzerFacadeForWasm() { + override val analyzerServices: PlatformDependentAnalyzerServices = WasmJsPlatformAnalyzerServices +} + +object TopDownAnalyzerFacadeForWasmWasi : TopDownAnalyzerFacadeForWasm() { + override val analyzerServices: PlatformDependentAnalyzerServices = WasmWasiPlatformAnalyzerServices } \ No newline at end of file diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt index 5b1c62a9cd6..ad572f1118f 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.ir.util.IrMessageLogger import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.config.WasmTarget import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices import org.jetbrains.kotlin.library.KotlinAbiVersion import org.jetbrains.kotlin.library.impl.BuiltInsPlatform @@ -49,7 +50,8 @@ import org.jetbrains.kotlin.platform.wasm.WasmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.utils.metadataVersion -import org.jetbrains.kotlin.wasm.resolve.WasmPlatformAnalyzerServices +import org.jetbrains.kotlin.wasm.resolve.WasmJsPlatformAnalyzerServices +import org.jetbrains.kotlin.wasm.resolve.WasmWasiPlatformAnalyzerServices import java.io.File import java.nio.file.Paths @@ -70,9 +72,13 @@ inline fun compileModuleToAnalyzedFir( val mainModuleName = moduleStructure.compilerConfiguration.get(CommonConfigurationKeys.MODULE_NAME)!! val escapedMainModuleName = Name.special("<$mainModuleName>") - val platform = if (useWasmPlatform) WasmPlatforms.Default else JsPlatforms.defaultJsPlatform - val platformAnalyzerServices = if (useWasmPlatform) WasmPlatformAnalyzerServices else JsPlatformAnalyzerServices + val platformAnalyzerServices = if (useWasmPlatform) { + when (moduleStructure.compilerConfiguration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS)) { + WasmTarget.JS -> WasmJsPlatformAnalyzerServices + WasmTarget.WASI -> WasmWasiPlatformAnalyzerServices + } + } else JsPlatformAnalyzerServices val binaryModuleData = BinaryModuleData.initialize(escapedMainModuleName, platform, platformAnalyzerServices) val dependencyList = DependencyListForCliModule.build(binaryModuleData) { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt index 1ec8294b455..692a7151463 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/FirSessionConstructionUtils.kt @@ -20,6 +20,8 @@ import org.jetbrains.kotlin.fir.session.* import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope import org.jetbrains.kotlin.incremental.components.LookupTracker +import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.config.WasmTarget import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary @@ -37,7 +39,8 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices import org.jetbrains.kotlin.resolve.multiplatform.hmppModuleName import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource -import org.jetbrains.kotlin.wasm.resolve.WasmPlatformAnalyzerServices +import org.jetbrains.kotlin.wasm.resolve.WasmJsPlatformAnalyzerServices +import org.jetbrains.kotlin.wasm.resolve.WasmWasiPlatformAnalyzerServices val isCommonSourceForPsi: (KtFile) -> Boolean = { it.isCommonSource == true } val fileBelongsToModuleForPsi: (KtFile, String) -> Boolean = { file, moduleName -> file.hmppModuleName == moduleName } @@ -213,8 +216,12 @@ fun prepareWasmSessions( lookupTracker: LookupTracker?, icData: KlibIcData?, ): List> { + val analyzerServices = when (configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS)) { + WasmTarget.JS -> WasmJsPlatformAnalyzerServices + WasmTarget.WASI -> WasmWasiPlatformAnalyzerServices + } return prepareSessions( - files, configuration, rootModuleName, WasmPlatforms.Default, WasmPlatformAnalyzerServices, + files, configuration, rootModuleName, WasmPlatforms.Default, analyzerServices, metadataCompilationMode = false, libraryList, isCommonSource, fileBelongsToModule, createLibrarySession = { sessionProvider -> FirWasmSessionFactory.createLibrarySession( diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/TestSetupUtils.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/TestSetupUtils.kt index 3f0b4b4eb4b..91cbeaf612b 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/TestSetupUtils.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/TestSetupUtils.kt @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.platform.konan.isNative import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices -import org.jetbrains.kotlin.wasm.resolve.WasmPlatformAnalyzerServices +import org.jetbrains.kotlin.wasm.resolve.WasmJsPlatformAnalyzerServices import java.io.File /** @@ -41,7 +41,7 @@ fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServices { isJs() -> JsPlatformAnalyzerServices isNative() -> NativePlatformAnalyzerServices isCommon() -> CommonPlatformAnalyzerServices - isWasm() -> WasmPlatformAnalyzerServices + isWasm() -> WasmJsPlatformAnalyzerServices else -> error("Unknown target platform: $this") } } \ No newline at end of file diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontend2IrConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontend2IrConverter.kt index a609850d809..7927d18e04b 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontend2IrConverter.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontend2IrConverter.kt @@ -154,7 +154,8 @@ class ClassicFrontend2IrConverter( } val errorPolicy = configuration.get(JSConfigurationKeys.ERROR_TOLERANCE_POLICY) ?: ErrorTolerancePolicy.DEFAULT - val hasErrors = TopDownAnalyzerFacadeForWasm.checkForErrors(sourceFiles, analysisResult.bindingContext, errorPolicy) + val analyzerFacade = TopDownAnalyzerFacadeForWasm.facadeFor(configuration.get(JSConfigurationKeys.WASM_TARGET)) + val hasErrors = analyzerFacade.checkForErrors(sourceFiles, analysisResult.bindingContext, errorPolicy) val metadataSerializer = KlibMetadataIncrementalSerializer(configuration, project, hasErrors) return IrBackendInput.WasmBackendInput( diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt index e7a389656fe..d718d0dda48 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontendFacade.kt @@ -44,6 +44,8 @@ import org.jetbrains.kotlin.incremental.components.InlineConstTracker import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.ir.backend.js.* import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS +import org.jetbrains.kotlin.js.config.JSConfigurationKeys +import org.jetbrains.kotlin.js.config.WasmTarget import org.jetbrains.kotlin.library.unresolvedDependencies import org.jetbrains.kotlin.load.java.lazy.SingleModuleClassResolver import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager @@ -356,7 +358,9 @@ class ClassicFrontendFacade( val allDependencies = runtimeKlibs + dependencyDescriptors + friendLibraries + friendsDescriptors + transitiveLibraries val builtInModuleDescriptor = allDependencies.firstNotNullOfOrNull { it.builtIns }?.builtInsModule - return TopDownAnalyzerFacadeForWasm.analyzeFiles( + val analyzerFacade = TopDownAnalyzerFacadeForWasm.facadeFor(configuration.get(JSConfigurationKeys.WASM_TARGET)) + + return analyzerFacade.analyzeFiles( files, project, configuration, diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/WasmEnvironmentConfigurator.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/WasmEnvironmentConfigurator.kt index 70a682f7ce7..c4a6e66d80e 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/WasmEnvironmentConfigurator.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/WasmEnvironmentConfigurator.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.SourceMapSourceEmbedding +import org.jetbrains.kotlin.js.config.WasmTarget import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.INFER_MAIN_MODULE @@ -158,5 +159,7 @@ class WasmEnvironmentConfigurator(testServices: TestServices) : EnvironmentConfi configuration.put(CommonConfigurationKeys.EXPECT_ACTUAL_LINKER, EXPECT_ACTUAL_LINKER in registeredDirectives) configuration.put(JSConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS, DISABLE_WASM_EXCEPTION_HANDLING in registeredDirectives) + + configuration.put(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) } } \ No newline at end of file diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/WasmPlatformAnalyzerServices.kt b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/WasmPlatformAnalyzerServices.kt index 6021d7168dd..f56037f945b 100644 --- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/WasmPlatformAnalyzerServices.kt +++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/WasmPlatformAnalyzerServices.kt @@ -11,12 +11,15 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.storage.StorageManager +// TODO: Here for IDE ABI, remove after rename in IDE +typealias WasmJsPlatformAnalyzerServices = WasmPlatformAnalyzerServices + object WasmPlatformAnalyzerServices : PlatformDependentAnalyzerServices() { override fun computePlatformSpecificDefaultImports(storageManager: StorageManager, result: MutableList) { result.add(ImportPath.fromString("kotlin.js.*")) } - override val platformConfigurator: PlatformConfigurator = WasmPlatformConfigurator + override val platformConfigurator: PlatformConfigurator = WasmJsPlatformConfigurator val builtIns: KotlinBuiltIns get() = DefaultBuiltIns.Instance @@ -24,3 +27,14 @@ object WasmPlatformAnalyzerServices : PlatformDependentAnalyzerServices() { override val excludedImports: List = listOf("Promise", "Date", "Console", "Math", "RegExp", "RegExpMatch", "Json", "json").map { FqName("kotlin.js.$it") } } + +object WasmWasiPlatformAnalyzerServices : PlatformDependentAnalyzerServices() { + override fun computePlatformSpecificDefaultImports(storageManager: StorageManager, result: MutableList) { + result.add(ImportPath.fromString("kotlin.wasm.*")) + } + + override val platformConfigurator: PlatformConfigurator = WasmWasiPlatformConfigurator + + val builtIns: KotlinBuiltIns + get() = DefaultBuiltIns.Instance +} \ No newline at end of file diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/WasmPlatformConfigurator.kt b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/WasmPlatformConfigurator.kt index ca8b7b3cb13..213bfa05429 100644 --- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/WasmPlatformConfigurator.kt +++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/WasmPlatformConfigurator.kt @@ -8,8 +8,6 @@ package org.jetbrains.kotlin.wasm.resolve import org.jetbrains.kotlin.container.StorageComponentContainer import org.jetbrains.kotlin.container.useImpl import org.jetbrains.kotlin.container.useInstance -import org.jetbrains.kotlin.js.analyze.JsNativeDiagnosticSuppressor -import org.jetbrains.kotlin.js.naming.NameSuggestion import org.jetbrains.kotlin.js.naming.WasmNameSuggestion import org.jetbrains.kotlin.js.resolve.ExtensionFunctionToExternalIsInlinable import org.jetbrains.kotlin.js.resolve.diagnostics.* @@ -21,7 +19,8 @@ import org.jetbrains.kotlin.wasm.resolve.diagnostics.* // TODO: Review the list of used K/JS checkers. // Refactor useful checkers into common module. -object WasmPlatformConfigurator : PlatformConfiguratorBase( +// KT-56848 +object WasmJsPlatformConfigurator : PlatformConfiguratorBase( additionalDeclarationCheckers = listOf( JsNameChecker, JsModuleChecker, JsExternalFileChecker, JsExternalChecker, WasmExternalInheritanceChecker, @@ -30,9 +29,9 @@ object WasmPlatformConfigurator : PlatformConfiguratorBase( JsExportDeclarationChecker, WasmExternalDeclarationChecker, WasmImportAnnotationChecker, - WasmExportAnnotationChecker, WasmJsFunAnnotationChecker, WasmJsInteropTypesChecker, + WasmJsExportChecker, ), additionalCallCheckers = listOf( JsModuleCallChecker, @@ -59,3 +58,36 @@ object WasmPlatformConfigurator : PlatformConfiguratorBase( container.useImpl() } } + + +// TODO: Review the list of used K/JS checkers. +// Refactor useful checkers into common module. +// KT-56848 +object WasmWasiPlatformConfigurator : PlatformConfiguratorBase( + additionalDeclarationCheckers = listOf( + JsRuntimeAnnotationChecker, + WasmImportAnnotationChecker, + WasmWasiExportChecker, + WasmWasiExternalDeclarationChecker, + ), + additionalCallCheckers = listOf( + LateinitIntrinsicApplicabilityChecker(isWarningInPre19 = true) + ), +) { + override fun configureModuleComponents(container: StorageComponentContainer) { + container.useInstance(WasmNameSuggestion()) + container.useImpl() + container.useImpl() + container.useImpl() + container.useImpl() + container.useImpl() + container.useInstance(ExtensionFunctionToExternalIsInlinable) + container.useInstance(JsQualifierChecker) + container.useInstance(WasmDiagnosticSuppressor) + } + + override fun configureModuleDependentCheckers(container: StorageComponentContainer) { + super.configureModuleDependentCheckers(container) + container.useImpl() + } +} diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/DefaultErrorMessagesWasm.kt b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/DefaultErrorMessagesWasm.kt index 7d39be949cd..5840cf48ea2 100644 --- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/DefaultErrorMessagesWasm.kt +++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/DefaultErrorMessagesWasm.kt @@ -28,6 +28,8 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { put(ErrorsWasm.NESTED_WASM_EXPORT, "Only top-level functions can be exported with @WasmExport") put(ErrorsWasm.WASM_EXPORT_ON_EXTERNAL_DECLARATION, "Functions annotated with @WasmExport must not be external") put(ErrorsWasm.JS_AND_WASM_EXPORTS_ON_SAME_DECLARATION, "Cannot use @WasmExport and @JsExport for same function") + put(ErrorsWasm.WASI_EXTERNAL_NOT_TOP_LEVEL_FUNCTION, "Only top-level functions can be external") + put(ErrorsWasm.WASI_EXTERNAL_FUNCTION_WITHOUT_IMPORT, "External functions should be annotated with @WasmImport") put(ErrorsWasm.NESTED_WASM_IMPORT, "Only top-level functions can be imported with @WasmImport") put(ErrorsWasm.WASM_IMPORT_ON_NON_EXTERNAL_DECLARATION, "Functions annotated with @WasmImport must be external") diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/ErrorsWasm.java b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/ErrorsWasm.java index 631c7651a84..2a67bd381c9 100644 --- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/ErrorsWasm.java +++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/ErrorsWasm.java @@ -23,6 +23,9 @@ public interface ErrorsWasm { DiagnosticFactory0 WASM_EXPORT_ON_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 JS_AND_WASM_EXPORTS_ON_SAME_DECLARATION = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 WASI_EXTERNAL_NOT_TOP_LEVEL_FUNCTION = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 WASI_EXTERNAL_FUNCTION_WITHOUT_IMPORT = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 NESTED_WASM_IMPORT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 WASM_IMPORT_ON_NON_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 WASM_IMPORT_EXPORT_PARAMETER_DEFAULT_VALUE = DiagnosticFactory0.create(ERROR); diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmInteropTypesChecker.kt b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmInteropTypesChecker.kt index b17886a14cc..b5f400fbdd4 100644 --- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmInteropTypesChecker.kt +++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmInteropTypesChecker.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal import org.jetbrains.kotlin.wasm.util.hasValidJsCodeBody // TODO: Implement in K2: KT-56849 -object WasmExportAnnotationChecker : DeclarationChecker { +abstract class WasmExportAnnotationChecker(val checkJsInterop: Boolean) : DeclarationChecker { private val wasmExportFqName = FqName("kotlin.wasm.WasmExport") private val jsExportFqName = FqName("kotlin.js.JsExport") @@ -28,12 +28,14 @@ object WasmExportAnnotationChecker : DeclarationChecker { val trace = context.trace val bindingContext = trace.bindingContext - if (descriptor.annotations.hasAnnotation(jsExportFqName)) { - val reportOn = descriptor.findPsi() ?: declaration - trace.report(ErrorsWasm.JS_AND_WASM_EXPORTS_ON_SAME_DECLARATION.on(reportOn)) + if (checkJsInterop) { + if (descriptor.annotations.hasAnnotation(jsExportFqName)) { + val reportOn = descriptor.findPsi() ?: declaration + trace.report(ErrorsWasm.JS_AND_WASM_EXPORTS_ON_SAME_DECLARATION.on(reportOn)) + } } - if (descriptor.isEffectivelyExternal() || descriptor.hasValidJsCodeBody(bindingContext)) { + if (descriptor.isEffectivelyExternal() || (checkJsInterop && descriptor.hasValidJsCodeBody(bindingContext))) { val reportOn = descriptor.findPsi() ?: declaration trace.report(ErrorsWasm.WASM_EXPORT_ON_EXTERNAL_DECLARATION.on(reportOn)) } @@ -45,4 +47,8 @@ object WasmExportAnnotationChecker : DeclarationChecker { WasmImportAnnotationChecker.checkSignatureIsPrimitive(descriptor, trace, declaration) } -} \ No newline at end of file +} + +object WasmJsExportChecker : WasmExportAnnotationChecker(checkJsInterop = true) + +object WasmWasiExportChecker : WasmExportAnnotationChecker(checkJsInterop = false) \ No newline at end of file diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmWasiExternalDeclarationChecker.kt b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmWasiExternalDeclarationChecker.kt new file mode 100644 index 00000000000..ac79599508a --- /dev/null +++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/resolve/diagnostics/WasmWasiExternalDeclarationChecker.kt @@ -0,0 +1,37 @@ +/* + * 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.wasm.resolve.diagnostics + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.MemberDescriptor +import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal + +// TODO: Implement in K2: KT-56849 +object WasmWasiExternalDeclarationChecker : DeclarationChecker { + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if (descriptor !is MemberDescriptor) return + if (!descriptor.isEffectivelyExternal()) return + + if (descriptor is FunctionDescriptor) { + if (!DescriptorUtils.isTopLevelDeclaration(descriptor)) { + val reportOn = descriptor.findPsi() ?: declaration + context.trace.report(ErrorsWasm.WASI_EXTERNAL_NOT_TOP_LEVEL_FUNCTION.on(reportOn)) + } else { + if (!descriptor.annotations.hasAnnotation(FqName("kotlin.wasm.WasmImport"))) { + val reportOn = descriptor.findPsi() ?: declaration + context.trace.report(ErrorsWasm.WASI_EXTERNAL_FUNCTION_WITHOUT_IMPORT.on(reportOn)) + } + } + } + } +} \ No newline at end of file