[Wasm] Allow implementing function interfaces
diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt
index 73407a8..b39d664 100644
--- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt
+++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt
@@ -391,6 +391,9 @@
             if (isIrBackendEnabled()) {
                 this[LanguageFeature.JsAllowValueClassesInExternals] = LanguageFeature.State.ENABLED
             }
+            if (wasm) {
+                this[LanguageFeature.JsAllowImplementingFunctionInterface] = LanguageFeature.State.ENABLED
+            }
         }
     }
 }
diff --git a/compiler/testData/codegen/box/classes/kt1535.kt b/compiler/testData/codegen/box/classes/kt1535.kt
index b97b80e..de7816b 100644
--- a/compiler/testData/codegen/box/classes/kt1535.kt
+++ b/compiler/testData/codegen/box/classes/kt1535.kt
@@ -1,5 +1,3 @@
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IMPLEMENTING_FUNCTION_INTERFACE
 // IGNORE_BACKEND: JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 // TODO: Enable when JS backend supports Java class library, since FunctionX are required for interoperation
diff --git a/compiler/testData/codegen/box/closures/closureOnTopLevel1.kt b/compiler/testData/codegen/box/closures/closureOnTopLevel1.kt
index cfc94f1..1975736 100644
--- a/compiler/testData/codegen/box/closures/closureOnTopLevel1.kt
+++ b/compiler/testData/codegen/box/closures/closureOnTopLevel1.kt
@@ -1,5 +1,3 @@
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IMPLEMENTING_FUNCTION_INTERFACE
 // IGNORE_BACKEND: JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 // TODO: muted automatically, investigate should it be ran for JS or not
diff --git a/compiler/testData/codegen/box/closures/closureOnTopLevel2.kt b/compiler/testData/codegen/box/closures/closureOnTopLevel2.kt
index 5f25ce4..642b069 100644
--- a/compiler/testData/codegen/box/closures/closureOnTopLevel2.kt
+++ b/compiler/testData/codegen/box/closures/closureOnTopLevel2.kt
@@ -1,5 +1,3 @@
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IMPLEMENTING_FUNCTION_INTERFACE
 // IGNORE_BACKEND: JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 // TODO: muted automatically, investigate should it be ran for JS or not
diff --git a/compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt b/compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt
index bb6d30f..261346e 100644
--- a/compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt
+++ b/compiler/testData/codegen/box/coroutines/suspendConversion/intersectionTypeToSubtypeConversion.kt
@@ -4,8 +4,6 @@
 // IGNORE_BACKEND: JVM, JS, JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 // IGNORE_LIGHT_ANALYSIS
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IGNORED_IN_JS
 
 import helpers.*
 import kotlin.coroutines.*
diff --git a/compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt b/compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt
index 966652c..ccc9968 100644
--- a/compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt
+++ b/compiler/testData/codegen/box/coroutines/suspendConversion/subtypeOfFunctionalTypeToSuspendConversion.kt
@@ -4,8 +4,6 @@
 // IGNORE_BACKEND: JVM, JS, JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 // IGNORE_LIGHT_ANALYSIS
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IGNORED_IN_JS
 
 import helpers.*
 import kotlin.coroutines.*
diff --git a/compiler/testData/codegen/box/extensionFunctions/extensionFunctionAsSupertype.kt b/compiler/testData/codegen/box/extensionFunctions/extensionFunctionAsSupertype.kt
index 72e5f37..9fb4bb9 100644
--- a/compiler/testData/codegen/box/extensionFunctions/extensionFunctionAsSupertype.kt
+++ b/compiler/testData/codegen/box/extensionFunctions/extensionFunctionAsSupertype.kt
@@ -1,5 +1,5 @@
 // !LANGUAGE: +FunctionalTypeWithExtensionAsSupertype
-// IGNORE_BACKEND: JS, JS_IR, WASM
+// IGNORE_BACKEND: JS, JS_IR
 
 interface I: (String) -> String
 
