From 572c0b2ade54e78bdbc72a718cacc8393f678692 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Thu, 18 Mar 2021 16:00:20 -0700 Subject: [PATCH] Raw FIR: make sure loop target preparation and loop configuration match by using the generated loop target during preparation in a message passing fashion --- .../lightTree/converter/ExpressionsConverter.kt | 15 +++++++++------ .../jetbrains/kotlin/fir/builder/RawFirBuilder.kt | 15 +++++++++------ .../kotlin/fir/builder/BaseFirBuilder.kt | 10 +++++++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index e3d7379623e..4881cde62e2 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -891,10 +891,11 @@ class ExpressionsConverter( var firCondition: FirExpression = buildErrorExpression(null, ConeSimpleDiagnostic("No condition in do-while loop", DiagnosticKind.Syntax)) + val target: FirLoopTarget return FirDoWhileLoopBuilder().apply { source = doWhileLoop.toFirSourceElement() // For break/continue in the do-while loop condition, prepare the loop target first so that it can refer to the same loop. - prepareTarget() + target = prepareTarget() doWhileLoop.forEachChildren { when (it.tokenType) { BODY -> block = it @@ -902,7 +903,7 @@ class ExpressionsConverter( } } condition = firCondition - }.configure { convertLoopBody(block) } + }.configure(target) { convertLoopBody(block) } } /** @@ -919,13 +920,14 @@ class ExpressionsConverter( } } + val target: FirLoopTarget return FirWhileLoopBuilder().apply { source = whileLoop.toFirSourceElement() condition = firCondition // break/continue in the while loop condition will refer to an outer loop if any. // So, prepare the loop target after building the condition. - prepareTarget() - }.configure { convertLoopBody(block) } + target = prepareTarget() + }.configure(target) { convertLoopBody(block) } } /** @@ -944,6 +946,7 @@ class ExpressionsConverter( } } + val target: FirLoopTarget return buildBlock { source = forLoop.toFirSourceElement() val iteratorVal = generateTemporaryVariable( @@ -962,8 +965,8 @@ class ExpressionsConverter( } // break/continue in the for loop condition will refer to an outer loop if any. // So, prepare the loop target after building the condition. - prepareTarget() - }.configure { + target = prepareTarget() + }.configure(target) { // NB: just body.toFirBlock() isn't acceptable here because we need to add some statements buildBlock block@{ source = blockNode?.toFirSourceElement() diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index a7fad763380..da8e9cbe50d 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -1650,28 +1650,31 @@ open class RawFirBuilder( } override fun visitDoWhileExpression(expression: KtDoWhileExpression, data: Unit): FirElement { + val target: FirLoopTarget return FirDoWhileLoopBuilder().apply { source = expression.toFirSourceElement() // For break/continue in the do-while loop condition, prepare the loop target first so that it can refer to the same loop. - prepareTarget() + target = prepareTarget() condition = expression.condition.toFirExpression("No condition in do-while loop") - }.configure { expression.body.toFirBlock() } + }.configure(target) { expression.body.toFirBlock() } } override fun visitWhileExpression(expression: KtWhileExpression, data: Unit): FirElement { + val target: FirLoopTarget return FirWhileLoopBuilder().apply { source = expression.toFirSourceElement() condition = expression.condition.toFirExpression("No condition in while loop") // break/continue in the while loop condition will refer to an outer loop if any. // So, prepare the loop target after building the condition. - prepareTarget() - }.configure { expression.body.toFirBlock() } + target = prepareTarget() + }.configure(target) { expression.body.toFirBlock() } } override fun visitForExpression(expression: KtForExpression, data: Unit?): FirElement { val rangeExpression = expression.loopRange.toFirExpression("No range in for loop") val ktParameter = expression.loopParameter val fakeSource = expression.toFirPsiSourceElement(FirFakeSourceElementKind.DesugaredForLoop) + val target: FirLoopTarget return buildBlock { source = fakeSource val rangeSource = expression.loopRange?.toFirSourceElement(FirFakeSourceElementKind.DesugaredForLoop) @@ -1699,8 +1702,8 @@ open class RawFirBuilder( } // break/continue in the for loop condition will refer to an outer loop if any. // So, prepare the loop target after building the condition. - prepareTarget() - }.configure { + target = prepareTarget() + }.configure(target) { // NB: just body.toFirBlock() isn't acceptable here because we need to add some statements val blockBuilder = when (val body = expression.body) { is KtBlockExpression -> configureBlockWithoutBuilding(body) diff --git a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt index 5166a183287..cf400220a78 100644 --- a/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt +++ b/compiler/fir/raw-fir/raw-fir.common/src/org/jetbrains/kotlin/fir/builder/BaseFirBuilder.kt @@ -216,16 +216,20 @@ abstract class BaseFirBuilder(val baseSession: FirSession, val context: Conte } } - fun FirLoopBuilder.prepareTarget() { + fun FirLoopBuilder.prepareTarget(): FirLoopTarget { label = context.firLabels.pop() val target = FirLoopTarget(label?.name) context.firLoopTargets += target + return target } - fun FirLoopBuilder.configure(generateBlock: () -> FirBlock): FirLoop { + fun FirLoopBuilder.configure(target: FirLoopTarget, generateBlock: () -> FirBlock): FirLoop { block = generateBlock() val loop = build() - val target = context.firLoopTargets.removeLast() + val stackTopTarget = context.firLoopTargets.removeLast() + assert(target == stackTopTarget) { + "Loop target preparation and loop configuration mismatch" + } target.bind(loop) return loop }