From 489c9ae11f614f1eac75fdffe180b85a0dde1b61 Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Mon, 25 Oct 2021 14:19:13 +0300 Subject: [PATCH] [FIR2IR] Recognize postfix inc/dec blocks in sequence of statements --- .../kotlin/fir/backend/Fir2IrVisitor.kt | 90 +++++++++++++------ .../irText/lambdas/localFunction.fir.ir.txt | 13 +-- .../irText/lambdas/localFunction.fir.kt.txt | 9 +- .../regressions/coercionInLoop.fir.ir.txt | 13 +-- .../regressions/coercionInLoop.fir.kt.txt | 9 +- 5 files changed, 89 insertions(+), 45 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index a044dce0781..38b965e0aa8 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -542,8 +542,56 @@ class Fir2IrVisitor( } } - private fun List.mapToIrStatements(): List { - return map { it.toIrStatement() } + private fun List.mapToIrStatements(recognizePostfixIncDec: Boolean = true): List { + var index = 0 + val result = ArrayList(size) + while (index < size) { + var irStatement: IrStatement? = null + if (recognizePostfixIncDec) { + val statementsOrigin = getStatementsOrigin(index) + if (statementsOrigin != null) { + val subStatements = this.subList(index, index + 3).mapNotNull { it.toIrStatement() } + irStatement = IrBlockImpl( + subStatements[0].startOffset, + subStatements[2].endOffset, + (subStatements[0] as IrVariable).type, + statementsOrigin, + subStatements + ) + index += 3 + } + } + + if (irStatement == null) { + irStatement = this[index].toIrStatement() + index++ + } + result.add(irStatement) + } + + return result + } + + private fun List.getStatementsOrigin(index: Int): IrStatementOrigin? { + if (index + 3 > size) return null + + val statement0 = this[index] + if (statement0 !is FirProperty || !statement0.isLocal) return null + val unarySymbol = statement0.symbol + if (unarySymbol.callableId.callableName != SpecialNames.UNARY) return null + val variable = statement0.initializer?.toResolvedCallableSymbol() ?: return null + + val statement2 = this[index + 2] + if (statement2 !is FirPropertyAccessExpression) return null + if (statement2.calleeReference.toResolvedCallableSymbol() != unarySymbol) return null + + val incrementStatement = this[index + 1] + if (incrementStatement !is FirVariableAssignment) return null + + if (incrementStatement.lValue.toResolvedCallableSymbol() != variable) return null + + val origin = incrementStatement.getIrAssignmentOrigin() + return if (origin == IrStatementOrigin.EQ) null else origin } internal fun convertToIrBlockBody(block: FirBlock): IrBlockBody { @@ -591,37 +639,25 @@ class Fir2IrVisitor( else (lastOrNull() as? FirExpression)?.typeRef?.toIrType() ?: irBuiltIns.unitType return source.convertWithOffsets { startOffset, endOffset -> - val itStatements = mapToIrStatements().filterNotNull() if (origin == IrStatementOrigin.DO_WHILE_LOOP) { - IrCompositeImpl(startOffset, endOffset, type, origin, itStatements) + IrCompositeImpl( + startOffset, endOffset, type, origin, + mapToIrStatements(recognizePostfixIncDec = false).filterNotNull() + ) } else { - IrBlockImpl(startOffset, endOffset, type, getStatementsOrigin() ?: origin, itStatements) + val irStatements = mapToIrStatements() + val singleStatement = irStatements.singleOrNull() + if (singleStatement is IrBlock && + (singleStatement.origin == IrStatementOrigin.POSTFIX_INCR || singleStatement.origin == IrStatementOrigin.POSTFIX_DECR) + ) { + singleStatement + } else { + IrBlockImpl(startOffset, endOffset, type, origin, irStatements.filterNotNull()) + } } } } - private fun List.getStatementsOrigin(): IrStatementOrigin? { - if (size != 3) return null - - val statement0 = this[0] - if (statement0 !is FirProperty || !statement0.isLocal) return null - val unarySymbol = statement0.symbol - if (unarySymbol.callableId.callableName != SpecialNames.UNARY) return null - - val statement2 = this[2] - if (statement2 !is FirPropertyAccessExpression) return null - if (statement2.calleeReference.toResolvedCallableSymbol() != unarySymbol) return null - - val incrementStatement = this[1] - if (incrementStatement !is FirVariableAssignment) return null - - val variable = statement0.initializer?.toResolvedCallableSymbol() ?: return null - if (incrementStatement.lValue.toResolvedCallableSymbol() != variable) return null - - val origin = incrementStatement.getIrAssignmentOrigin() - return if (origin == IrStatementOrigin.EQ) null else origin - } - override fun visitErrorExpression(errorExpression: FirErrorExpression, data: Any?): IrElement { return errorExpression.convertWithOffsets { startOffset, endOffset -> IrErrorExpressionImpl( diff --git a/compiler/testData/ir/irText/lambdas/localFunction.fir.ir.txt b/compiler/testData/ir/irText/lambdas/localFunction.fir.ir.txt index 9e75ddd7bde..9d93d67ddce 100644 --- a/compiler/testData/ir/irText/lambdas/localFunction.fir.ir.txt +++ b/compiler/testData/ir/irText/lambdas/localFunction.fir.ir.txt @@ -5,11 +5,12 @@ FILE fqName: fileName:/localFunction.kt CONST Int type=kotlin.Int value=0 FUN LOCAL_FUNCTION name:local visibility:local modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY - VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val] - GET_VAR 'var x: kotlin.Int [var] declared in .outer' type=kotlin.Int origin=null - SET_VAR 'var x: kotlin.Int [var] declared in .outer' type=kotlin.Unit origin=POSTFIX_INCR - CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null - $this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in .outer.local' type=kotlin.Int origin=null TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit - GET_VAR 'val tmp_0: kotlin.Int [val] declared in .outer.local' type=kotlin.Int origin=null + BLOCK type=kotlin.Int origin=POSTFIX_INCR + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val] + GET_VAR 'var x: kotlin.Int [var] declared in .outer' type=kotlin.Int origin=null + SET_VAR 'var x: kotlin.Int [var] declared in .outer' type=kotlin.Unit origin=POSTFIX_INCR + CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null + $this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in .outer.local' type=kotlin.Int origin=null + GET_VAR 'val tmp_0: kotlin.Int [val] declared in .outer.local' type=kotlin.Int origin=null CALL 'local final fun local (): kotlin.Unit declared in .outer' type=kotlin.Unit origin=null diff --git a/compiler/testData/ir/irText/lambdas/localFunction.fir.kt.txt b/compiler/testData/ir/irText/lambdas/localFunction.fir.kt.txt index 051571a5ade..4f154b37814 100644 --- a/compiler/testData/ir/irText/lambdas/localFunction.fir.kt.txt +++ b/compiler/testData/ir/irText/lambdas/localFunction.fir.kt.txt @@ -1,10 +1,13 @@ fun outer() { var x: Int = 0 local fun local() { - val : Int = x - x = .inc() - /*~> Unit */ + { // BLOCK + val : Int = x + x = .inc() + + } /*~> Unit */ } local() } + diff --git a/compiler/testData/ir/irText/regressions/coercionInLoop.fir.ir.txt b/compiler/testData/ir/irText/regressions/coercionInLoop.fir.ir.txt index f25522f3895..d2164bf112e 100644 --- a/compiler/testData/ir/irText/regressions/coercionInLoop.fir.ir.txt +++ b/compiler/testData/ir/irText/regressions/coercionInLoop.fir.ir.txt @@ -26,11 +26,12 @@ FILE fqName: fileName:/coercionInLoop.kt STRING_CONCATENATION type=kotlin.String CONST String type=kotlin.String value="Fail " GET_VAR 'var i: kotlin.Int [var] declared in .box' type=kotlin.Int origin=null - VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val] - GET_VAR 'var i: kotlin.Int [var] declared in .box' type=kotlin.Int origin=null - SET_VAR 'var i: kotlin.Int [var] declared in .box' type=kotlin.Unit origin=POSTFIX_INCR - CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null - $this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in .box' type=kotlin.Int origin=null - GET_VAR 'val tmp_0: kotlin.Int [val] declared in .box' type=kotlin.Int origin=null + BLOCK type=kotlin.Int origin=POSTFIX_INCR + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.Int [val] + GET_VAR 'var i: kotlin.Int [var] declared in .box' type=kotlin.Int origin=null + SET_VAR 'var i: kotlin.Int [var] declared in .box' type=kotlin.Unit origin=POSTFIX_INCR + CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null + $this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in .box' type=kotlin.Int origin=null + GET_VAR 'val tmp_0: kotlin.Int [val] declared in .box' type=kotlin.Int origin=null RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' CONST String type=kotlin.String value="OK" diff --git a/compiler/testData/ir/irText/regressions/coercionInLoop.fir.kt.txt b/compiler/testData/ir/irText/regressions/coercionInLoop.fir.kt.txt index 72e73ae7056..19064af1694 100644 --- a/compiler/testData/ir/irText/regressions/coercionInLoop.fir.kt.txt +++ b/compiler/testData/ir/irText/regressions/coercionInLoop.fir.kt.txt @@ -6,9 +6,12 @@ fun box(): String { when { ieee754equals(arg0 = a.get(index = i), arg1 = x.next()).not() -> return "Fail " + i } - val : Int = i - i = .inc() - + { // BLOCK + val : Int = i + i = .inc() + + } } return "OK" } +