diff --git a/compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt b/compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt
index ceac246..3d5c955 100644
--- a/compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt
+++ b/compiler/testData/codegen/box/funInterface/intersectionTypeToFunInterfaceConversion.kt
@@ -1,5 +1,3 @@
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IGNORED_IN_JS
 // IGNORE_BACKEND: JS, JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 
diff --git a/compiler/testData/codegen/box/funInterface/kt46908_functionSupertype.kt b/compiler/testData/codegen/box/funInterface/kt46908_functionSupertype.kt
index 7790259..dcf948e 100644
--- a/compiler/testData/codegen/box/funInterface/kt46908_functionSupertype.kt
+++ b/compiler/testData/codegen/box/funInterface/kt46908_functionSupertype.kt
@@ -1,4 +1,4 @@
-// IGNORE_BACKEND: JS, JS_IR, WASM
+// IGNORE_BACKEND: JS, JS_IR
 
 fun interface Foo : () -> Int
 
diff --git a/compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt b/compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt
index 5084a208..95339eb 100644
--- a/compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt
+++ b/compiler/testData/codegen/box/funInterface/subtypeOfFunctionalTypeToFunInterfaceConversion.kt
@@ -1,5 +1,3 @@
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IGNORED_IN_JS
 // IGNORE_BACKEND: JS, JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 
diff --git a/compiler/testData/codegen/box/functions/bigArity/subclass.kt b/compiler/testData/codegen/box/functions/bigArity/subclass.kt
index 86f7537..98af6b6 100644
--- a/compiler/testData/codegen/box/functions/bigArity/subclass.kt
+++ b/compiler/testData/codegen/box/functions/bigArity/subclass.kt
@@ -1,5 +1,3 @@
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IGNORED_IN_JS
 // !LANGUAGE: +FunctionTypesWithBigArity
 
 // Implementing function interface is prohibited in JavaScript
diff --git a/compiler/testData/codegen/box/functions/invoke/kt3190.kt b/compiler/testData/codegen/box/functions/invoke/kt3190.kt
index ade3888..4786050 100644
--- a/compiler/testData/codegen/box/functions/invoke/kt3190.kt
+++ b/compiler/testData/codegen/box/functions/invoke/kt3190.kt
@@ -1,5 +1,3 @@
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IGNORED_IN_JS
 // IGNORE_BACKEND: JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 //KT-3190 Compiler crash if function called 'invoke' calls a closure
diff --git a/compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt b/compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt
index 8e561ee..5279ca2 100644
--- a/compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt
+++ b/compiler/testData/codegen/box/functions/invoke/kt3822invokeOnThis.kt
@@ -1,5 +1,3 @@
-// IGNORE_BACKEND: WASM
-// WASM_MUTE_REASON: IMPLEMENTING_FUNCTION_INTERFACE
 // IGNORE_BACKEND: JS_IR
 // IGNORE_BACKEND: JS_IR_ES6
 //KT-3822 Compiler crashes when use invoke convention with `this` in class which extends Function0<T>
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CompilerTestLanguageVersionSettings.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CompilerTestLanguageVersionSettings.kt
index e6e234d..c420549 100644
--- a/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CompilerTestLanguageVersionSettings.kt
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/checkers/CompilerTestLanguageVersionSettings.kt
@@ -53,7 +53,11 @@
 fun parseLanguageVersionSettingsOrDefault(directiveMap: Directives): CompilerTestLanguageVersionSettings =
     parseLanguageVersionSettings(directiveMap) ?: defaultLanguageVersionSettings()
 
