diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt index 81fbcb1b849..6e91ee1063a 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/BodyGenerator.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.psi2ir.intermediate.VariableLValue import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny @@ -71,6 +72,15 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context: val ktBody = ktFun.bodyExpression!! val irBlockBody = IrBlockBodyImpl(ktBody.startOffset, ktBody.endOffset) + + for (ktParameter in ktFun.valueParameters) { + val ktDestructuringDeclaration = ktParameter.destructuringDeclaration ?: continue + val valueParameter = getOrFail(BindingContext.VALUE_PARAMETER, ktParameter) + val parameterValue = VariableLValue(ktDestructuringDeclaration.startOffset, ktDestructuringDeclaration.endOffset, + valueParameter, IrStatementOrigin.DESTRUCTURING_DECLARATION) + statementGenerator.declareComponentVariablesInBlock(ktDestructuringDeclaration, irBlockBody, parameterValue) + } + if (ktBody is KtBlockExpression) { val ktBodyStatements = ktBody.statements if (ktBodyStatements.isNotEmpty()) { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index bf42482c212..b4c57116f6b 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -105,7 +105,7 @@ class StatementGenerator( return irBlock } - fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrContainerExpressionBase, containerValue: IntermediateValue) { + fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrStatementContainer, containerValue: IntermediateValue) { val callGenerator = CallGenerator(this) for ((index, ktEntry) in multiDeclaration.entries.withIndex()) { val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry) diff --git a/compiler/testData/ir/irText/lambdas/destructuringInLambda.kt b/compiler/testData/ir/irText/lambdas/destructuringInLambda.kt new file mode 100644 index 00000000000..21022a7b9e4 --- /dev/null +++ b/compiler/testData/ir/irText/lambdas/destructuringInLambda.kt @@ -0,0 +1,3 @@ +data class A(val x: Int, val y: Int) + +var fn: (A) -> Int = { (_, y) -> 42 + y } \ No newline at end of file diff --git a/compiler/testData/ir/irText/lambdas/destructuringInLambda.txt b/compiler/testData/ir/irText/lambdas/destructuringInLambda.txt new file mode 100644 index 00000000000..abd16a0eb4c --- /dev/null +++ b/compiler/testData/ir/irText/lambdas/destructuringInLambda.txt @@ -0,0 +1,139 @@ +FILE /destructuringInLambda.kt + CLASS CLASS A + CONSTRUCTOR public constructor A(x: kotlin.Int, y: kotlin.Int) + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='A' + PROPERTY public final val x: kotlin.Int + FIELD PROPERTY_BACKING_FIELD public final val x: kotlin.Int + EXPRESSION_BODY + GET_VAR 'value-parameter x: Int' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Int' + GET_FIELD 'x: Int' type=kotlin.Int origin=null + receiver: GET_VAR '' type=A origin=null + PROPERTY public final val y: kotlin.Int + FIELD PROPERTY_BACKING_FIELD public final val y: kotlin.Int + EXPRESSION_BODY + GET_VAR 'value-parameter y: Int' type=kotlin.Int origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): Int' + GET_FIELD 'y: Int' type=kotlin.Int origin=null + receiver: GET_VAR '' type=A origin=null + FUN GENERATED_DATA_CLASS_MEMBER public final operator fun component1(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='component1(): Int' + CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + FUN GENERATED_DATA_CLASS_MEMBER public final operator fun component2(): kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='component2(): Int' + CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + FUN GENERATED_DATA_CLASS_MEMBER public final fun copy(x: kotlin.Int = ..., y: kotlin.Int = ...): A + x: EXPRESSION_BODY + CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + y: EXPRESSION_BODY + CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + BLOCK_BODY + RETURN type=kotlin.Nothing from='copy(Int = ..., Int = ...): A' + CALL 'constructor A(Int, Int)' type=A origin=null + x: GET_VAR 'value-parameter x: Int = ...' type=kotlin.Int origin=null + y: GET_VAR 'value-parameter y: Int = ...' type=kotlin.Int origin=null + FUN GENERATED_DATA_CLASS_MEMBER public open override fun toString(): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='toString(): String' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value='A(' + CONST String type=kotlin.String value='x=' + CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + CONST String type=kotlin.String value=', ' + CONST String type=kotlin.String value='y=' + CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + CONST String type=kotlin.String value=')' + FUN GENERATED_DATA_CLASS_MEMBER public open override fun hashCode(): kotlin.Int + BLOCK_BODY + VAR IR_TEMPORARY_VARIABLE var tmp0_result: kotlin.Int + CONST Int type=kotlin.Int value='0' + SET_VAR 'tmp0_result: Int' type=kotlin.Unit origin=EQ + CALL 'hashCode(): Int' type=kotlin.Int origin=null + $this: CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + SET_VAR 'tmp0_result: Int' type=kotlin.Unit origin=EQ + CALL 'plus(Int): Int' type=kotlin.Int origin=null + $this: CALL 'times(Int): Int' type=kotlin.Int origin=null + $this: GET_VAR 'tmp0_result: Int' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value='31' + other: CALL 'hashCode(): Int' type=kotlin.Int origin=null + $this: CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + RETURN type=kotlin.Nothing from='hashCode(): Int' + GET_VAR 'tmp0_result: Int' type=kotlin.Int origin=null + FUN GENERATED_DATA_CLASS_MEMBER public open override fun equals(other: kotlin.Any?): kotlin.Boolean + BLOCK_BODY + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'EQEQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQEQ + arg0: GET_VAR '' type=A origin=null + arg1: GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value='true' + WHEN type=kotlin.Unit origin=null + BRANCH + if: TYPE_OP origin=NOT_INSTANCEOF typeOperand=A + GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value='false' + VAR IR_TEMPORARY_VARIABLE val tmp0_other_with_cast: A + TYPE_OP origin=CAST typeOperand=A + GET_VAR 'value-parameter other: Any?' type=kotlin.Any? origin=null + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + arg1: CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR 'tmp0_other_with_cast: A' type=A origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value='false' + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '' type=A origin=null + arg1: CALL '(): Int' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR 'tmp0_other_with_cast: A' type=A origin=null + then: RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value='false' + RETURN type=kotlin.Nothing from='equals(Any?): Boolean' + CONST Boolean type=kotlin.Boolean value='true' + PROPERTY public var fn: (A) -> kotlin.Int + FIELD PROPERTY_BACKING_FIELD public var fn: (A) -> kotlin.Int + EXPRESSION_BODY + BLOCK type=(A) -> kotlin.Int origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA local final fun (: A): kotlin.Int + BLOCK_BODY + VAR val y: kotlin.Int + CALL 'component2(): Int' type=kotlin.Int origin=COMPONENT_N(index=2) + $this: GET_VAR 'value-parameter : A' type=A origin=DESTRUCTURING_DECLARATION + RETURN type=kotlin.Nothing from='(A): Int' + CALL 'plus(Int): Int' type=kotlin.Int origin=PLUS + $this: CONST Int type=kotlin.Int value='42' + other: GET_VAR 'y: Int' type=kotlin.Int origin=null + CALLABLE_REFERENCE '(A): Int' type=(A) -> kotlin.Int origin=LAMBDA + FUN DEFAULT_PROPERTY_ACCESSOR public fun (): (A) -> kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): (A) -> Int' + GET_FIELD 'fn: (A) -> Int' type=(A) -> kotlin.Int origin=null + FUN DEFAULT_PROPERTY_ACCESSOR public fun (: (A) -> kotlin.Int): kotlin.Unit + BLOCK_BODY + SET_FIELD 'fn: (A) -> Int' type=kotlin.Unit origin=null + value: GET_VAR 'value-parameter : (A) -> Int' type=(A) -> kotlin.Int origin=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index c83f46b55b4..593f9ceb262 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -785,6 +785,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("destructuringInLambda.kt") + public void testDestructuringInLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/destructuringInLambda.kt"); + doTest(fileName); + } + @TestMetadata("extensionLambda.kt") public void testExtensionLambda() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/extensionLambda.kt");