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 =
|
var firCondition: FirExpression =
|
||||||
buildErrorExpression(null, ConeSimpleDiagnostic("No condition in do-while loop", DiagnosticKind.Syntax))
|
buildErrorExpression(null, ConeSimpleDiagnostic("No condition in do-while loop", DiagnosticKind.Syntax))
|
||||||
|
|
||||||
|
val target: FirLoopTarget
|
||||||
return FirDoWhileLoopBuilder().apply {
|
return FirDoWhileLoopBuilder().apply {
|
||||||
source = doWhileLoop.toFirSourceElement()
|
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.
|
// 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 {
|
doWhileLoop.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
BODY -> block = it
|
BODY -> block = it
|
||||||
@@ -902,7 +903,7 @@ class ExpressionsConverter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
condition = firCondition
|
condition = firCondition
|
||||||
}.configure { convertLoopBody(block) }
|
}.configure(target) { convertLoopBody(block) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -919,13 +920,14 @@ class ExpressionsConverter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val target: FirLoopTarget
|
||||||
return FirWhileLoopBuilder().apply {
|
return FirWhileLoopBuilder().apply {
|
||||||
source = whileLoop.toFirSourceElement()
|
source = whileLoop.toFirSourceElement()
|
||||||
condition = firCondition
|
condition = firCondition
|
||||||
// break/continue in the while loop condition will refer to an outer loop if any.
|
// break/continue in the while loop condition will refer to an outer loop if any.
|
||||||
// So, prepare the loop target after building the condition.
|
// So, prepare the loop target after building the condition.
|
||||||
prepareTarget()
|
target = prepareTarget()
|
||||||
}.configure { convertLoopBody(block) }
|
}.configure(target) { convertLoopBody(block) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -944,6 +946,7 @@ class ExpressionsConverter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val target: FirLoopTarget
|
||||||
return buildBlock {
|
return buildBlock {
|
||||||
source = forLoop.toFirSourceElement()
|
source = forLoop.toFirSourceElement()
|
||||||
val iteratorVal = generateTemporaryVariable(
|
val iteratorVal = generateTemporaryVariable(
|
||||||
@@ -962,8 +965,8 @@ class ExpressionsConverter(
|
|||||||
}
|
}
|
||||||
// break/continue in the for loop condition will refer to an outer loop if any.
|
// break/continue in the for loop condition will refer to an outer loop if any.
|
||||||
// So, prepare the loop target after building the condition.
|
// So, prepare the loop target after building the condition.
|
||||||
prepareTarget()
|
target = prepareTarget()
|
||||||
}.configure {
|
}.configure(target) {
|
||||||
// NB: just body.toFirBlock() isn't acceptable here because we need to add some statements
|
// NB: just body.toFirBlock() isn't acceptable here because we need to add some statements
|
||||||
buildBlock block@{
|
buildBlock block@{
|
||||||
source = blockNode?.toFirSourceElement()
|
source = blockNode?.toFirSourceElement()
|
||||||
|
|||||||
@@ -1650,28 +1650,31 @@ open class RawFirBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDoWhileExpression(expression: KtDoWhileExpression, data: Unit): FirElement {
|
override fun visitDoWhileExpression(expression: KtDoWhileExpression, data: Unit): FirElement {
|
||||||
|
val target: FirLoopTarget
|
||||||
return FirDoWhileLoopBuilder().apply {
|
return FirDoWhileLoopBuilder().apply {
|
||||||
source = expression.toFirSourceElement()
|
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.
|
// 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")
|
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 {
|
override fun visitWhileExpression(expression: KtWhileExpression, data: Unit): FirElement {
|
||||||
|
val target: FirLoopTarget
|
||||||
return FirWhileLoopBuilder().apply {
|
return FirWhileLoopBuilder().apply {
|
||||||
source = expression.toFirSourceElement()
|
source = expression.toFirSourceElement()
|
||||||
condition = expression.condition.toFirExpression("No condition in while loop")
|
condition = expression.condition.toFirExpression("No condition in while loop")
|
||||||
// break/continue in the while loop condition will refer to an outer loop if any.
|
// break/continue in the while loop condition will refer to an outer loop if any.
|
||||||
// So, prepare the loop target after building the condition.
|
// So, prepare the loop target after building the condition.
|
||||||
prepareTarget()
|
target = prepareTarget()
|
||||||
}.configure { expression.body.toFirBlock() }
|
}.configure(target) { expression.body.toFirBlock() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitForExpression(expression: KtForExpression, data: Unit?): FirElement {
|
override fun visitForExpression(expression: KtForExpression, data: Unit?): FirElement {
|
||||||
val rangeExpression = expression.loopRange.toFirExpression("No range in for loop")
|
val rangeExpression = expression.loopRange.toFirExpression("No range in for loop")
|
||||||
val ktParameter = expression.loopParameter
|
val ktParameter = expression.loopParameter
|
||||||
val fakeSource = expression.toFirPsiSourceElement(FirFakeSourceElementKind.DesugaredForLoop)
|
val fakeSource = expression.toFirPsiSourceElement(FirFakeSourceElementKind.DesugaredForLoop)
|
||||||
|
val target: FirLoopTarget
|
||||||
return buildBlock {
|
return buildBlock {
|
||||||
source = fakeSource
|
source = fakeSource
|
||||||
val rangeSource = expression.loopRange?.toFirSourceElement(FirFakeSourceElementKind.DesugaredForLoop)
|
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.
|
// break/continue in the for loop condition will refer to an outer loop if any.
|
||||||
// So, prepare the loop target after building the condition.
|
// So, prepare the loop target after building the condition.
|
||||||
prepareTarget()
|
target = prepareTarget()
|
||||||
}.configure {
|
}.configure(target) {
|
||||||
// NB: just body.toFirBlock() isn't acceptable here because we need to add some statements
|
// NB: just body.toFirBlock() isn't acceptable here because we need to add some statements
|
||||||
val blockBuilder = when (val body = expression.body) {
|
val blockBuilder = when (val body = expression.body) {
|
||||||
is KtBlockExpression -> configureBlockWithoutBuilding(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()
|
label = context.firLabels.pop()
|
||||||
val target = FirLoopTarget(label?.name)
|
val target = FirLoopTarget(label?.name)
|
||||||
context.firLoopTargets += target
|
context.firLoopTargets += target
|
||||||
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirLoopBuilder.configure(generateBlock: () -> FirBlock): FirLoop {
|
fun FirLoopBuilder.configure(target: FirLoopTarget, generateBlock: () -> FirBlock): FirLoop {
|
||||||
block = generateBlock()
|
block = generateBlock()
|
||||||
val loop = build()
|
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)
|
target.bind(loop)
|
||||||
return loop
|
return loop
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user