[K/Wasm] Fix Promise API compatibility


Merge-request: KT-MR-22764
Merged-by: Artem Kobzar <Artem.Kobzar@jetbrains.com>
diff --git a/compiler/testData/codegen/box/size/add.kt b/compiler/testData/codegen/box/size/add.kt
index 63cf5d1..3b137f1 100644
--- a/compiler/testData/codegen/box/size/add.kt
+++ b/compiler/testData/codegen/box/size/add.kt
@@ -2,7 +2,7 @@
 
 // RUN_THIRD_PARTY_OPTIMIZER
 // WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm  54_055
-// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs    5_865
+// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs    5_955
 // WASM_OPT_EXPECTED_OUTPUT_SIZE:           76
 
 // FILE: test.kt
diff --git a/compiler/testData/codegen/box/size/helloWorld.kt b/compiler/testData/codegen/box/size/helloWorld.kt
index 035c09a..57d7596 100644
--- a/compiler/testData/codegen/box/size/helloWorld.kt
+++ b/compiler/testData/codegen/box/size/helloWorld.kt
@@ -2,8 +2,8 @@
 
 // RUN_THIRD_PARTY_OPTIMIZER
 // WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm  54_371
-// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs    5_831
-// WASM_OPT_EXPECTED_OUTPUT_SIZE:        6_270
+// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs    5_890
+// WASM_OPT_EXPECTED_OUTPUT_SIZE:        6_353
 
 fun box(): String {
     println("Hello, World!")
diff --git a/compiler/testData/codegen/box/size/helloWorldPromise.kt b/compiler/testData/codegen/box/size/helloWorldPromise.kt
index b049932..dcb9d16 100644
--- a/compiler/testData/codegen/box/size/helloWorldPromise.kt
+++ b/compiler/testData/codegen/box/size/helloWorldPromise.kt
@@ -3,7 +3,7 @@
 // RUN_THIRD_PARTY_OPTIMIZER
 // WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 54_474
 // WASM_DCE_EXPECTED_OUTPUT_SIZE:  mjs  6_067
-// WASM_OPT_EXPECTED_OUTPUT_SIZE:       6_465
+// WASM_OPT_EXPECTED_OUTPUT_SIZE:       6_548
 
 // FILE: test.kt
 
diff --git a/compiler/testData/codegen/box/size/objectsOptimization.kt b/compiler/testData/codegen/box/size/objectsOptimization.kt
index 3c5650d..43d2703 100644
--- a/compiler/testData/codegen/box/size/objectsOptimization.kt
+++ b/compiler/testData/codegen/box/size/objectsOptimization.kt
@@ -2,8 +2,8 @@
 
 // RUN_THIRD_PARTY_OPTIMIZER
 // WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 58_966
-// WASM_DCE_EXPECTED_OUTPUT_SIZE:  mjs  5_762
-// WASM_OPT_EXPECTED_OUTPUT_SIZE:       7_654
+// WASM_DCE_EXPECTED_OUTPUT_SIZE:  mjs  5_821
+// WASM_OPT_EXPECTED_OUTPUT_SIZE:       7_737
 
 object Simple
 
diff --git a/compiler/testData/codegen/box/size/ok.kt b/compiler/testData/codegen/box/size/ok.kt
index b2c2373..d87f872 100644
--- a/compiler/testData/codegen/box/size/ok.kt
+++ b/compiler/testData/codegen/box/size/ok.kt
@@ -2,7 +2,7 @@
 
 // RUN_THIRD_PARTY_OPTIMIZER
 // WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 54_104
-// WASM_DCE_EXPECTED_OUTPUT_SIZE:  mjs  5_762
-// WASM_OPT_EXPECTED_OUTPUT_SIZE:       6_174
+// WASM_DCE_EXPECTED_OUTPUT_SIZE:  mjs  5_821
+// WASM_OPT_EXPECTED_OUTPUT_SIZE:       6_257
 
 fun box() = "OK"
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/size/removeUnusedOverride.kt b/compiler/testData/codegen/box/size/removeUnusedOverride.kt
index 513fbb6..debacb5 100644
--- a/compiler/testData/codegen/box/size/removeUnusedOverride.kt
+++ b/compiler/testData/codegen/box/size/removeUnusedOverride.kt
@@ -3,8 +3,8 @@
 
 // RUN_THIRD_PARTY_OPTIMIZER
 // WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm  54_786
-// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs    5_762
-// WASM_OPT_EXPECTED_OUTPUT_SIZE:        6_178
+// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs    5_821
+// WASM_OPT_EXPECTED_OUTPUT_SIZE:        6_261
 
 interface I {
     fun foo() = "OK"
diff --git a/libraries/stdlib/common-js-wasmjs/src/kotlin/js/JsError.kt b/libraries/stdlib/common-js-wasmjs/src/kotlin/js/JsError.kt
deleted file mode 100644
index 2c6c1a8..0000000
--- a/libraries/stdlib/common-js-wasmjs/src/kotlin/js/JsError.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright 2010-2025 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 kotlin.js
-
-@ExperimentalWasmJsInterop
-@SinceKotlin("2.2")
-public expect class JsError : JsAny
diff --git a/libraries/stdlib/common-js-wasmjs/src/kotlin/js/JsPromiseError.kt b/libraries/stdlib/common-js-wasmjs/src/kotlin/js/JsPromiseError.kt
new file mode 100644
index 0000000..ce47312
--- /dev/null
+++ b/libraries/stdlib/common-js-wasmjs/src/kotlin/js/JsPromiseError.kt
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2010-2025 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 kotlin.js
+
+@ExperimentalWasmJsInterop
+@SinceKotlin("2.2")
+@Suppress("EXPECT_ACTUAL_IR_INCOMPATIBILITY")
+public expect class JsPromiseError : JsAny
+
+@ExperimentalWasmJsInterop
+@SinceKotlin("2.2")
+public expect fun JsPromiseError.asJsException(): JsException
diff --git a/libraries/stdlib/common-js-wasmjs/src/kotlin/js/Promise.kt b/libraries/stdlib/common-js-wasmjs/src/kotlin/js/Promise.kt
index b31f166..8a406cc 100644
--- a/libraries/stdlib/common-js-wasmjs/src/kotlin/js/Promise.kt
+++ b/libraries/stdlib/common-js-wasmjs/src/kotlin/js/Promise.kt
@@ -12,20 +12,20 @@
  */
 @ExperimentalWasmJsInterop
 @SinceKotlin("2.2")
-public expect class Promise<out T : JsAny?>(executor: (resolve: (T) -> Unit, reject: (JsError) -> Unit) -> Unit): JsAny {
+public expect class Promise<out T : JsAny?>(executor: (resolve: (T) -> Unit, reject: (JsPromiseError) -> Unit) -> Unit): JsAny {
     @LowPriorityInOverloadResolution
     public fun <S : JsAny?> then(onFulfilled: ((T) -> S)?): Promise<S>
 
     @LowPriorityInOverloadResolution
-    public fun <S : JsAny?> then(onFulfilled: ((T) -> S)?, onRejected: ((JsError) -> S)?): Promise<S>
+    public fun <S : JsAny?> then(onFulfilled: ((T) -> S)?, onRejected: ((JsPromiseError) -> S)?): Promise<S>
 
-    public fun <S : JsAny?> catch(onRejected: (JsError) -> S): Promise<S>
+    public fun <S : JsAny?> catch(onRejected: (JsPromiseError) -> S): Promise<S>
     public fun finally(onFinally: () -> Unit): Promise<T>
 
     public companion object {
         public fun <S : JsAny?> all(promise: JsArray<out Promise<S>>): Promise<JsArray<out S>>
         public fun <S : JsAny?> race(promise: JsArray<out Promise<S>>): Promise<S>
-        public fun reject(e: JsError): Promise<Nothing>
+        public fun reject(e: JsPromiseError): Promise<Nothing>
         public fun <S : JsAny?> resolve(e: S): Promise<S>
         public fun <S : JsAny?> resolve(e: Promise<S>): Promise<S>
     }
diff --git a/libraries/stdlib/js/src/kotlin/wasmJs/JsError.kt b/libraries/stdlib/js/src/kotlin/wasmJs/JsError.kt
deleted file mode 100644
index 2b76171..0000000
--- a/libraries/stdlib/js/src/kotlin/wasmJs/JsError.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright 2010-2025 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 kotlin.js
-
-@SinceKotlin("2.2")
-@ExperimentalWasmJsInterop
-public actual typealias JsError = Throwable
-
diff --git a/libraries/stdlib/js/src/kotlin/wasmJs/JsPromiseError.kt b/libraries/stdlib/js/src/kotlin/wasmJs/JsPromiseError.kt
new file mode 100644
index 0000000..aaaffdc
--- /dev/null
+++ b/libraries/stdlib/js/src/kotlin/wasmJs/JsPromiseError.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2010-2025 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 kotlin.js
+
+import kotlin.internal.InlineOnly
+
+@SinceKotlin("2.2")
+@ExperimentalWasmJsInterop
+public actual typealias JsPromiseError = Throwable
+
+@InlineOnly
+@ExperimentalWasmJsInterop
+@SinceKotlin("2.2")
+public actual inline fun JsPromiseError.asJsException(): Throwable = this
diff --git a/libraries/stdlib/wasm/js/src/kotlin/js/JsError.kt b/libraries/stdlib/wasm/js/src/kotlin/js/JsError.kt
deleted file mode 100644
index 6be0819..0000000
--- a/libraries/stdlib/wasm/js/src/kotlin/js/JsError.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2010-2025 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 kotlin.js
-
-import kotlin.wasm.internal.ExternalInterfaceType
-
-@SinceKotlin("2.2")
-@JsName("Error")
-@ExperimentalWasmJsInterop
-public actual external class JsError : JsAny {
-    internal val message: String
-    internal var name: String
-    internal val stack: ExternalInterfaceType
-    internal val cause: JsError?
-    internal var kotlinException: JsReference<Throwable>?
-}
-
diff --git a/libraries/stdlib/wasm/js/src/kotlin/js/JsException.kt b/libraries/stdlib/wasm/js/src/kotlin/js/JsException.kt
index fedd561..67501ba 100644
--- a/libraries/stdlib/wasm/js/src/kotlin/js/JsException.kt
+++ b/libraries/stdlib/wasm/js/src/kotlin/js/JsException.kt
@@ -43,3 +43,13 @@
 
 @ExperimentalWasmJsInterop
 public actual val JsException.thrownValue: JsAny? get() = this.thrownValue
+
+@OptIn(ExperimentalWasmJsInterop::class)
+@JsName("Error")
+internal external class JsError : JsAny {
+    val message: String
+    var name: String
+    val stack: ExternalInterfaceType
+    val cause: JsError?
+    var kotlinException: JsReference<Throwable>?
+}
\ No newline at end of file
diff --git a/libraries/stdlib/wasm/js/src/kotlin/js/JsPromiseError.kt b/libraries/stdlib/wasm/js/src/kotlin/js/JsPromiseError.kt
new file mode 100644
index 0000000..a92e2d6
--- /dev/null
+++ b/libraries/stdlib/wasm/js/src/kotlin/js/JsPromiseError.kt
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2010-2025 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.
+ */
+@file:Suppress("EXPECT_ACTUAL_INCOMPATIBLE_CLASS_KIND", "EXPECT_ACTUAL_INCOMPATIBLE_SUPERTYPES")
+package kotlin.js
+
+@SinceKotlin("2.2")
+@ExperimentalWasmJsInterop
+public actual typealias JsPromiseError = JsAny
+
+@ExperimentalWasmJsInterop
+@SinceKotlin("2.2")
+public actual fun JsPromiseError.asJsException(): JsException =
+    JsException(this)
diff --git a/libraries/stdlib/wasm/js/src/kotlin/js/Promise.kt b/libraries/stdlib/wasm/js/src/kotlin/js/Promise.kt
index 5c56e9c..4f483f4 100644
--- a/libraries/stdlib/wasm/js/src/kotlin/js/Promise.kt
+++ b/libraries/stdlib/wasm/js/src/kotlin/js/Promise.kt
@@ -2,7 +2,7 @@
  * Copyright 2010-2022 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.
  */
-
+@file:Suppress("EXPECT_ACTUAL_INCOMPATIBLE_VISIBILITY")
 package kotlin.js
 
 import kotlin.internal.LowPriorityInOverloadResolution
@@ -12,27 +12,15 @@
  */
 @ExperimentalWasmJsInterop
 public actual external class Promise<out T : JsAny?>
-@SinceKotlin("2.2")
-@LowPriorityInOverloadResolution
-actual constructor(executor: (resolve: (T) -> Unit, reject: (JsError) -> Unit) -> Unit) : JsAny {
-
-    public constructor(executor: (resolve: (T) -> Unit, reject: (JsAny) -> Unit) -> Unit)
+actual constructor(executor: (resolve: (T) -> Unit, reject: (JsAny) -> Unit) -> Unit) : JsAny {
 
     @LowPriorityInOverloadResolution
     public actual fun <S : JsAny?> then(onFulfilled: ((T) -> S)?): Promise<S>
 
-    @SinceKotlin("2.2")
     @LowPriorityInOverloadResolution
-    public actual fun <S : JsAny?> then(onFulfilled: ((T) -> S)?, onRejected: ((JsError) -> S)?): Promise<S>
+    public actual fun <S : JsAny?> then(onFulfilled: ((T) -> S)?, onRejected: ((JsAny) -> S)?): Promise<S>
 
-    @LowPriorityInOverloadResolution
-    public fun <S : JsAny?> then(onFulfilled: ((T) -> S)?, onRejected: ((JsAny) -> S)?): Promise<S>
-
-    @SinceKotlin("2.2")
-    @LowPriorityInOverloadResolution
-    public actual fun <S : JsAny?> catch(onRejected: (JsError) -> S): Promise<S>
-
-    public fun <S : JsAny?> catch(onRejected: (JsAny) -> S): Promise<S>
+    public actual fun <S : JsAny?> catch(onRejected: (JsAny) -> S): Promise<S>
 
     public actual fun finally(onFinally: () -> Unit): Promise<T>
 
@@ -40,10 +28,7 @@
         public actual fun <S : JsAny?> all(promise: JsArray<out Promise<S>>): Promise<JsArray<out S>>
         public actual fun <S : JsAny?> race(promise: JsArray<out Promise<S>>): Promise<S>
 
-        @SinceKotlin("2.2")
-        @LowPriorityInOverloadResolution
-        public actual fun reject(e: JsError): Promise<Nothing>
-        public fun reject(e: JsAny): Promise<Nothing>
+        public actual fun reject(e: JsAny): Promise<Nothing>
 
         public actual fun <S : JsAny?> resolve(e: S): Promise<S>
         public actual fun <S : JsAny?> resolve(e: Promise<S>): Promise<S>
diff --git a/libraries/tools/binary-compatibility-validator/klib-public-api/kotlin-stdlib.api b/libraries/tools/binary-compatibility-validator/klib-public-api/kotlin-stdlib.api
index 1390ae1..04d3d1d 100644
--- a/libraries/tools/binary-compatibility-validator/klib-public-api/kotlin-stdlib.api
+++ b/libraries/tools/binary-compatibility-validator/klib-public-api/kotlin-stdlib.api
@@ -15139,6 +15139,9 @@
 final inline fun (kotlin/String).kotlin.text/uppercase(): kotlin/String // kotlin.text/uppercase|uppercase@kotlin.String(){}[0]
 
 // Targets: [js]
+final inline fun (kotlin/Throwable).kotlin.js/asJsException(): kotlin/Throwable // kotlin.js/asJsException|asJsException@kotlin.Throwable(){}[0]
+
+// Targets: [js]
 final inline fun /withType(kotlin/String, dynamic): dynamic // /withType|withType(kotlin.String;<dynamic>){}[0]
 
 // Targets: [js]
@@ -15470,13 +15473,10 @@
 // Targets: [wasmJs]
 final class <#A: out kotlin.js/JsAny?> kotlin.js/Promise : kotlin.js/JsAny { // kotlin.js/Promise|null[0]
     constructor <init>(kotlin/Function2<kotlin/Function1<#A, kotlin/Unit>, kotlin/Function1<kotlin.js/JsAny, kotlin/Unit>, kotlin/Unit>) // kotlin.js/Promise.<init>|<init>(kotlin.Function2<kotlin.Function1<1:0,kotlin.Unit>,kotlin.Function1<kotlin.js.JsAny,kotlin.Unit>,kotlin.Unit>){}[0]
-    constructor <init>(kotlin/Function2<kotlin/Function1<#A, kotlin/Unit>, kotlin/Function1<kotlin.js/JsError, kotlin/Unit>, kotlin/Unit>) // kotlin.js/Promise.<init>|<init>(kotlin.Function2<kotlin.Function1<1:0,kotlin.Unit>,kotlin.Function1<kotlin.js.JsError,kotlin.Unit>,kotlin.Unit>){}[0]
 
     final fun <#A1: kotlin.js/JsAny?> catch(kotlin/Function1<kotlin.js/JsAny, #A1>): kotlin.js/Promise<#A1> // kotlin.js/Promise.catch|catch(kotlin.Function1<kotlin.js.JsAny,0:0>){0§<kotlin.js.JsAny?>}[0]
-    final fun <#A1: kotlin.js/JsAny?> catch(kotlin/Function1<kotlin.js/JsError, #A1>): kotlin.js/Promise<#A1> // kotlin.js/Promise.catch|catch(kotlin.Function1<kotlin.js.JsError,0:0>){0§<kotlin.js.JsAny?>}[0]
     final fun <#A1: kotlin.js/JsAny?> then(kotlin/Function1<#A, #A1>?): kotlin.js/Promise<#A1> // kotlin.js/Promise.then|then(kotlin.Function1<1:0,0:0>?){0§<kotlin.js.JsAny?>}[0]
     final fun <#A1: kotlin.js/JsAny?> then(kotlin/Function1<#A, #A1>?, kotlin/Function1<kotlin.js/JsAny, #A1>?): kotlin.js/Promise<#A1> // kotlin.js/Promise.then|then(kotlin.Function1<1:0,0:0>?;kotlin.Function1<kotlin.js.JsAny,0:0>?){0§<kotlin.js.JsAny?>}[0]
-    final fun <#A1: kotlin.js/JsAny?> then(kotlin/Function1<#A, #A1>?, kotlin/Function1<kotlin.js/JsError, #A1>?): kotlin.js/Promise<#A1> // kotlin.js/Promise.then|then(kotlin.Function1<1:0,0:0>?;kotlin.Function1<kotlin.js.JsError,0:0>?){0§<kotlin.js.JsAny?>}[0]
     final fun finally(kotlin/Function0<kotlin/Unit>): kotlin.js/Promise<#A> // kotlin.js/Promise.finally|finally(kotlin.Function0<kotlin.Unit>){}[0]
 
     final object Companion { // kotlin.js/Promise.Companion|null[0]
@@ -15485,7 +15485,6 @@
         final fun <#A2: kotlin.js/JsAny?> resolve(#A2): kotlin.js/Promise<#A2> // kotlin.js/Promise.Companion.resolve|resolve(0:0){0§<kotlin.js.JsAny?>}[0]
         final fun <#A2: kotlin.js/JsAny?> resolve(kotlin.js/Promise<#A2>): kotlin.js/Promise<#A2> // kotlin.js/Promise.Companion.resolve|resolve(kotlin.js.Promise<0:0>){0§<kotlin.js.JsAny?>}[0]
         final fun reject(kotlin.js/JsAny): kotlin.js/Promise<kotlin/Nothing> // kotlin.js/Promise.Companion.reject|reject(kotlin.js.JsAny){}[0]
-        final fun reject(kotlin.js/JsError): kotlin.js/Promise<kotlin/Nothing> // kotlin.js/Promise.Companion.reject|reject(kotlin.js.JsError){}[0]
     }
 }
 
@@ -15496,11 +15495,6 @@
 final class kotlin.js/JsBoolean : kotlin.js/JsAny // kotlin.js/JsBoolean|null[0]
 
 // Targets: [wasmJs]
-final class kotlin.js/JsError : kotlin.js/JsAny { // kotlin.js/JsError|null[0]
-    constructor <init>() // kotlin.js/JsError.<init>|<init>(){}[0]
-}
-
-// Targets: [wasmJs]
 final class kotlin.js/JsException : kotlin/Throwable { // kotlin.js/JsException|null[0]
     final val message // kotlin.js/JsException.message|{}message[0]
         final fun <get-message>(): kotlin/String? // kotlin.js/JsException.message.<get-message>|<get-message>(){}[0]
@@ -15523,6 +15517,9 @@
     final fun (kotlin.js/JsException).<get-thrownValue>(): kotlin.js/JsAny? // kotlin.js/thrownValue.<get-thrownValue>|<get-thrownValue>@kotlin.js.JsException(){}[0]
 
 // Targets: [wasmJs]
+final fun (kotlin.js/JsAny).kotlin.js/asJsException(): kotlin.js/JsException // kotlin.js/asJsException|asJsException@kotlin.js.JsAny(){}[0]
+
+// Targets: [wasmJs]
 final fun (kotlin.js/JsAny).kotlin.js/toThrowableOrNull(): kotlin/Throwable? // kotlin.js/toThrowableOrNull|toThrowableOrNull@kotlin.js.JsAny(){}[0]
 
 // Targets: [wasmJs]