Raw FIR: make sure loop target preparation and loop configuration match

by using the generated loop target during preparation in a message
passing fashion
This commit is contained in:
Jinseong Jeon
2021-03-18 16:00:20 -07:00
committed by TeamCityServer
parent bb242f022f
commit 572c0b2ade
3 changed files with 25 additions and 15 deletions
@@ -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()
@@ -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)
@@ -216,16 +216,20 @@ abstract class BaseFirBuilder<T>(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
}