PSI2IR: do not generate when subjects multiple times

`in x` is represented as `<subject expression> in x` in psi, so
generating the entire call and then replacing the argument with a read
of a temporary results in redundant regenerations of the subject.

 #KT-42054 Fixed
 #KT-42455 Fixed
This commit is contained in:
pyos
2020-10-07 12:46:07 +02:00
committed by Dmitry Petrov
parent e280416fe2
commit 98088f739d
10 changed files with 63 additions and 17 deletions
@@ -5667,6 +5667,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/controlStructures/kt416.kt");
}
@TestMetadata("kt42455.kt")
public void testKt42455() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt42455.kt");
}
@TestMetadata("kt513.kt")
public void testKt513() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt513.kt");
@@ -473,13 +473,19 @@ fun Generator.getSuperQualifier(resolvedCall: ResolvedCall<*>): ClassDescriptor?
return getOrFail(BindingContext.REFERENCE_TARGET, superCallExpression.instanceReference) as ClassDescriptor
}
fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>): CallBuilder {
fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>): CallBuilder =
pregenerateCallUsing(resolvedCall) { generateExpression(it) }
fun StatementGenerator.pregenerateCallUsing(
resolvedCall: ResolvedCall<*>,
generateArgumentExpression: (KtExpression) -> IrExpression?
): CallBuilder {
if (resolvedCall.isExtensionInvokeCall()) {
return pregenerateExtensionInvokeCall(resolvedCall)
}
val call = pregenerateCallReceivers(resolvedCall)
pregenerateValueArguments(call, resolvedCall)
pregenerateValueArgumentsUsing(call, resolvedCall, generateArgumentExpression)
generateSamConversionForValueArgumentsIfRequired(call, resolvedCall)
return call
}
@@ -562,14 +568,6 @@ private fun ResolvedCall<*>.isExtensionInvokeCall(): Boolean {
return extensionReceiver != null
}
private fun StatementGenerator.pregenerateValueArguments(call: CallBuilder, resolvedCall: ResolvedCall<*>) {
pregenerateValueArgumentsUsing(call, resolvedCall) {
generateExpression(it)
}
generateSamConversionForValueArgumentsIfRequired(call, resolvedCall)
}
fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: CallBuilder, resolvedCall: ResolvedCall<*>) {
val samConversion = context.extensions.samConversion
@@ -113,7 +113,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
for (ktCondition in ktEntry.conditions) {
val irCondition =
if (irSubject != null)
generateWhenConditionWithSubject(ktCondition, irSubject)
generateWhenConditionWithSubject(ktCondition, irSubject, expression.subjectExpression)
else
generateWhenConditionNoSubject(ktCondition)
irBranchCondition = irBranchCondition?.let { context.whenComma(it, irCondition) } ?: irCondition
@@ -190,12 +190,14 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
private fun generateWhenConditionNoSubject(ktCondition: KtWhenCondition): IrExpression =
(ktCondition as KtWhenConditionWithExpression).expression!!.genExpr()
private fun generateWhenConditionWithSubject(ktCondition: KtWhenCondition, irSubject: IrVariable): IrExpression {
private fun generateWhenConditionWithSubject(
ktCondition: KtWhenCondition, irSubject: IrVariable, ktSubject: KtExpression?
): IrExpression {
return when (ktCondition) {
is KtWhenConditionWithExpression ->
generateEqualsCondition(irSubject, ktCondition)
is KtWhenConditionInRange ->
generateInRangeCondition(irSubject, ktCondition)
generateInCondition(irSubject, ktCondition, ktSubject)
is KtWhenConditionIsPattern ->
generateIsPatternCondition(irSubject, ktCondition)
else ->
@@ -227,11 +229,13 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
irInstanceOf
}
private fun generateInRangeCondition(irSubject: IrVariable, ktCondition: KtWhenConditionInRange): IrExpression {
val inCall = statementGenerator.pregenerateCall(getResolvedCall(ktCondition.operationReference)!!)
private fun generateInCondition(irSubject: IrVariable, ktCondition: KtWhenConditionInRange, ktSubject: KtExpression?): IrExpression {
val startOffset = ktCondition.startOffsetSkippingComments
val endOffset = ktCondition.endOffset
inCall.irValueArgumentsByIndex[0] = irSubject.loadAt(startOffset, startOffset)
val inCall = statementGenerator.pregenerateCallUsing(getResolvedCall(ktCondition.operationReference)!!) {
// In a `when` with a subject, `in x` is represented as `x.contains(<reference to subject expression>)`.
if (it === ktSubject) irSubject.loadAt(startOffset, startOffset) else statementGenerator.generateExpression(it)
}
val inOperator = getInfixOperator(ktCondition.operationReference.getReferencedNameElementType())
val irInCall = CallGenerator(statementGenerator).generateCall(ktCondition, inCall, inOperator)
return when (inOperator) {
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME
fun box(): String {
val xs = listOf(1, 2, 3)
return when (xs.first { it > 1 }) {
in xs -> "OK"
else -> "fail"
}
}
@@ -5702,6 +5702,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/controlStructures/kt416.kt");
}
@TestMetadata("kt42455.kt")
public void testKt42455() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt42455.kt");
}
@TestMetadata("kt513.kt")
public void testKt513() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt513.kt");
@@ -5702,6 +5702,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/controlStructures/kt416.kt");
}
@TestMetadata("kt42455.kt")
public void testKt42455() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt42455.kt");
}
@TestMetadata("kt513.kt")
public void testKt513() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt513.kt");
@@ -5667,6 +5667,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/controlStructures/kt416.kt");
}
@TestMetadata("kt42455.kt")
public void testKt42455() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt42455.kt");
}
@TestMetadata("kt513.kt")
public void testKt513() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt513.kt");
@@ -4572,6 +4572,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/controlStructures/kt416.kt");
}
@TestMetadata("kt42455.kt")
public void testKt42455() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt42455.kt");
}
@TestMetadata("kt513.kt")
public void testKt513() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt513.kt");
@@ -4572,6 +4572,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/controlStructures/kt416.kt");
}
@TestMetadata("kt42455.kt")
public void testKt42455() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt42455.kt");
}
@TestMetadata("kt513.kt")
public void testKt513() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt513.kt");
@@ -4572,6 +4572,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/controlStructures/kt416.kt");
}
@TestMetadata("kt42455.kt")
public void testKt42455() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt42455.kt");
}
@TestMetadata("kt513.kt")
public void testKt513() throws Exception {
runTest("compiler/testData/codegen/box/controlStructures/kt513.kt");