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");
}
@TestMetadata("destructuring.kt")
public void testDestructuring() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.kt");
}
@TestMetadata("extensionLambdaInDefaultArgument.kt")
public void testExtensionLambdaInDefaultArgument() throws Exception {
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");
}
@Test
@TestMetadata("destructuring.kt")
public void testDestructuring() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/destructuring.kt");
}
@Test
@TestMetadata("extensionLambdaInDefaultArgument.kt")
public void testExtensionLambdaInDefaultArgument() throws Exception {
@@ -615,6 +615,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
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
@TestMetadata("extensionLambdaInDefaultArgument.kt")
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.builder.buildProperty
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.builder.*
import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration
@@ -106,7 +107,7 @@ fun generateDestructuringBlock(
multiDeclaration: DestructuringDeclaration,
container: FirVariable<*>,
tmpVariable: Boolean
): FirExpression {
): FirBlock {
return buildBlock {
if (tmpVariable) {
statements += container
@@ -147,7 +147,7 @@ class ExpressionsConverter(
}
target = FirFunctionTarget(labelName = label?.name, isLambda = true)
context.firFunctionTargets += target
var destructuringBlock: FirExpression? = null
val destructuringStatements = mutableListOf<FirStatement>()
for (valueParameter in valueParameterList) {
val multiDeclaration = valueParameter.destructuringDeclaration
valueParameters += if (multiDeclaration != null) {
@@ -163,12 +163,12 @@ class ExpressionsConverter(
isNoinline = false
isVararg = false
}
destructuringBlock = generateDestructuringBlock(
destructuringStatements += generateDestructuringBlock(
this@ExpressionsConverter.baseSession,
multiDeclaration,
multiParameter,
tmpVariable = false
)
).statements
multiParameter
} else {
valueParameter.firValueParameter
@@ -187,11 +187,7 @@ class ExpressionsConverter(
}
)
}
if (destructuringBlock is FirBlock) {
for ((index, statement) in destructuringBlock.statements.withIndex()) {
statements.add(index, statement)
}
}
statements.addAll(0, destructuringStatements)
}.build()
}
} else {
@@ -989,11 +985,7 @@ class ExpressionsConverter(
firLoopParameter,
tmpVariable = true
)
if (destructuringBlock is FirBlock) {
for ((index, statement) in destructuringBlock.statements.withIndex()) {
statements.add(index, statement)
}
}
statements.addAll(0, destructuringBlock.statements)
} else {
statements.add(0, firLoopParameter)
}
@@ -88,7 +88,7 @@ internal fun generateDestructuringBlock(
tmpVariable: Boolean,
extractAnnotationsTo: KtAnnotated.(FirAnnotationContainerBuilder) -> Unit,
toFirOrImplicitTypeRef: KtTypeReference?.() -> FirTypeRef,
): FirExpression {
): FirBlock {
return buildBlock {
source = multiDeclaration.toFirPsiSourceElement()
if (tmpVariable) {
@@ -1069,7 +1069,7 @@ open class RawFirBuilder(
symbol = FirAnonymousFunctionSymbol()
isLambda = true
var destructuringBlock: FirExpression? = null
val destructuringStatements = mutableListOf<FirStatement>()
for (valueParameter in literal.valueParameters) {
val multiDeclaration = valueParameter.destructuringDeclaration
valueParameters += if (multiDeclaration != null) {
@@ -1087,13 +1087,13 @@ open class RawFirBuilder(
isNoinline = false
isVararg = false
}
destructuringBlock = generateDestructuringBlock(
destructuringStatements += generateDestructuringBlock(
baseSession,
multiDeclaration,
multiParameter,
tmpVariable = false,
extractAnnotationsTo = { extractAnnotationsTo(it) },
) { toFirOrImplicitType() }
) { toFirOrImplicitType() }.statements
multiParameter
} else {
val typeRef = valueParameter.typeReference?.convertSafe() ?: buildImplicitTypeRef {
@@ -1129,11 +1129,7 @@ open class RawFirBuilder(
}
)
}
if (destructuringBlock is FirBlock) {
for ((index, statement) in destructuringBlock.statements.withIndex()) {
statements.add(index, statement)
}
}
statements.addAll(0, destructuringStatements)
}.build()
}
context.firFunctionTargets.removeLast()
@@ -1742,11 +1738,7 @@ open class RawFirBuilder(
tmpVariable = true,
extractAnnotationsTo = { extractAnnotationsTo(it) },
) { toFirOrImplicitType() }
if (destructuringBlock is FirBlock) {
for ((index, statement) in destructuringBlock.statements.withIndex()) {
blockBuilder.statements.add(index, statement)
}
}
blockBuilder.statements.addAll(0, destructuringBlock.statements)
} else {
blockBuilder.statements.add(0, firLoopParameter)
}
@@ -24,24 +24,24 @@ fun bar(aInstance: A, bInstance: B) {
foo(bInstance) {
(a, b): A, (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() }
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
a checkType { _<Int>() }
b checkType { _<String>() }
c checkType { _<Double>() }
d checkType { _<Short>() }
}
foo(bInstance) {
(a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() }
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
<!COMPONENT_FUNCTION_MISSING, COMPONENT_FUNCTION_MISSING!>(a, b)<!>, (c, d) ->
a <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() }
b <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
c checkType { _<Double>() }
d checkType { _<Short>() }
}
foo<A, B>(bInstance) {
(a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() }
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
a checkType { _<Int>() }
b checkType { _<String>() }
c checkType { _<Double>() }
d checkType { _<Short>() }
}
@@ -23,7 +23,7 @@ fun bar() {
}
foo { (a, b), (c, b) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() }
a checkType { _<Int>() }
b checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
c checkType { <!INAPPLICABLE_CANDIDATE!>_<!><B>() }
}
@@ -36,8 +36,8 @@ fun bar() {
}
foobar { (a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() }
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
a checkType { _<Int>() }
b checkType { _<String>() }
c checkType { _<Double>() }
d checkType { _<Short>() }
}
@@ -32,12 +32,12 @@ fun bar() {
}
foobar { (a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>a<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Int>() }
a checkType { _<Int>() }
d checkType { _<Short>() }
}
foobar { (a, b), (c, d) ->
<!UNRESOLVED_REFERENCE!>b<!> checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() }
b checkType { _<String>() }
c checkType { _<Double>() }
}
}