diff --git a/kopy-compiler/main/kotlin/com/javiersc/kotlin/kopy/compiler/ir/_internal/UpdateCallTransformer.kt b/kopy-compiler/main/kotlin/com/javiersc/kotlin/kopy/compiler/ir/_internal/UpdateCallTransformer.kt index 16731f8..bc43913 100644 --- a/kopy-compiler/main/kotlin/com/javiersc/kotlin/kopy/compiler/ir/_internal/UpdateCallTransformer.kt +++ b/kopy-compiler/main/kotlin/com/javiersc/kotlin/kopy/compiler/ir/_internal/UpdateCallTransformer.kt @@ -6,9 +6,12 @@ import com.javiersc.kotlin.compiler.extensions.ir.asIr import com.javiersc.kotlin.compiler.extensions.ir.asIrOrNull import com.javiersc.kotlin.compiler.extensions.ir.createIrFunctionExpression import com.javiersc.kotlin.compiler.extensions.ir.declarationIrBuilder +import com.javiersc.kotlin.compiler.extensions.ir.filterIrIsInstance import com.javiersc.kotlin.compiler.extensions.ir.firstIrSimpleFunction +import com.javiersc.kotlin.compiler.extensions.ir.treeNode import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.IrBlockBodyBuilder @@ -86,13 +89,14 @@ internal class UpdateCallTransformer( .apply { parent = declarationParent addValueParameter { - this.name = "it".toName() + this.name = StandardNames.IMPLICIT_LAMBDA_PARAMETER_NAME this.type = type } } val letBlockBody: IrBlockBody = pluginContext.declarationIrBuilder(letBlockFunction).irBlockBody { + replaceUpdateBlockItWithLetBlockIt(updateCall, letBlockFunction) for (statement in updateBlockStatements) { +processUpdateBlockStatement(statement) } @@ -130,9 +134,40 @@ internal class UpdateCallTransformer( return letCall } + private fun replaceUpdateBlockItWithLetBlockIt( + updateCall: IrCall, + letBlockFunction: IrSimpleFunction, + ) { + val updateItValueParameter: IrValueParameter = + updateCall + .getValueArgument(0) + ?.asIrOrNull() + ?.function + ?.valueParameters + ?.firstOrNull() ?: return + val its: List = + updateCall + .getValueArgument(0) + ?.treeNode + ?.asSequence() + ?.filterIrIsInstance() + ?.filter { it.symbol.owner == updateItValueParameter } + .orEmpty() + .toList() + + val letItValueParameter: IrValueParameter = letBlockFunction.valueParameters.first() + + for (it in its) { + it.symbol = letItValueParameter.symbol + } + } + private fun IrBlockBodyBuilder.processUpdateBlockStatement( statement: IrStatement - ): IrStatement = if (statement is IrReturn) irReturn(statement.value) else statement + ): IrStatement { + + return if (statement is IrReturn) irReturn(statement.value) else statement + } private fun createCopyCall(updateCall: IrCall, letCall: IrCall): IrCall { val tempVarGet: IrGetValue = diff --git a/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.fir.ir.txt b/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.fir.ir.txt new file mode 100644 index 0000000..70ca699 --- /dev/null +++ b/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.fir.ir.txt @@ -0,0 +1,250 @@ +FILE fqName:com.javiersc.kotlin.kopy.playground fileName:/no-nest-invoke-update-with-it.kt + FUN name:box visibility:public modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + VAR name:house0 type:com.javiersc.kotlin.kopy.playground.House [val] + CONSTRUCTOR_CALL 'public constructor (street: kotlin.String, squareMeters: kotlin.Int) declared in com.javiersc.kotlin.kopy.playground.House' type=com.javiersc.kotlin.kopy.playground.House origin=null + street: CONST String type=kotlin.String value="Street" + squareMeters: CONST Int type=kotlin.Int value=20 + VAR name:house1 type:com.javiersc.kotlin.kopy.playground.House [val] + CALL 'public final fun run (block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.run declared in kotlin' type=com.javiersc.kotlin.kopy.playground.House origin=null + : com.javiersc.kotlin.kopy.playground.House + : com.javiersc.kotlin.kopy.playground.House + $receiver: GET_VAR 'val house0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box' type=com.javiersc.kotlin.kopy.playground.House origin=VARIABLE_AS_FUNCTION + block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:com.javiersc.kotlin.kopy.playground.House) returnType:com.javiersc.kotlin.kopy.playground.House + $receiver: VALUE_PARAMETER name:$this$run type:com.javiersc.kotlin.kopy.playground.House + BLOCK_BODY + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:com.javiersc.kotlin.kopy.playground.House [var] + GET_VAR '$this$run: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=com.javiersc.kotlin.kopy.playground.House origin=null + SET_VAR 'var tmp_0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=kotlin.Unit origin=EQ + CALL 'public final fun copy (street: kotlin.String, squareMeters: kotlin.Int): com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House' type=com.javiersc.kotlin.kopy.playground.House origin=null + $this: GET_VAR 'var tmp_0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=com.javiersc.kotlin.kopy.playground.House origin=null + squareMeters: CALL 'public final fun let (block: kotlin.Function1): R of kotlin.let declared in kotlin' type=kotlin.Int origin=null + : kotlin.Int + : kotlin.Int + $receiver: CALL 'public final fun (): kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR 'var tmp_0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=com.javiersc.kotlin.kopy.playground.House origin=null + block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Int + VALUE_PARAMETER name:it index:0 type:kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (it: kotlin.Int): kotlin.Int declared in com.javiersc.kotlin.kopy.playground.box.' + CALL 'public final fun plus (other: kotlin.Int): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=PLUS + $this: GET_VAR 'it: kotlin.Int declared in com.javiersc.kotlin.kopy.playground.box..' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value=20 + RETURN type=kotlin.Nothing from='local final fun (): com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box' + GET_VAR 'var tmp_0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=com.javiersc.kotlin.kopy.playground.House origin=null + VAR name:house2 type:com.javiersc.kotlin.kopy.playground.House [val] + CALL 'public final fun run (block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.run declared in kotlin' type=com.javiersc.kotlin.kopy.playground.House origin=null + : com.javiersc.kotlin.kopy.playground.House + : com.javiersc.kotlin.kopy.playground.House + $receiver: GET_VAR 'val house0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box' type=com.javiersc.kotlin.kopy.playground.House origin=null + block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:com.javiersc.kotlin.kopy.playground.House) returnType:com.javiersc.kotlin.kopy.playground.House + $receiver: VALUE_PARAMETER name:$this$run type:com.javiersc.kotlin.kopy.playground.House + BLOCK_BODY + VAR name:tmp0 type:com.javiersc.kotlin.kopy.playground.House [var] + GET_VAR '$this$run: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=com.javiersc.kotlin.kopy.playground.House origin=null + SET_VAR 'var tmp0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=kotlin.Unit origin=EQ + CALL 'public final fun copy (street: kotlin.String, squareMeters: kotlin.Int): com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House' type=com.javiersc.kotlin.kopy.playground.House origin=null + $this: GET_VAR 'var tmp0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=com.javiersc.kotlin.kopy.playground.House origin=null + squareMeters: CALL 'public final fun let (block: kotlin.Function1): R of kotlin.let declared in kotlin' type=kotlin.Int origin=null + : kotlin.Int + : kotlin.Int + $receiver: CALL 'public final fun (): kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR 'var tmp0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=com.javiersc.kotlin.kopy.playground.House origin=null + block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Int + VALUE_PARAMETER name:it index:0 type:kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (it: kotlin.Int): kotlin.Int declared in com.javiersc.kotlin.kopy.playground.box.' + CALL 'public final fun plus (other: kotlin.Int): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=PLUS + $this: GET_VAR 'it: kotlin.Int declared in com.javiersc.kotlin.kopy.playground.box..' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value=20 + RETURN type=kotlin.Nothing from='local final fun (): com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box' + GET_VAR 'var tmp0: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box.' type=com.javiersc.kotlin.kopy.playground.House origin=null + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in com.javiersc.kotlin.kopy.playground' + WHEN type=kotlin.String origin=IF + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'val house1: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box' type=com.javiersc.kotlin.kopy.playground.House origin=null + arg1: GET_VAR 'val house2: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box' type=com.javiersc.kotlin.kopy.playground.House origin=null + then: CONST String type=kotlin.String value="OK" + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="Fail: \nHouse1: " + GET_VAR 'val house1: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box' type=com.javiersc.kotlin.kopy.playground.House origin=null + CONST String type=kotlin.String value=" \nHouse2: " + GET_VAR 'val house2: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.box' type=com.javiersc.kotlin.kopy.playground.House origin=null + CLASS CLASS name:House modality:FINAL visibility:internal [data] superTypes:[kotlin.Any; com.javiersc.kotlin.kopy.runtime.Kopyable] + annotations: + Kopy + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:com.javiersc.kotlin.kopy.playground.House + CONSTRUCTOR visibility:public <> (street:kotlin.String, squareMeters:kotlin.Int) returnType:com.javiersc.kotlin.kopy.playground.House [primary] + VALUE_PARAMETER name:street index:0 type:kotlin.String + VALUE_PARAMETER name:squareMeters index:1 type:kotlin.Int + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:House modality:FINAL visibility:internal [data] superTypes:[kotlin.Any; com.javiersc.kotlin.kopy.runtime.Kopyable]' + PROPERTY name:street visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:street type:kotlin.String visibility:private [final] + EXPRESSION_BODY + GET_VAR 'street: kotlin.String declared in com.javiersc.kotlin.kopy.playground.House.' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:com.javiersc.kotlin.kopy.playground.House) returnType:kotlin.String + correspondingProperty: PROPERTY name:street visibility:public modality:FINAL [val] + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.playground.House + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in com.javiersc.kotlin.kopy.playground.House' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:street type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.' type=com.javiersc.kotlin.kopy.playground.House origin=null + PROPERTY name:squareMeters visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:squareMeters type:kotlin.Int visibility:private [final] + EXPRESSION_BODY + GET_VAR 'squareMeters: kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House.' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:com.javiersc.kotlin.kopy.playground.House) returnType:kotlin.Int + correspondingProperty: PROPERTY name:squareMeters visibility:public modality:FINAL [val] + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.playground.House + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:squareMeters type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.' type=com.javiersc.kotlin.kopy.playground.House origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:component1 visibility:public modality:FINAL <> ($this:com.javiersc.kotlin.kopy.playground.House) returnType:kotlin.String [operator] + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.playground.House + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun component1 (): kotlin.String declared in com.javiersc.kotlin.kopy.playground.House' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:street type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.component1' type=com.javiersc.kotlin.kopy.playground.House origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:component2 visibility:public modality:FINAL <> ($this:com.javiersc.kotlin.kopy.playground.House) returnType:kotlin.Int [operator] + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.playground.House + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun component2 (): kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:squareMeters type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.component2' type=com.javiersc.kotlin.kopy.playground.House origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:copy visibility:public modality:FINAL <> ($this:com.javiersc.kotlin.kopy.playground.House, street:kotlin.String, squareMeters:kotlin.Int) returnType:com.javiersc.kotlin.kopy.playground.House + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.playground.House + VALUE_PARAMETER name:street index:0 type:kotlin.String + EXPRESSION_BODY + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:street type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.copy' type=com.javiersc.kotlin.kopy.playground.House origin=null + VALUE_PARAMETER name:squareMeters index:1 type:kotlin.Int + EXPRESSION_BODY + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:squareMeters type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.copy' type=com.javiersc.kotlin.kopy.playground.House origin=null + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun copy (street: kotlin.String, squareMeters: kotlin.Int): com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House' + CONSTRUCTOR_CALL 'public constructor (street: kotlin.String, squareMeters: kotlin.Int) declared in com.javiersc.kotlin.kopy.playground.House' type=com.javiersc.kotlin.kopy.playground.House origin=null + street: GET_VAR 'street: kotlin.String declared in com.javiersc.kotlin.kopy.playground.House.copy' type=kotlin.String origin=null + squareMeters: GET_VAR 'squareMeters: kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House.copy' type=kotlin.Int origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:toString visibility:public modality:OPEN <> ($this:com.javiersc.kotlin.kopy.playground.House) returnType:kotlin.String + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.playground.House + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun toString (): kotlin.String declared in com.javiersc.kotlin.kopy.playground.House' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="House(" + CONST String type=kotlin.String value="street=" + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:street type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.toString' type=com.javiersc.kotlin.kopy.playground.House origin=null + CONST String type=kotlin.String value=", " + CONST String type=kotlin.String value="squareMeters=" + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:squareMeters type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.toString' type=com.javiersc.kotlin.kopy.playground.House origin=null + CONST String type=kotlin.String value=")" + FUN GENERATED_DATA_CLASS_MEMBER name:hashCode visibility:public modality:OPEN <> ($this:com.javiersc.kotlin.kopy.playground.House) returnType:kotlin.Int + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.playground.House + BLOCK_BODY + VAR name:result type:kotlin.Int [var] + CALL 'public open fun hashCode (): kotlin.Int declared in kotlin.String' type=kotlin.Int origin=null + $this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:street type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.hashCode' type=com.javiersc.kotlin.kopy.playground.House origin=null + SET_VAR 'var result: kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House.hashCode' type=kotlin.Unit origin=EQ + CALL 'public final fun plus (other: kotlin.Int): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=null + $this: CALL 'public final fun times (other: kotlin.Int): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=null + $this: GET_VAR 'var result: kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House.hashCode' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value=31 + other: CALL 'public open fun hashCode (): kotlin.Int declared in kotlin.Int' type=kotlin.Int origin=null + $this: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:squareMeters type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.hashCode' type=com.javiersc.kotlin.kopy.playground.House origin=null + RETURN type=kotlin.Nothing from='public open fun hashCode (): kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House' + GET_VAR 'var result: kotlin.Int declared in com.javiersc.kotlin.kopy.playground.House.hashCode' type=kotlin.Int origin=null + FUN GENERATED_DATA_CLASS_MEMBER name:equals visibility:public modality:OPEN <> ($this:com.javiersc.kotlin.kopy.playground.House, other:kotlin.Any?) returnType:kotlin.Boolean [operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.playground.House + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'public final fun EQEQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQEQ + arg0: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.equals' type=com.javiersc.kotlin.kopy.playground.House origin=null + arg1: GET_VAR 'other: kotlin.Any? declared in com.javiersc.kotlin.kopy.playground.House.equals' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in com.javiersc.kotlin.kopy.playground.House' + CONST Boolean type=kotlin.Boolean value=true + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=NOT_INSTANCEOF typeOperand=com.javiersc.kotlin.kopy.playground.House + GET_VAR 'other: kotlin.Any? declared in com.javiersc.kotlin.kopy.playground.House.equals' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in com.javiersc.kotlin.kopy.playground.House' + CONST Boolean type=kotlin.Boolean value=false + VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:com.javiersc.kotlin.kopy.playground.House [val] + TYPE_OP type=com.javiersc.kotlin.kopy.playground.House origin=CAST typeOperand=com.javiersc.kotlin.kopy.playground.House + GET_VAR 'other: kotlin.Any? declared in com.javiersc.kotlin.kopy.playground.House.equals' type=kotlin.Any? origin=null + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'public final fun not (): kotlin.Boolean declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ + $this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ + arg0: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:street type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.equals' type=com.javiersc.kotlin.kopy.playground.House origin=null + arg1: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:street type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR 'val tmp_1: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.equals' type=com.javiersc.kotlin.kopy.playground.House origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in com.javiersc.kotlin.kopy.playground.House' + CONST Boolean type=kotlin.Boolean value=false + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'public final fun not (): kotlin.Boolean declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ + $this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ + arg0: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:squareMeters type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null + receiver: GET_VAR ': com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.equals' type=com.javiersc.kotlin.kopy.playground.House origin=null + arg1: GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:squareMeters type:kotlin.Int visibility:private [final]' type=kotlin.Int origin=null + receiver: GET_VAR 'val tmp_1: com.javiersc.kotlin.kopy.playground.House declared in com.javiersc.kotlin.kopy.playground.House.equals' type=com.javiersc.kotlin.kopy.playground.House origin=null + then: RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in com.javiersc.kotlin.kopy.playground.House' + CONST Boolean type=kotlin.Boolean value=false + RETURN type=kotlin.Nothing from='public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in com.javiersc.kotlin.kopy.playground.House' + CONST Boolean type=kotlin.Boolean value=true + FUN FAKE_OVERRIDE name:copy visibility:public modality:OPEN <> ($this:com.javiersc.kotlin.kopy.runtime.Kopyable, kopy:@[ExtensionFunctionType] kotlin.Function1) returnType:com.javiersc.kotlin.kopy.playground.House [fake_override,infix] + annotations: + KopyFunctionInvoke + overridden: + public open fun copy (kopy: @[ExtensionFunctionType] kotlin.Function1): T of com.javiersc.kotlin.kopy.runtime.Kopyable declared in com.javiersc.kotlin.kopy.runtime.Kopyable + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.runtime.Kopyable + VALUE_PARAMETER name:kopy index:0 type:@[ExtensionFunctionType] kotlin.Function1 + FUN FAKE_OVERRIDE name:invoke visibility:public modality:OPEN <> ($this:com.javiersc.kotlin.kopy.runtime.Kopyable, kopy:@[ExtensionFunctionType] kotlin.Function1) returnType:com.javiersc.kotlin.kopy.playground.House [fake_override,operator,infix] + annotations: + KopyFunctionInvoke + overridden: + public open fun invoke (kopy: @[ExtensionFunctionType] kotlin.Function1): T of com.javiersc.kotlin.kopy.runtime.Kopyable declared in com.javiersc.kotlin.kopy.runtime.Kopyable + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.runtime.Kopyable + VALUE_PARAMETER name:kopy index:0 type:@[ExtensionFunctionType] kotlin.Function1 + FUN FAKE_OVERRIDE name:set visibility:public modality:OPEN ($this:com.javiersc.kotlin.kopy.runtime.Kopyable, $receiver:R of com.javiersc.kotlin.kopy.playground.House.set, other:R of com.javiersc.kotlin.kopy.playground.House.set) returnType:R of com.javiersc.kotlin.kopy.playground.House.set [fake_override,infix] + annotations: + KopyFunctionSet + overridden: + public open fun set (other: R of com.javiersc.kotlin.kopy.runtime.Kopyable.set): R of com.javiersc.kotlin.kopy.runtime.Kopyable.set declared in com.javiersc.kotlin.kopy.runtime.Kopyable + TYPE_PARAMETER name:R index:0 variance: superTypes:[kotlin.Any?] reified:false + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.runtime.Kopyable + $receiver: VALUE_PARAMETER name: type:R of com.javiersc.kotlin.kopy.playground.House.set + VALUE_PARAMETER name:other index:0 type:R of com.javiersc.kotlin.kopy.playground.House.set + FUN FAKE_OVERRIDE name:update visibility:public modality:OPEN ($this:com.javiersc.kotlin.kopy.runtime.Kopyable, $receiver:R of com.javiersc.kotlin.kopy.playground.House.update, other:kotlin.Function1) returnType:R of com.javiersc.kotlin.kopy.playground.House.update [fake_override,infix] + annotations: + KopyFunctionUpdate + overridden: + public open fun update (other: kotlin.Function1): R of com.javiersc.kotlin.kopy.runtime.Kopyable.update declared in com.javiersc.kotlin.kopy.runtime.Kopyable + TYPE_PARAMETER name:R index:0 variance: superTypes:[kotlin.Any?] reified:false + $this: VALUE_PARAMETER name: type:com.javiersc.kotlin.kopy.runtime.Kopyable + $receiver: VALUE_PARAMETER name: type:R of com.javiersc.kotlin.kopy.playground.House.update + VALUE_PARAMETER name:other index:0 type:kotlin.Function1 +FILE fqName: fileName:/SomeFile.kt diff --git a/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.fir.txt b/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.fir.txt new file mode 100644 index 0000000..7ca31d7 --- /dev/null +++ b/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.fir.txt @@ -0,0 +1,49 @@ +FILE: no-nest-invoke-update-with-it.kt + package com.javiersc.kotlin.kopy.playground + + public final fun box(): R|kotlin/String| { + lval house0: R|com/javiersc/kotlin/kopy/playground/House| = R|com/javiersc/kotlin/kopy/playground/House.House|(street = String(Street), squareMeters = Int(20)) + lval house1: R|com/javiersc/kotlin/kopy/playground/House| = R|/house0|.R|SubstitutionOverride|( = house0@fun R|com/javiersc/kotlin/kopy/playground/House|.(): R|kotlin/Unit| { + (this@R|special/anonymous|, this@R|special/anonymous|.R|com/javiersc/kotlin/kopy/playground/House.squareMeters|).R|SubstitutionOverride|( = update@fun (it: R|kotlin/Int|): R|kotlin/Int| { + ^ R|/it|.R|kotlin/Int.plus|(Int(20)) + } + ) + } + ) + lval house2: R|com/javiersc/kotlin/kopy/playground/House| = R|/house0|.R|kotlin/run|( = run@fun R|com/javiersc/kotlin/kopy/playground/House|.(): R|com/javiersc/kotlin/kopy/playground/House| { + lvar tmp0: R|com/javiersc/kotlin/kopy/playground/House| = this@R|special/anonymous| + R|/tmp0| = R|/tmp0|.R|com/javiersc/kotlin/kopy/playground/House.copy|(squareMeters = R|/tmp0|.R|com/javiersc/kotlin/kopy/playground/House.squareMeters|.R|kotlin/let|( = let@fun (it: R|kotlin/Int|): R|kotlin/Int| { + ^ R|/it|.R|kotlin/Int.plus|(Int(20)) + } + )) + ^ R|/tmp0| + } + ) + ^box when () { + ==(R|/house1|, R|/house2|) -> { + String(OK) + } + else -> { + (String(Fail: ), Char(10), String(House1: ), R|/house1|, String( ), Char(10), String(House2: ), R|/house2|) + } + } + + } + @R|com/javiersc/kotlin/kopy/Kopy|() internal final data class House : R|kotlin/Any|, R|com/javiersc/kotlin/kopy/runtime/Kopyable| { + public constructor(street: R|kotlin/String|, squareMeters: R|kotlin/Int|): R|com/javiersc/kotlin/kopy/playground/House| { + super() + } + + public final val street: R|kotlin/String| = R|/street| + public get(): R|kotlin/String| + + public final val squareMeters: R|kotlin/Int| = R|/squareMeters| + public get(): R|kotlin/Int| + + public final operator fun component1(): R|kotlin/String| + + public final operator fun component2(): R|kotlin/Int| + + public final fun copy(street: R|kotlin/String| = this@R|com/javiersc/kotlin/kopy/playground/House|.R|com/javiersc/kotlin/kopy/playground/House.street|, squareMeters: R|kotlin/Int| = this@R|com/javiersc/kotlin/kopy/playground/House|.R|com/javiersc/kotlin/kopy/playground/House.squareMeters|): R|com/javiersc/kotlin/kopy/playground/House| + + } diff --git a/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.kt b/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.kt new file mode 100644 index 0000000..3724de7 --- /dev/null +++ b/kopy-compiler/test-data/box/no-nest-invoke-update-with-it.kt @@ -0,0 +1,19 @@ +// !DIAGNOSTICS: -MISSING_DEPENDENCY_SUPERCLASS + +package com.javiersc.kotlin.kopy.playground + +import com.javiersc.kotlin.kopy.Kopy + +fun box(): String { + val house0 = House(street = "Street", squareMeters = 20) + val house1 = house0 { squareMeters.update { it + 20 } } + val house2 = + house0.run { + var tmp0 = this + tmp0 = tmp0.copy(squareMeters = tmp0.squareMeters.let { it + 20 }) + tmp0 + } + return if (house1 == house2) "OK" else "Fail: \nHouse1: $house1 \nHouse2: $house2" +} + +@Kopy internal data class House(val street: String, val squareMeters: Int) diff --git a/kopy-compiler/test-gen/java/com/javiersc/kotlin/kopy/compiler/BoxTestGenerated.java b/kopy-compiler/test-gen/java/com/javiersc/kotlin/kopy/compiler/BoxTestGenerated.java index 6c6fad3..1ddfcc4 100644 --- a/kopy-compiler/test-gen/java/com/javiersc/kotlin/kopy/compiler/BoxTestGenerated.java +++ b/kopy-compiler/test-gen/java/com/javiersc/kotlin/kopy/compiler/BoxTestGenerated.java @@ -33,4 +33,10 @@ public void testNo_nest_copy_update_no_it() throws Exception { public void testNo_nest_invoke_update_no_it() throws Exception { runTest("test-data/box/no-nest-invoke-update-no-it.kt"); } + + @Test + @TestMetadata("no-nest-invoke-update-with-it.kt") + public void testNo_nest_invoke_update_with_it() throws Exception { + runTest("test-data/box/no-nest-invoke-update-with-it.kt"); + } } diff --git a/kopy-runtime/main/kotlin/com/javiersc/kotlin/kopy/runtime/delete/Delete.kt b/kopy-runtime/main/kotlin/com/javiersc/kotlin/kopy/runtime/delete/Delete.kt index c0ce66d..719a8de 100644 --- a/kopy-runtime/main/kotlin/com/javiersc/kotlin/kopy/runtime/delete/Delete.kt +++ b/kopy-runtime/main/kotlin/com/javiersc/kotlin/kopy/runtime/delete/Delete.kt @@ -5,14 +5,14 @@ import com.javiersc.kotlin.kopy.runtime.Kopyable internal fun box(): String { val house0 = House(street = "Street", squareMeters = 20) - val house1 = house0 { squareMeters.update { 40 } } + val house1 = house0 { squareMeters.update { it + 20 } } val house2 = house0.run { - var tmp1 = this - tmp1 = tmp1.copy(squareMeters = tmp1.squareMeters.let { 40 }) - tmp1 + var tmp0 = this + tmp0 = tmp0.copy(squareMeters = tmp0.squareMeters.let { it + 20 }) + tmp0 } - return if (house1 == house2) "OK" else "ERROR" + return if (house1 == house2) "OK" else "Fail: \nHouse1: $house1 \nHouse2: $house2" } @Kopy internal data class House(val street: String, val squareMeters: Int) : Kopyable