KT-16566 Support destructuring declarations for lambda parameter in psi2ir
This commit is contained in:
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
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.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
@@ -71,6 +72,15 @@ class BodyGenerator(val scopeOwner: DeclarationDescriptor, override val context:
|
|||||||
|
|
||||||
val ktBody = ktFun.bodyExpression!!
|
val ktBody = ktFun.bodyExpression!!
|
||||||
val irBlockBody = IrBlockBodyImpl(ktBody.startOffset, ktBody.endOffset)
|
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) {
|
if (ktBody is KtBlockExpression) {
|
||||||
val ktBodyStatements = ktBody.statements
|
val ktBodyStatements = ktBody.statements
|
||||||
if (ktBodyStatements.isNotEmpty()) {
|
if (ktBodyStatements.isNotEmpty()) {
|
||||||
|
|||||||
+1
-1
@@ -105,7 +105,7 @@ class StatementGenerator(
|
|||||||
return irBlock
|
return irBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrContainerExpressionBase, containerValue: IntermediateValue) {
|
fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrStatementContainer, containerValue: IntermediateValue) {
|
||||||
val callGenerator = CallGenerator(this)
|
val callGenerator = CallGenerator(this)
|
||||||
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
|
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
|
||||||
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
|
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
data class A(val x: Int, val y: Int)
|
||||||
|
|
||||||
|
var fn: (A) -> Int = { (_, y) -> 42 + y }
|
||||||
@@ -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 <get-x>(): kotlin.Int
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<get-x>(): Int'
|
||||||
|
GET_FIELD 'x: Int' type=kotlin.Int origin=null
|
||||||
|
receiver: GET_VAR '<receiver: A>' 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 <get-y>(): kotlin.Int
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<get-y>(): Int'
|
||||||
|
GET_FIELD 'y: Int' type=kotlin.Int origin=null
|
||||||
|
receiver: GET_VAR '<receiver: A>' 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 '<get-x>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' 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 '<get-y>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' type=A origin=null
|
||||||
|
FUN GENERATED_DATA_CLASS_MEMBER public final fun copy(x: kotlin.Int = ..., y: kotlin.Int = ...): A
|
||||||
|
x: EXPRESSION_BODY
|
||||||
|
CALL '<get-x>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' type=A origin=null
|
||||||
|
y: EXPRESSION_BODY
|
||||||
|
CALL '<get-y>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' 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 '<get-x>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' type=A origin=null
|
||||||
|
CONST String type=kotlin.String value=', '
|
||||||
|
CONST String type=kotlin.String value='y='
|
||||||
|
CALL '<get-y>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' 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 '<get-x>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' 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 '<get-y>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' 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 '<receiver: A>' 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 '<get-x>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' type=A origin=null
|
||||||
|
arg1: CALL '<get-x>(): 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 '<get-y>(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||||
|
$this: GET_VAR '<receiver: A>' type=A origin=null
|
||||||
|
arg1: CALL '<get-y>(): 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 <anonymous>(<name for destructuring parameter 0>: 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 <name for destructuring parameter 0>: A' type=A origin=DESTRUCTURING_DECLARATION
|
||||||
|
RETURN type=kotlin.Nothing from='<anonymous>(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 '<anonymous>(A): Int' type=(A) -> kotlin.Int origin=LAMBDA
|
||||||
|
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-fn>(): (A) -> kotlin.Int
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<get-fn>(): (A) -> Int'
|
||||||
|
GET_FIELD 'fn: (A) -> Int' type=(A) -> kotlin.Int origin=null
|
||||||
|
FUN DEFAULT_PROPERTY_ACCESSOR public fun <set-fn>(<set-?>: (A) -> kotlin.Int): kotlin.Unit
|
||||||
|
BLOCK_BODY
|
||||||
|
SET_FIELD 'fn: (A) -> Int' type=kotlin.Unit origin=null
|
||||||
|
value: GET_VAR 'value-parameter <set-?>: (A) -> Int' type=(A) -> kotlin.Int origin=null
|
||||||
@@ -785,6 +785,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("extensionLambda.kt")
|
||||||
public void testExtensionLambda() throws Exception {
|
public void testExtensionLambda() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/extensionLambda.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/lambdas/extensionLambda.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user