From 26487d283d3534a5c227845de491a08c5a6388e0 Mon Sep 17 00:00:00 2001
From: Anton Bannykh <anton.bannykh@jetbrains.com>
Date: Fri, 15 Apr 2022 21:01:43 +0300
Subject: [PATCH] JS IR: materialize Unit in lambdas

^KT-52010 fixed

(cherry picked from commit 281e381223eeb5957fac93436413639617976636)
---
 .../lower/InteropCallableReferenceLowering.kt |  6 ++++
 .../kotlin/js/test/BoxJsTestGenerated.java    | 12 +++++++
 .../js/test/ir/IrBoxJsTestGenerated.java      | 12 +++++++
 .../expression/function/lambdaReturnValue.kt  | 35 +++++++++++++++++++
 .../testData/box/regression/kt52010.kt        | 22 ++++++++++++
 5 files changed, 87 insertions(+)
 create mode 100644 js/js.translator/testData/box/expression/function/lambdaReturnValue.kt
 create mode 100644 js/js.translator/testData/box/regression/kt52010.kt

diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/InteropCallableReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/InteropCallableReferenceLowering.kt
index a72702611745f..7b4c60df08c4d 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/InteropCallableReferenceLowering.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/InteropCallableReferenceLowering.kt
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
 import org.jetbrains.kotlin.ir.symbols.*
 import org.jetbrains.kotlin.ir.types.IrType
 import org.jetbrains.kotlin.ir.types.classifierOrNull
+import org.jetbrains.kotlin.ir.types.isUnit
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
 import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -147,6 +148,11 @@ class InteropCallableReferenceLowering(val context: JsIrBackendContext) : BodyLo
         // Fix parents of declarations inside body
         body.patchDeclarationParents(lambdaDeclaration)
 
+        if (invokeFun.returnType.isUnit()) {
+            val unitValue = JsIrBuilder.buildGetObjectValue(context.irBuiltIns.unitType, context.irBuiltIns.unitClass)
+            (body as IrBlockBody).statements.add(IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.nothingType, lambdaDeclaration.symbol, unitValue))
+        }
+
         return body as IrBlockBody
     }
 
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java
index d0d93fdbbac85..41e9a478865b0 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/BoxJsTestGenerated.java
@@ -2947,6 +2947,12 @@ public void testLambdaOrLocalFunInsideEnumMethod() throws Exception {
                 runTest("js/js.translator/testData/box/expression/function/lambdaOrLocalFunInsideEnumMethod.kt");
             }
 
+            @Test
+            @TestMetadata("lambdaReturnValue.kt")
+            public void testLambdaReturnValue() throws Exception {
+                runTest("js/js.translator/testData/box/expression/function/lambdaReturnValue.kt");
+            }
+
             @Test
             @TestMetadata("localExtFunction.kt")
             public void testLocalExtFunction() throws Exception {
@@ -8612,6 +8618,12 @@ public void testKt2470() throws Exception {
             runTest("js/js.translator/testData/box/regression/kt2470.kt");
         }
 
+        @Test
+        @TestMetadata("kt52010.kt")
+        public void testKt52010() throws Exception {
+            runTest("js/js.translator/testData/box/regression/kt52010.kt");
+        }
+
         @Test
         @TestMetadata("tmpInsidePrimaryConstructor.kt")
         public void testTmpInsidePrimaryConstructor() throws Exception {
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java
index 22bc69df2cee4..a16b0f55d607c 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java
@@ -3337,6 +3337,12 @@ public void testLambdaOrLocalFunInsideEnumMethod() throws Exception {
                 runTest("js/js.translator/testData/box/expression/function/lambdaOrLocalFunInsideEnumMethod.kt");
             }
 
+            @Test
+            @TestMetadata("lambdaReturnValue.kt")
+            public void testLambdaReturnValue() throws Exception {
+                runTest("js/js.translator/testData/box/expression/function/lambdaReturnValue.kt");
+            }
+
             @Test
             @TestMetadata("localExtFunction.kt")
             public void testLocalExtFunction() throws Exception {
@@ -9002,6 +9008,12 @@ public void testKt2470() throws Exception {
             runTest("js/js.translator/testData/box/regression/kt2470.kt");
         }
 
+        @Test
+        @TestMetadata("kt52010.kt")
+        public void testKt52010() throws Exception {
+            runTest("js/js.translator/testData/box/regression/kt52010.kt");
+        }
+
         @Test
         @TestMetadata("tmpInsidePrimaryConstructor.kt")
         public void testTmpInsidePrimaryConstructor() throws Exception {
diff --git a/js/js.translator/testData/box/expression/function/lambdaReturnValue.kt b/js/js.translator/testData/box/expression/function/lambdaReturnValue.kt
new file mode 100644
index 0000000000000..9809cce2756f0
--- /dev/null
+++ b/js/js.translator/testData/box/expression/function/lambdaReturnValue.kt
@@ -0,0 +1,35 @@
+// EXPECTED_REACHABLE_NODES: 1285
+
+fun <T> rawReturnValue(fn: () -> T): Any {
+    return fn() as Any
+}
+
+fun unitFun() {}
+
+fun charFun(): Char = 'a'
+
+value class VC(val v: Int)
+
+fun vcFun(): VC = VC(1)
+
+
+
+fun box(): String {
+    if (rawReturnValue { unitFun() } != Unit) return "fail1.1"
+    if (rawReturnValue<Unit> { unitFun() } != Unit) return "fail1.2"
+    if (rawReturnValue<Any> { unitFun() } != Unit) return "fail1.3"
+
+    val boxedA: Any = 'a'
+
+    if (rawReturnValue { charFun() } != boxedA) return "fail2.1"
+    if (rawReturnValue<Char> { charFun() } != boxedA) return "fail2.2"
+    if (rawReturnValue<Any> { charFun() } != boxedA) return "fail2.3"
+
+    val boxed1: Any = VC(1)
+
+    if (rawReturnValue { vcFun() } != boxed1) return "fail3.1"
+    if (rawReturnValue<VC> { vcFun() } != boxed1) return "fail3.2"
+    if (rawReturnValue<Any> { vcFun() } != boxed1) return "fail3.3"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/js/js.translator/testData/box/regression/kt52010.kt b/js/js.translator/testData/box/regression/kt52010.kt
new file mode 100644
index 0000000000000..706e1ccad3e16
--- /dev/null
+++ b/js/js.translator/testData/box/regression/kt52010.kt
@@ -0,0 +1,22 @@
+// EXPECTED_REACHABLE_NODES: 1274
+
+fun box(): String {
+    instance = Holder()
+    instance?.applyAndRet<Unit> { sideEffect("left") } ?: sideEffect("right")
+
+    if (log == "left") return "OK" else return "fail: $log"
+}
+
+var log = ""
+
+fun sideEffect(msg: String) {
+    log += msg
+}
+
+var instance: Holder? = null
+
+class Holder() {
+    fun <T> applyAndRet(block: () -> T): T {
+        return block()
+    }
+}