-fun parseLanguageVersionSettings(directives: Directives): CompilerTestLanguageVersionSettings? {
+@JvmOverloads
+fun parseLanguageVersionSettings(
+    directives: Directives,
+    extraLanguageFeatures: Map<LanguageFeature, LanguageFeature.State> = emptyMap()
+): CompilerTestLanguageVersionSettings? {
     val apiVersionString = directives[API_VERSION_DIRECTIVE]
     val languageFeaturesString = directives[LANGUAGE_DIRECTIVE]
 
@@ -81,7 +85,7 @@
 
     val languageVersion = maxOf(LanguageVersion.LATEST_STABLE, LanguageVersion.fromVersionString(apiVersion.versionString)!!)
 
-    val languageFeatures = languageFeaturesString?.let(::collectLanguageFeatureMap).orEmpty()
+    val languageFeatures = languageFeaturesString?.let(::collectLanguageFeatureMap).orEmpty() + extraLanguageFeatures
 
     return CompilerTestLanguageVersionSettings(languageFeatures, apiVersion, languageVersion, mapOf(*analysisFlags.toTypedArray()))
 }
diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
index a5cfce4..4877766 100644
--- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
+++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt
@@ -315,6 +315,7 @@
     ValueClasses(sinceVersion = null, kind = UNSTABLE_FEATURE),
     JavaSamConversionEqualsHashCode(sinceVersion = null, kind = UNSTABLE_FEATURE),
     UnitConversionsOnArbitraryExpressions(sinceVersion = null),
+    JsAllowImplementingFunctionInterface(sinceVersion = null, kind = UNSTABLE_FEATURE),
     ;
 
     init {
diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsInheritanceChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsInheritanceChecker.kt
index 927ac3c..a3e48c4 100644
--- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsInheritanceChecker.kt
+++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsInheritanceChecker.kt
@@ -18,6 +18,7 @@
 
 import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
 import org.jetbrains.kotlin.builtins.isSuspendFunctionTypeOrSubtype
+import org.jetbrains.kotlin.config.LanguageFeature
 import org.jetbrains.kotlin.descriptors.ClassDescriptor
 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
 import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -44,10 +45,12 @@
             }
         }
 
-        if (descriptor is ClassDescriptor &&
-            descriptor.defaultType.immediateSupertypes().any { it.isBuiltinFunctionalTypeOrSubtype && !it.isSuspendFunctionTypeOrSubtype }
-        ) {
-            context.trace.report(ErrorsJs.IMPLEMENTING_FUNCTION_INTERFACE.on(declaration as KtClassOrObject))
+        if (!context.languageVersionSettings.supportsFeature(LanguageFeature.JsAllowImplementingFunctionInterface)) {
+            if (descriptor is ClassDescriptor &&
+                descriptor.defaultType.immediateSupertypes().any { it.isBuiltinFunctionalTypeOrSubtype && !it.isSuspendFunctionTypeOrSubtype }
+            ) {
+                context.trace.report(ErrorsJs.IMPLEMENTING_FUNCTION_INTERFACE.on(declaration as KtClassOrObject))
+            }
         }
     }
 
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt
index 0a8e5c9..1085e99 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt
@@ -48,6 +48,10 @@
 
     private val COMMON_FILES_NAME = "_common"
 
+    private val extraLanguageFeatures = mapOf(
+        LanguageFeature.JsAllowImplementingFunctionInterface to LanguageFeature.State.ENABLED,
+    )
+
     fun doTest(filePath: String) = doTestWithTransformer(filePath) { it }
     fun doTestWithTransformer(filePath: String, transformer: java.util.function.Function<String, String>) {
         val file = File(filePath)
@@ -244,7 +248,7 @@
         configuration.put(JSConfigurationKeys.WASM_ENABLE_ARRAY_RANGE_CHECKS, true)
         configuration.put(JSConfigurationKeys.WASM_ENABLE_ASSERTS, true)
         configuration.languageVersionSettings = languageVersionSettings
-            ?: LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE)
+            ?: LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, specificFeatures = extraLanguageFeatures)
         return JsConfig(project, configuration, CompilerEnvironment, null, null)
     }
 
@@ -259,7 +263,7 @@
                 }
             }
 
-            val languageVersionSettings = parseLanguageVersionSettings(directives)
+            val languageVersionSettings = parseLanguageVersionSettings(directives, extraLanguageFeatures)
 
             val temporaryFile = File(tmpDir, "WASM_TEST/$fileName")
             KtTestUtil.mkdirs(temporaryFile.parentFile)