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:
committed by
TeamCityServer
parent
bb242f022f
commit
572c0b2ade
+9
-6
@@ -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)
|
||||
|
||||
+7
-3
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user