KT-16566 Support destructuring declarations for lambda parameter in psi2ir

This commit is contained in:
Dmitry Petrov
2017-03-01 14:39:57 +03:00
parent c226707a80
commit 9baaf607a3
5 changed files with 159 additions and 1 deletions
@@ -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()) {
@@ -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)
@@ -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);
}
@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");