[Wasm] Disallow js(code) inside function block body
diff --git a/compiler/testData/codegen/boxWasmJsInterop/kotlinToJsAdapters.kt b/compiler/testData/codegen/boxWasmJsInterop/kotlinToJsAdapters.kt
index dfdd3bf..d63ebe6 100644
--- a/compiler/testData/codegen/boxWasmJsInterop/kotlinToJsAdapters.kt
+++ b/compiler/testData/codegen/boxWasmJsInterop/kotlinToJsAdapters.kt
@@ -1,14 +1,11 @@
-fun notNullString(x: String) {
- js("if (x !== 'abc') throw 'error'")
-}
+fun notNullString(x: String): Unit =
+ js("{ if (x !== 'abc') throw 'error' }")
-fun nullString(x: String?) {
- js("if (x !== 'abc') throw 'error'")
-}
+fun nullString(x: String?): Unit =
+ js("{ if (x !== 'abc') throw 'error' }")
-fun null2String(x: String?) {
- js("if (x !== null) throw 'error'")
-}
+fun null2String(x: String?): Unit =
+ js("{ if (x !== null) throw 'error' }")
fun testString() {
notNullString("abc")
@@ -18,17 +15,14 @@
external interface ExternRef
-fun notNullExternRef(x: ExternRef) {
- js("if (x !== 'abc') throw 'error'")
-}
+fun notNullExternRef(x: ExternRef): Unit =
+ js("{ if (x !== 'abc') throw 'error' }")
-fun nullExternRef(x: ExternRef?) {
- js("if (x !== 'abc') throw 'error'")
-}
+fun nullExternRef(x: ExternRef?): Unit =
+ js("{ if (x !== 'abc') throw 'error' }")
-fun null2ExternRef(x: ExternRef?) {
- js("if (x !== null) throw 'error'")
-}
+fun null2ExternRef(x: ExternRef?): Unit =
+ js("{ if (x !== null) throw 'error' }")
fun getExternRef(): ExternRef =
js("'abc'")
@@ -40,17 +34,14 @@
null2ExternRef(null)
}
-fun notNullInt(x: Int) {
- js("if (x !== 123) throw 'error'")
-}
+fun notNullInt(x: Int): Unit =
+ js("{ if (x !== 123) throw 'error' }")
-fun nullInt(x: Int?) {
- js("if (x !== 123) throw 'error'")
-}
+fun nullInt(x: Int?): Unit =
+ js("{ if (x !== 123) throw 'error' }")
-fun null2Int(x: Int?) {
- js("if (x !== null) throw 'error'")
-}
+fun null2Int(x: Int?): Unit =
+ js("{ if (x !== null) throw 'error' }")
fun testInt() {
notNullInt(123)
@@ -58,17 +49,14 @@
null2Int(null)
}
-fun notNullBoolean(x: Boolean) {
- js("if (x !== true) throw 'error'")
-}
+fun notNullBoolean(x: Boolean): Unit =
+ js("{ if (x !== true) throw 'error' }")
-fun nullBoolean(x: Boolean?) {
- js("if (x !== true) throw 'error'")
-}
+fun nullBoolean(x: Boolean?): Unit =
+ js("{ if (x !== true) throw 'error' }")
-fun null2Boolean(x: Boolean?) {
- js("if (x !== null) throw 'error'")
-}
+fun null2Boolean(x: Boolean?): Unit =
+ js("{ if (x !== null) throw 'error' }")
fun testBoolean() {
notNullBoolean(true)
@@ -76,17 +64,14 @@
null2Boolean(null)
}
-fun notNullShort(x: Short) {
- js("x == 123")
-}
+fun notNullShort(x: Short): Unit =
+ js("{ x == 123 }")
-fun nullShort(x: Short?) {
- js("if (x !== 123) throw 'error'")
-}
+fun nullShort(x: Short?): Unit =
+ js("{ if (x !== 123) throw 'error' }")
-fun null2Short(x: Short?) {
- js("if (x !== null) throw 'error'")
-}
+fun null2Short(x: Short?): Unit =
+ js("{ if (x !== null) throw 'error' }")
fun testShort() {
notNullShort(123.toShort())
@@ -94,17 +79,14 @@
null2Short(null)
}
-fun notNullFloat(x: Float) {
- js("if (x !== 123.5) throw 'error'")
-}
+fun notNullFloat(x: Float): Unit =
+ js("{ if (x !== 123.5) throw 'error' }")
-fun nullFloat(x: Float?) {
- js("if (x !== 123.5) throw 'error'")
-}
+fun nullFloat(x: Float?): Unit =
+ js("{ if (x !== 123.5) throw 'error' }")
-fun null2Float(x: Float?) {
- js("if (x !== null) throw 'error'")
-}
+fun null2Float(x: Float?): Unit =
+ js("{ if (x !== null) throw 'error' }")
fun testFloat() {
notNullFloat(123.5f)
diff --git a/compiler/testData/diagnostics/wasmTests/jsInterop/jsCode.kt b/compiler/testData/diagnostics/wasmTests/jsInterop/jsCode.kt
index 353f592..211a0ad 100644
--- a/compiler/testData/diagnostics/wasmTests/jsInterop/jsCode.kt
+++ b/compiler/testData/diagnostics/wasmTests/jsInterop/jsCode.kt
@@ -4,8 +4,8 @@
fun funExprBody(x: Int): Int =
js("x")
-fun funBlockBody(x: Int): Int {
- js("return x;")
+fun funBlockBody(<!UNUSED_PARAMETER!>x<!>: Int): Int {
+ <!JSCODE_WRONG_CONTEXT!>js<!>("return x;")
}
fun <!IMPLICIT_NOTHING_RETURN_TYPE!>returnTypeNotSepcified<!>() = js("1")
diff --git a/compiler/testData/diagnostics/wasmTests/jsInterop/types.kt b/compiler/testData/diagnostics/wasmTests/jsInterop/types.kt
index 9e27705..e9f421a 100644
--- a/compiler/testData/diagnostics/wasmTests/jsInterop/types.kt
+++ b/compiler/testData/diagnostics/wasmTests/jsInterop/types.kt
@@ -95,9 +95,6 @@
): T3
<!WRONG_JS_INTEROP_TYPE!>fun jsCode1(<!WRONG_JS_INTEROP_TYPE!>x: Any<!>): Any<!> = js("x")
-<!WRONG_JS_INTEROP_TYPE!>fun jsCode2(<!WRONG_JS_INTEROP_TYPE!>x: Any<!>): Any<!> {
- js("return x;")
-}
<!WRONG_JS_INTEROP_TYPE!>val jsProp: Any<!> = js("1")
<!WRONG_JS_INTEROP_TYPE!>@JsExport
diff --git a/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/JasmineLikeAdapter.kt b/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/JasmineLikeAdapter.kt
index 2232433..3b08e11 100644
--- a/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/JasmineLikeAdapter.kt
+++ b/libraries/kotlin.test/wasm/src/main/kotlin/kotlin/test/JasmineLikeAdapter.kt
@@ -21,13 +21,11 @@
private fun xit(name: String, fn: () -> JsAny?): Unit =
js("xit(name, fn)")
-private fun jsThrow(jsException: JsAny) {
- js("throw e")
-}
+private fun jsThrow(jsException: JsAny): Nothing =
+ js("{ throw e; }")
-private fun throwableToJsError(message: String, stack: String): JsAny {
- js("var e = new Error(); e.message = message; e.stack = stack; return e;")
-}
+private fun throwableToJsError(message: String, stack: String): JsAny =
+ js("{ var e = new Error(); e.message = message; e.stack = stack; return e; }")
private fun Throwable.toJsError(): JsAny =
throwableToJsError(message ?: "", stackTraceToString())
@@ -70,4 +68,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/libraries/stdlib/wasm/src/kotlin/js/core.kt b/libraries/stdlib/wasm/src/kotlin/js/core.kt
index 78a2a7d..0eceec5 100644
--- a/libraries/stdlib/wasm/src/kotlin/js/core.kt
+++ b/libraries/stdlib/wasm/src/kotlin/js/core.kt
@@ -42,26 +42,22 @@
* It is used to implement top-level functions and initialize top-level properties.
*
* It is important to note, that calls to [js] function should be the only expression
- * in a function body or a property initializer.
+ * in a function expression body or a property initializer.
*
* [code] parameter should be a compile-time constant.
*
- * When used in an expression context, [code] should contain a single JavaScript expression. For example:
+ * [code] should contain a single JavaScript expression or a block of JavaScript statements
+ * enclosed in curly brackets. For example:
*
* ``` kotlin
* val version: String = js("process.version")
+ *
* fun newEmptyJsArray(): JsValue = js("[]")
- * ```
*
- * When used in a function body, [code] is expected to be a list of JavaScript statements. For example:
- *
- * ``` kotlin
- * fun log(message1: String, message2: String) {
- * js("""
+ * fun log(message1: String, message2: String): Unit = js("""{
* console.log(message1);
* console.log(message2);
- * """)
- * }
+ * }""")
* ```
*
* You can use parameters of calling function in JavaScript [code].
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 79a25d2..51112f4 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
@@ -36,7 +36,7 @@
put(
ErrorsWasm.JSCODE_WRONG_CONTEXT,
- "Calls to js(code) should be a single expression inside a top-level function body or a property initializer in Kotlin/Wasm"
+ "Calls to js(code) should be a single expression inside a top-level function expression body or a property initializer in Kotlin/Wasm"
)
put(
ErrorsWasm.JSCODE_UNSUPPORTED_FUNCTION_KIND,
diff --git a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/util/jsCodeUtils.kt b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/util/jsCodeUtils.kt
index 4c2c4da..2d1cfa4 100644
--- a/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/util/jsCodeUtils.kt
+++ b/wasm/wasm.frontend/src/org/jetbrains/kotlin/wasm/util/jsCodeUtils.kt
@@ -29,10 +29,6 @@
val body = bodyExpression!!
return when {
!hasBlockBody() -> body.isJsCall(bindingContext)
- body is KtBlockExpression -> {
- val statement = body.statements.singleOrNull() ?: return false
- statement.isJsCall(bindingContext)
- }
else -> false
}
}