FIR: generate destructurings for more than one parameter

This commit is contained in:
pyos
2021-04-07 09:50:15 +02:00
committed by Mikhail Glukhikh
parent 4df5dcdf75
commit 1b1949d242
13 changed files with 124 additions and 40 deletions
@@ -521,6 +521,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/definetelyNotNullForTypeParameter.kt"); runTest("compiler/fir/analysis-tests/testData/resolve/arguments/definetelyNotNullForTypeParameter.kt");
} }
@TestMetadata("destructuring.kt")
public void testDestructuring() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.kt");
}
@TestMetadata("extensionLambdaInDefaultArgument.kt") @TestMetadata("extensionLambdaInDefaultArgument.kt")
public void testExtensionLambdaInDefaultArgument() throws Exception { public void testExtensionLambdaInDefaultArgument() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/extensionLambdaInDefaultArgument.kt"); runTest("compiler/fir/analysis-tests/testData/resolve/arguments/extensionLambdaInDefaultArgument.kt");
@@ -0,0 +1,69 @@
FILE: destructuring.kt
public final data class C : R|kotlin/Any| {
public constructor(x: R|kotlin/Int|, y: R|kotlin/String|): R|C| {
super<R|kotlin/Any|>()
}
public final val x: R|kotlin/Int| = R|<local>/x|
public get(): R|kotlin/Int|
public final val y: R|kotlin/String| = R|<local>/y|
public get(): R|kotlin/String|
public final operator fun component1(): R|kotlin/Int|
public final operator fun component2(): R|kotlin/String|
public final fun copy(x: R|kotlin/Int| = this@R|/C|.R|/C.x|, y: R|kotlin/String| = this@R|/C|.R|/C.y|): R|C|
}
public final fun foo1(block: R|(C) -> kotlin/Unit|): R|kotlin/Unit| {
^foo1 R|<local>/block|.R|SubstitutionOverride<kotlin/Function1.invoke: R|kotlin/Unit|>|(R|/C.C|(Int(0), String()))
}
public final fun foo2(block: R|(C, C) -> kotlin/Unit|): R|kotlin/Unit| {
^foo2 R|<local>/block|.R|SubstitutionOverride<kotlin/Function2.invoke: R|kotlin/Unit|>|(R|/C.C|(Int(0), String()), R|/C.C|(Int(0), String()))
}
public final fun test(): R|kotlin/Unit| {
R|/foo1|(<L> = foo1@fun <anonymous>(<destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
R|/C.C|(R|<local>/x|, R|<local>/y|)
}
)
R|/foo1|(<L> = foo1@fun <anonymous>(<destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
R|/C.C|(R|<local>/x|, R|<local>/y|)
}
)
R|/foo1|(<L> = foo1@fun <anonymous>(<destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
lval x: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component1|()
lval y: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component2|()
<Inapplicable(INAPPLICABLE): /C.C>#(R|<local>/x|, R|<local>/y|)
}
)
R|/foo2|(<L> = foo2@fun <anonymous>(<destruct>: R|C|, <destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
lval z: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
lval w: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
R|/C.C|(R|<local>/x|.R|kotlin/Int.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/String.plus|(R|<local>/w|))
}
)
R|/foo2|(<L> = foo2@fun <anonymous>(<destruct>: R|C|, <destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
lval x: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
lval y: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
lval z: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component1|()
lval w: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component2|()
R|/C.C|(R|<local>/x|.R|kotlin/Int.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/String.plus|(R|<local>/w|))
}
)
R|/foo2|(<L> = foo2@fun <anonymous>(<destruct>: R|C|, <destruct>: R|C|): R|kotlin/Unit| <inline=NoInline> {
lval x: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component1|()
lval y: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component2|()
lval z: R|kotlin/String| = R|<local>/<destruct>|.R|/C.component1|()
lval w: R|kotlin/Int| = R|<local>/<destruct>|.R|/C.component2|()
<Inapplicable(INAPPLICABLE): /C.C>#(R|<local>/x|.R|kotlin/String.plus|(R|<local>/z|), R|<local>/y|.R|kotlin/Int.plus|(R|<local>/w|))
}
)
}
@@ -0,0 +1,13 @@
data class C(val x: Int, val y: String)
fun foo1(block: (C) -> Unit) = block(C(0, ""))
fun foo2(block: (C, C) -> Unit) = block(C(0, ""), C(0, ""))
fun test() {
foo1 { (x, y) -> C(x, y) }
foo1 { (x: Int, y: String) -> C(x, y) }
foo1 { (x: String, y: Int) -> <!INAPPLICABLE_CANDIDATE!>C<!>(x, y) }
foo2 { (x, y), (z, w) -> C(x + z, y + w) }
foo2 { (x: Int, y: String), (z: Int, w: String) -> C(x + z, y + w) }
foo2 { (x: String, y: Int), (z: String, w: Int) -> <!INAPPLICABLE_CANDIDATE!>C<!>(x + z, y + w) }
}
@@ -611,6 +611,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/definetelyNotNullForTypeParameter.kt"); runTest("compiler/fir/analysis-tests/testData/resolve/arguments/definetelyNotNullForTypeParameter.kt");
} }
@Test
@TestMetadata("destructuring.kt")
public void testDestructuring() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.kt");
}
@Test @Test
@TestMetadata("extensionLambdaInDefaultArgument.kt") @TestMetadata("extensionLambdaInDefaultArgument.kt")
public void testExtensionLambdaInDefaultArgument() throws Exception { public void testExtensionLambdaInDefaultArgument() throws Exception {
@@ -615,6 +615,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/definetelyNotNullForTypeParameter.kt"); runTest("compiler/fir/analysis-tests/testData/resolve/arguments/definetelyNotNullForTypeParameter.kt");
} }
@Test
@TestMetadata("destructuring.kt")
public void testDestructuring() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.kt");
}
@Test @Test
@TestMetadata("extensionLambdaInDefaultArgument.kt") @TestMetadata("extensionLambdaInDefaultArgument.kt")
public void testExtensionLambdaInDefaultArgument() throws Exception { public void testExtensionLambdaInDefaultArgument() throws Exception {
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.builder.* import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration
@@ -106,7 +107,7 @@ fun generateDestructuringBlock(
multiDeclaration: DestructuringDeclaration, multiDeclaration: DestructuringDeclaration,
container: FirVariable<*>, container: FirVariable<*>,
tmpVariable: Boolean tmpVariable: Boolean
): FirExpression { ): FirBlock {
return buildBlock { return buildBlock {
if (tmpVariable) { if (tmpVariable) {
statements += container statements += container
@@ -147,7 +147,7 @@ class ExpressionsConverter(
} }
target = FirFunctionTarget(labelName = label?.name, isLambda = true) target = FirFunctionTarget(labelName = label?.name, isLambda = true)
context.firFunctionTargets += target context.firFunctionTargets += target
var destructuringBlock: FirExpression? = null val destructuringStatements = mutableListOf<FirStatement>()
for (valueParameter in valueParameterList) { for (valueParameter in valueParameterList) {
val multiDeclaration = valueParameter.destructuringDeclaration val multiDeclaration = valueParameter.destructuringDeclaration
valueParameters += if (multiDeclaration != null) { valueParameters += if (multiDeclaration != null) {
@@ -163,12 +163,12 @@ class ExpressionsConverter(
isNoinline = false isNoinline = false
isVararg = false isVararg = false
} }
destructuringBlock = generateDestructuringBlock( destructuringStatements += generateDestructuringBlock(
this@ExpressionsConverter.baseSession, this@ExpressionsConverter.baseSession,
multiDeclaration, multiDeclaration,
multiParameter, multiParameter,
tmpVariable = false tmpVariable = false
) ).statements
multiParameter multiParameter
} else { } else {
valueParameter.firValueParameter valueParameter.firValueParameter
@@ -187,11 +187,7 @@ class ExpressionsConverter(
} }
) )
} }
if (destructuringBlock is FirBlock) { statements.addAll(0, destructuringStatements)
for ((index, statement) in destructuringBlock.statements.withIndex()) {
statements.add(index, statement)
}
}
}.build() }.build()
} }
} else { } else {
@@ -989,11 +985,7 @@ class ExpressionsConverter(
firLoopParameter, firLoopParameter,
tmpVariable = true tmpVariable = true
) )
if (destructuringBlock is FirBlock) { statements.addAll(0, destructuringBlock.statements)
for ((index, statement) in destructuringBlock.statements.withIndex()) {
statements.add(index, statement)
}
}
} else { } else {
statements.add(0, firLoopParameter) statements.add(0, firLoopParameter)
} }
@@ -88,7 +88,7 @@ internal fun generateDestructuringBlock(
tmpVariable: Boolean, tmpVariable: Boolean,
extractAnnotationsTo: KtAnnotated.(FirAnnotationContainerBuilder) -> Unit, extractAnnotationsTo: KtAnnotated.(FirAnnotationContainerBuilder) -> Unit,
toFirOrImplicitTypeRef: KtTypeReference?.() -> FirTypeRef, toFirOrImplicitTypeRef: KtTypeReference?.() -> FirTypeRef,
): FirExpression { ): FirBlock {
return buildBlock { return buildBlock {
source = multiDeclaration.toFirPsiSourceElement() source = multiDeclaration.toFirPsiSourceElement()
if (tmpVariable) { if (tmpVariable) {
@@ -1069,7 +1069,7 @@ open class RawFirBuilder(
symbol = FirAnonymousFunctionSymbol() symbol = FirAnonymousFunctionSymbol()
isLambda = true isLambda = true
var destructuringBlock: FirExpression? = null val destructuringStatements = mutableListOf<FirStatement>()
for (valueParameter in literal.valueParameters) { for (valueParameter in literal.valueParameters) {
val multiDeclaration = valueParameter.destructuringDeclaration val multiDeclaration = valueParameter.destructuringDeclaration
valueParameters += if (multiDeclaration != null) { valueParameters += if (multiDeclaration != null) {
@@ -1087,13 +1087,13 @@ open class RawFirBuilder(
isNoinline = false isNoinline = false
isVararg = false isVararg = false
} }
destructuringBlock = generateDestructuringBlock( destructuringStatements += generateDestructuringBlock(
baseSession, baseSession,
multiDeclaration, multiDeclaration,
multiParameter, multiParameter,
tmpVariable = false, tmpVariable = false,
extractAnnotationsTo = { extractAnnotationsTo(it) }, extractAnnotationsTo = { extractAnnotationsTo(it) },
) { toFirOrImplicitType() } ) { toFirOrImplicitType() }.statements
multiParameter multiParameter
} else { } else {
val typeRef = valueParameter.typeReference?.convertSafe() ?: buildImplicitTypeRef { val typeRef = valueParameter.typeReference?.convertSafe() ?: buildImplicitTypeRef {
@@ -1129,11 +1129,7 @@ open class RawFirBuilder(
} }
) )
} }
if (destructuringBlock is FirBlock) { statements.addAll(0, destructuringStatements)
for ((index, statement) in destructuringBlock.statements.withIndex()) {
statements.add(index, statement)
}
}
}.build() }.build()
} }
context.firFunctionTargets.removeLast() context.firFunctionTargets.removeLast()
@@ -1742,11 +1738,7 @@ open class RawFirBuilder(
tmpVariable = true, tmpVariable = true,
extractAnnotationsTo = { extractAnnotationsTo(it) }, extractAnnotationsTo = { extractAnnotationsTo(it) },
) { toFirOrImplicitType() } ) { toFirOrImplicitType() }
if (destructuringBlock is FirBlock) { blockBuilder.statements.addAll(0, destructuringBlock.statements)
for ((index, statement) in destructuringBlock.statements.withIndex()) {
blockBuilder.statements.add(index, statement)
}
}
} else { } else {
blockBuilder.statements.add(0, firLoopParameter) blockBuilder.statements.add(0, firLoopParameter)
} }
@@ -24,24 +24,24 @@ fun bar(aInstance: A, bInstance: B) {
foo(bInstance) { foo(bInstance) {
(a, b): A, (c, d) -> (a, b): A, (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() } a checkType { _<Int>() }
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() } b checkType { _<String>() }
c checkType { _<Double>() } c checkType { _<Double>() }
d checkType { _<Short>() } d checkType { _<Short>() }
} }
foo(bInstance) { foo(bInstance) {
(a, b), (c, d) -> <!COMPONENT_FUNCTION_MISSING, COMPONENT_FUNCTION_MISSING!>(a, b)<!>, (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() } a <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() }
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() } b <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
c checkType { _<Double>() } c checkType { _<Double>() }
d checkType { _<Short>() } d checkType { _<Short>() }
} }
foo<A, B>(bInstance) { foo<A, B>(bInstance) {
(a, b), (c, d) -> (a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() } a checkType { _<Int>() }
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() } b checkType { _<String>() }
c checkType { _<Double>() } c checkType { _<Double>() }
d checkType { _<Short>() } d checkType { _<Short>() }
} }
@@ -23,7 +23,7 @@ fun bar() {
} }
foo { (a, b), (c, b) -> foo { (a, b), (c, b) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() } a checkType { _<Int>() }
b checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() } b checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
c checkType { <!INAPPLICABLE_CANDIDATE!>_<!><B>() } c checkType { <!INAPPLICABLE_CANDIDATE!>_<!><B>() }
} }
@@ -36,8 +36,8 @@ fun bar() {
} }
foobar { (a, b), (c, d) -> foobar { (a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() } a checkType { _<Int>() }
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() } b checkType { _<String>() }
c checkType { _<Double>() } c checkType { _<Double>() }
d checkType { _<Short>() } d checkType { _<Short>() }
} }
@@ -32,12 +32,12 @@ fun bar() {
} }
foobar { (a, b), (c, d) -> foobar { (a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() } a checkType { _<Int>() }
d checkType { _<Short>() } d checkType { _<Short>() }
} }
foobar { (a, b), (c, d) -> foobar { (a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() } b checkType { _<String>() }
c checkType { _<Double>() } c checkType { _<Double>() }
} }
} }