[go: nahoru, domu]

Fix a bug preventing the usage of default values in compose/js

Expressions for default values can use other parameters.
```fun Foo(a: String, b: String = a) {...}```
In such cases we need to ensure that default values expressions
use parameters of the new function (new/copied value parameters).

The change is only for kotlin/js targets (DecoysTransformer is k/js specific)

Test: tested locally in compose-jb fork
Change-Id: I4d174f0d335902911b284c0c1b3bd5f0a485ccf9
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
index 8038409..b6b129c 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt
@@ -43,6 +43,10 @@
 import org.jetbrains.kotlin.ir.declarations.IrFunction
 import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
 import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
+import org.jetbrains.kotlin.ir.declarations.IrValueParameter
+import org.jetbrains.kotlin.ir.expressions.IrExpression
+import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
+import org.jetbrains.kotlin.ir.expressions.IrGetValue
 import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
 import org.jetbrains.kotlin.ir.types.IrSimpleType
 import org.jetbrains.kotlin.ir.types.IrType
@@ -53,6 +57,8 @@
 import org.jetbrains.kotlin.ir.util.hasDefaultValue
 import org.jetbrains.kotlin.ir.util.isLocal
 import org.jetbrains.kotlin.ir.util.patchDeclarationParents
+import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.resolve.BindingTrace
 
@@ -218,9 +224,43 @@
 
         newFunction.addDecoyImplementationAnnotation(newName.asString(), original.getSignatureId())
 
+        newFunction.valueParameters.forEach {
+            it.defaultValue?.transformDefaultValue(
+                originalFunction = original,
+                newFunction = newFunction
+            )
+        }
+
         return newFunction
     }
 
+    /**
+     *  Expressions for default values can use other parameters.
+     *  In such cases we need to ensure that default values expressions use parameters of the new
+     *  function (new/copied value parameters).
+     *
+     *  Example:
+     *  fun Foo(a: String, b: String = a) {...}
+     */
+    private fun IrExpressionBody.transformDefaultValue(
+        originalFunction: IrFunction,
+        newFunction: IrFunction
+    ) {
+        transformChildrenVoid(object : IrElementTransformerVoid() {
+            override fun visitGetValue(expression: IrGetValue): IrExpression {
+                val original = super.visitGetValue(expression)
+                val valueParameter =
+                    (expression.symbol.owner as? IrValueParameter) ?: return original
+
+                val parameterIndex = valueParameter.index
+                if (parameterIndex < 0 || valueParameter.parent != originalFunction) {
+                    return super.visitGetValue(expression)
+                }
+                return irGet(newFunction.valueParameters[parameterIndex])
+            }
+        })
+    }
+
     private fun IrFunction.stubBody() {
         body = DeclarationIrBuilder(context, symbol).irBlockBody {
             + irReturn(