From d5b958f744b1c624c4c581a933c9da5b7a446cd3 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Wed, 8 Mar 2023 19:38:19 +0100 Subject: [PATCH] [Wasm] Support default parameter values in functions with js(code) --- .../backend/wasm/lower/JsCodeCallsLowering.kt | 27 ++++++++++++++++++- .../codegen/boxWasmJsInterop/jsCode.kt | 20 ++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsCodeCallsLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsCodeCallsLowering.kt index 644c9b29e53..a473feabf83 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsCodeCallsLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsCodeCallsLowering.kt @@ -11,8 +11,8 @@ import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.* /** * Lower calls to `js(code)` into `@JsFun(code) external` functions. @@ -55,6 +55,31 @@ class JsCodeCallsLowering(val context: WasmBackendContext) : FileLoweringPass { append(jsCode) if (!isSingleExpressionJsCode) append(" }") } + if (function.valueParameters.any { it.defaultValue != null }) { + // Create a separate external function without default arguments + // and delegate calls to it. + val externalFun = createExternalJsFunction( + context, + function.name, + "_js_code", + function.returnType, + jsCode = jsFunCode, + ) + externalFun.copyTypeParametersFrom(function) + externalFun.valueParameters = function.valueParameters.map { it.copyTo(externalFun, defaultValue = null) } + function.body = context.createIrBuilder(function.symbol).irBlockBody { + val call = irCall(externalFun.symbol) + function.valueParameters.forEachIndexed { index, parameter -> + call.putValueArgument(index, irGet(parameter)) + } + function.typeParameters.forEachIndexed { index, typeParameter -> + call.putTypeArgument(index, typeParameter.defaultType) + } + +irReturn(call) + } + return listOf(function, externalFun) + } + val builder = context.createIrBuilder(function.symbol) function.annotations += builder.irCallConstructor(context.wasmSymbols.jsFunConstructor, typeArguments = emptyList()).also { it.putValueArgument(0, builder.irString(jsFunCode)) diff --git a/compiler/testData/codegen/boxWasmJsInterop/jsCode.kt b/compiler/testData/codegen/boxWasmJsInterop/jsCode.kt index 11f1e921ef5..77f0932ea67 100644 --- a/compiler/testData/codegen/boxWasmJsInterop/jsCode.kt +++ b/compiler/testData/codegen/boxWasmJsInterop/jsCode.kt @@ -2,10 +2,30 @@ fun foo(x: Int, y: Int, z: String): Int = js("x + y + Number(z)") val x: String = js("typeof 10") +fun fooDefault(x: Int = 1, y: Int? = 2, z: String? = "3"): Int = + js("x + y + Number(z)") + +external interface EIA +external class EIB : EIA + +val eia10: EIA = js("'10'") +val eib1000: EIB = js("'1000'") + +fun fooDefaultT(x: T? = null): T? = + js("x") + fun box(): String { val res = foo(10, 20, z = "30") if (res != 60) return "Wrong foo: $res" if (x != "number") return "Wrong x: $x" + if (fooDefault() != 6) return "Wrong fooDefault 1" + if (fooDefault(x = 100, y = 200, z = "300") != 600) return "Wrong fooDefault 2" + if (fooDefault(y = 200, z = "300") != 501) return "Wrong fooDefault 3" + + if (fooDefaultT() != null) return "Wrong fooDefaultT 1" + if (fooDefaultT(eia10).toString() != "10") return "Wrong fooDefaultT 2" + if (fooDefaultT(eib1000).toString() != "1000") return "Wrong fooDefaultT 3" + return "OK" } \ No newline at end of file