'while' & 'do-while' loops
This commit is contained in:
committed by
Dmitry Petrov
parent
8bba49cba6
commit
87c7b4834b
+43
-2
@@ -22,15 +22,56 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.psi2ir.defaultLoad
|
import org.jetbrains.kotlin.psi2ir.defaultLoad
|
||||||
|
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.getInfixOperator
|
import org.jetbrains.kotlin.psi2ir.generators.getInfixOperator
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
import java.lang.AssertionError
|
import java.lang.AssertionError
|
||||||
|
|
||||||
class WhenExpressionGenerator(val statementGenerator: StatementGenerator) : BodyGenerator {
|
class BranchingExpressionGenerator(val statementGenerator: StatementGenerator) : GeneratorWithScope {
|
||||||
override val scope: Scope get() = statementGenerator.scope
|
override val scope: Scope get() = statementGenerator.scope
|
||||||
override val context: GeneratorContext get() = statementGenerator.context
|
override val context: GeneratorContext get() = statementGenerator.context
|
||||||
|
|
||||||
fun generate(expression: KtWhenExpression): IrExpression {
|
fun generateIfExpression(expression: KtIfExpression): IrExpression {
|
||||||
|
val resultType = getInferredTypeWithSmartcasts(expression)
|
||||||
|
|
||||||
|
var ktLastIf: KtIfExpression = expression
|
||||||
|
val irBranches = SmartList<Pair<IrExpression, IrExpression>>()
|
||||||
|
var irElseBranch: IrExpression? = null
|
||||||
|
|
||||||
|
whenBranches@while (true) {
|
||||||
|
val irCondition = statementGenerator.generateExpression(ktLastIf.condition!!)
|
||||||
|
val irThenBranch = statementGenerator.generateExpression(ktLastIf.then!!)
|
||||||
|
irBranches.add(Pair(irCondition, irThenBranch))
|
||||||
|
|
||||||
|
val ktElse = ktLastIf.`else`?.deparenthesize()
|
||||||
|
when (ktElse) {
|
||||||
|
null -> break@whenBranches
|
||||||
|
is KtIfExpression -> ktLastIf = ktElse
|
||||||
|
is KtExpression -> {
|
||||||
|
irElseBranch = statementGenerator.generateExpression(ktElse)
|
||||||
|
break@whenBranches
|
||||||
|
}
|
||||||
|
else -> throw AssertionError("Unexpected else expression: ${ktElse.text}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (irBranches.size == 1) {
|
||||||
|
val (irCondition, irThenBranch) = irBranches[0]
|
||||||
|
IrIfThenElseImpl(expression.startOffset, expression.endOffset, resultType,
|
||||||
|
irCondition, irThenBranch, irElseBranch, IrOperator.IF)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val irWhen = IrWhenImpl(expression.startOffset, expression.endOffset, resultType, IrOperator.WHEN)
|
||||||
|
for ((irCondition, irThenBranch) in irBranches) {
|
||||||
|
irWhen.addBranch(irCondition, irThenBranch)
|
||||||
|
}
|
||||||
|
irWhen.elseBranch = irElseBranch
|
||||||
|
irWhen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun generateWhenExpression(expression: KtWhenExpression): IrExpression {
|
||||||
val irSubject = expression.subjectExpression?.let {
|
val irSubject = expression.subjectExpression?.let {
|
||||||
scope.createTemporaryVariable(statementGenerator.generateExpression(it), "subject")
|
scope.createTemporaryVariable(statementGenerator.generateExpression(it), "subject")
|
||||||
}
|
}
|
||||||
@@ -35,9 +35,9 @@ import java.util.*
|
|||||||
class CallGenerator(
|
class CallGenerator(
|
||||||
override val context: GeneratorContext,
|
override val context: GeneratorContext,
|
||||||
override val scope: Scope
|
override val scope: Scope
|
||||||
) : BodyGenerator {
|
) : GeneratorWithScope {
|
||||||
|
|
||||||
constructor(parent: BodyGenerator) : this(parent.context, parent.scope)
|
constructor(parent: GeneratorWithScope) : this(parent.context, parent.scope)
|
||||||
|
|
||||||
fun generateCall(
|
fun generateCall(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
|
|||||||
+10
-4
@@ -17,16 +17,17 @@
|
|||||||
package org.jetbrains.kotlin.psi2ir.generators
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBlockImpl
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrReturnImpl
|
|
||||||
import org.jetbrains.kotlin.psi.KtBlockExpression
|
import org.jetbrains.kotlin.psi.KtBlockExpression
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtWhileExpression
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class ExpressionBodyGenerator(val scopeOwner: CallableDescriptor, override val context: GeneratorContext): BodyGenerator {
|
class ExpressionBodyGenerator(val scopeOwner: CallableDescriptor, override val context: GeneratorContext): GeneratorWithScope {
|
||||||
override val scope = Scope(scopeOwner)
|
override val scope = Scope(scopeOwner)
|
||||||
|
private val loopTable = HashMap<KtExpression, IrLoop>()
|
||||||
|
|
||||||
fun generateFunctionBody(ktBody: KtExpression): IrExpression {
|
fun generateFunctionBody(ktBody: KtExpression): IrExpression {
|
||||||
resetInternalContext()
|
resetInternalContext()
|
||||||
@@ -46,6 +47,7 @@ class ExpressionBodyGenerator(val scopeOwner: CallableDescriptor, override val c
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resetInternalContext() {
|
private fun resetInternalContext() {
|
||||||
|
loopTable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun postprocessFunctionBody() {
|
private fun postprocessFunctionBody() {
|
||||||
@@ -56,5 +58,9 @@ class ExpressionBodyGenerator(val scopeOwner: CallableDescriptor, override val c
|
|||||||
|
|
||||||
private fun createStatementGenerator() =
|
private fun createStatementGenerator() =
|
||||||
StatementGenerator(context, scopeOwner, this, scope)
|
StatementGenerator(context, scopeOwner, this, scope)
|
||||||
|
|
||||||
|
fun putLoop(expression: KtExpression, irLoop: IrLoop) {
|
||||||
|
loopTable[expression] = irLoop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ interface Generator {
|
|||||||
val context: GeneratorContext
|
val context: GeneratorContext
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BodyGenerator : Generator {
|
interface GeneratorWithScope : Generator {
|
||||||
val scope: Scope
|
val scope: Scope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.psi2ir.generators
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.psi.KtDoWhileExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtWhileExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtWhileExpressionBase
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
|
||||||
|
class LoopExpressionGenerator(val statementGenerator: StatementGenerator) {
|
||||||
|
fun generateWhileExpression(expression: KtWhileExpression): IrExpression =
|
||||||
|
generateConditionalLoop(expression, IrWhileLoopImpl(expression.startOffset, expression.endOffset, IrOperator.WHILE_LOOP))
|
||||||
|
|
||||||
|
fun generateDoWhileExpression(expression: KtDoWhileExpression): IrExpression =
|
||||||
|
generateConditionalLoop(expression, IrDoWhileLoopImpl(expression.startOffset, expression.endOffset, IrOperator.DO_WHILE_LOOP))
|
||||||
|
|
||||||
|
private fun generateConditionalLoop(expression: KtWhileExpressionBase, irLoop: IrLoop): IrLoop {
|
||||||
|
statementGenerator.expressionBodyGenerator.putLoop(expression, irLoop)
|
||||||
|
irLoop.condition = statementGenerator.generateExpression(expression.condition!!)
|
||||||
|
irLoop.body = statementGenerator.generateExpression(expression.body!!)
|
||||||
|
return irLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -34,7 +34,7 @@ import java.lang.AssertionError
|
|||||||
|
|
||||||
class OperatorExpressionGenerator(
|
class OperatorExpressionGenerator(
|
||||||
val statementGenerator: StatementGenerator
|
val statementGenerator: StatementGenerator
|
||||||
) : BodyGenerator {
|
) : GeneratorWithScope {
|
||||||
override val scope: Scope get() = statementGenerator.scope
|
override val scope: Scope get() = statementGenerator.scope
|
||||||
override val context: GeneratorContext get() = statementGenerator.context
|
override val context: GeneratorContext get() = statementGenerator.context
|
||||||
|
|
||||||
|
|||||||
+9
-43
@@ -41,15 +41,14 @@ import org.jetbrains.kotlin.resolve.constants.StringValue
|
|||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
|
||||||
import java.lang.AssertionError
|
import java.lang.AssertionError
|
||||||
|
|
||||||
class StatementGenerator(
|
class StatementGenerator(
|
||||||
override val context: GeneratorContext,
|
override val context: GeneratorContext,
|
||||||
val scopeOwner: DeclarationDescriptor,
|
val scopeOwner: DeclarationDescriptor,
|
||||||
@Suppress("unused") val expressionBodyGenerator: ExpressionBodyGenerator,
|
val expressionBodyGenerator: ExpressionBodyGenerator,
|
||||||
override val scope: Scope
|
override val scope: Scope
|
||||||
) : KtVisitor<IrStatement, Nothing?>(), BodyGenerator {
|
) : KtVisitor<IrStatement, Nothing?>(), GeneratorWithScope {
|
||||||
fun generateExpression(ktExpression: KtExpression): IrExpression =
|
fun generateExpression(ktExpression: KtExpression): IrExpression =
|
||||||
ktExpression.genExpr()
|
ktExpression.genExpr()
|
||||||
|
|
||||||
@@ -267,50 +266,17 @@ class StatementGenerator(
|
|||||||
override fun visitIsExpression(expression: KtIsExpression, data: Nothing?): IrStatement =
|
override fun visitIsExpression(expression: KtIsExpression, data: Nothing?): IrStatement =
|
||||||
OperatorExpressionGenerator(this).generateInstanceOfExpression(expression)
|
OperatorExpressionGenerator(this).generateInstanceOfExpression(expression)
|
||||||
|
|
||||||
override fun visitIfExpression(expression: KtIfExpression, data: Nothing?): IrStatement {
|
override fun visitIfExpression(expression: KtIfExpression, data: Nothing?): IrStatement =
|
||||||
val resultType = getInferredTypeWithSmartcasts(expression)
|
BranchingExpressionGenerator(this).generateIfExpression(expression)
|
||||||
|
|
||||||
var ktLastIf: KtIfExpression = expression
|
|
||||||
val irBranches = SmartList<Pair<IrExpression, IrExpression>>()
|
|
||||||
var irElseBranch: IrExpression? = null
|
|
||||||
|
|
||||||
whenBranches@while (true) {
|
|
||||||
val irCondition = ktLastIf.condition!!.genExpr()
|
|
||||||
val irThenBranch = ktLastIf.then!!.genExpr()
|
|
||||||
irBranches.add(Pair(irCondition, irThenBranch))
|
|
||||||
|
|
||||||
val ktElse = ktLastIf.`else`?.deparenthesize()
|
|
||||||
when (ktElse) {
|
|
||||||
null -> break@whenBranches
|
|
||||||
is KtIfExpression -> ktLastIf = ktElse
|
|
||||||
is KtExpression -> {
|
|
||||||
irElseBranch = ktElse.genExpr()
|
|
||||||
break@whenBranches
|
|
||||||
}
|
|
||||||
else -> throw AssertionError("Unexpected else expression: ${ktElse.text}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return if (irBranches.size == 1) {
|
|
||||||
val (irCondition, irThenBranch) = irBranches[0]
|
|
||||||
IrIfThenElseImpl(expression.startOffset, expression.endOffset, resultType,
|
|
||||||
irCondition, irThenBranch, irElseBranch, IrOperator.IF)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val irWhen = IrWhenImpl(expression.startOffset, expression.endOffset, resultType, IrOperator.WHEN)
|
|
||||||
for ((irCondition, irThenBranch) in irBranches) {
|
|
||||||
irWhen.addBranch(irCondition, irThenBranch)
|
|
||||||
}
|
|
||||||
irWhen.elseBranch = irElseBranch
|
|
||||||
irWhen
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitWhenExpression(expression: KtWhenExpression, data: Nothing?): IrStatement =
|
override fun visitWhenExpression(expression: KtWhenExpression, data: Nothing?): IrStatement =
|
||||||
WhenExpressionGenerator(this).generate(expression)
|
BranchingExpressionGenerator(this).generateWhenExpression(expression)
|
||||||
|
|
||||||
|
override fun visitWhileExpression(expression: KtWhileExpression, data: Nothing?): IrStatement =
|
||||||
|
LoopExpressionGenerator(this).generateWhileExpression(expression)
|
||||||
|
|
||||||
|
override fun visitDoWhileExpression(expression: KtDoWhileExpression, data: Nothing?): IrStatement =
|
||||||
|
LoopExpressionGenerator(this).generateDoWhileExpression(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -20,14 +20,14 @@ import org.jetbrains.kotlin.ir.expressions.IrBlockImpl
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrIfThenElseImpl
|
import org.jetbrains.kotlin.ir.expressions.IrIfThenElseImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
import org.jetbrains.kotlin.ir.expressions.IrOperator
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.BodyGenerator
|
import org.jetbrains.kotlin.psi2ir.generators.GeneratorWithScope
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.constNull
|
import org.jetbrains.kotlin.psi2ir.generators.constNull
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.equalsNull
|
import org.jetbrains.kotlin.psi2ir.generators.equalsNull
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
|
|
||||||
|
|
||||||
class SafeCallReceiver(
|
class SafeCallReceiver(
|
||||||
val generator: BodyGenerator,
|
val generator: GeneratorWithScope,
|
||||||
val startOffset: Int,
|
val startOffset: Int,
|
||||||
val endOffset: Int,
|
val endOffset: Int,
|
||||||
val explicitReceiver: IrExpression,
|
val explicitReceiver: IrExpression,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.*
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
|
||||||
interface IrLoop : IrExpression {
|
interface IrLoop : IrExpression {
|
||||||
|
val operator: IrOperator?
|
||||||
var body: IrExpression
|
var body: IrExpression
|
||||||
var condition: IrExpression
|
var condition: IrExpression
|
||||||
}
|
}
|
||||||
@@ -30,8 +31,19 @@ interface IrDoWhileLoop : IrLoop
|
|||||||
|
|
||||||
abstract class IrLoopBase(
|
abstract class IrLoopBase(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int
|
endOffset: Int,
|
||||||
|
override val operator: IrOperator?
|
||||||
) : IrExpressionBase(startOffset, endOffset, null), IrLoop {
|
) : IrExpressionBase(startOffset, endOffset, null), IrLoop {
|
||||||
|
private var conditionImpl: IrExpression? = null
|
||||||
|
override var condition: IrExpression
|
||||||
|
get() = conditionImpl!!
|
||||||
|
set(value) {
|
||||||
|
value.assertDetached()
|
||||||
|
conditionImpl?.detach()
|
||||||
|
conditionImpl = value
|
||||||
|
value.setTreeLocation(this, LOOP_CONDITION_SLOT)
|
||||||
|
}
|
||||||
|
|
||||||
private var bodyImpl: IrExpression? = null
|
private var bodyImpl: IrExpression? = null
|
||||||
override var body: IrExpression
|
override var body: IrExpression
|
||||||
get() = bodyImpl!!
|
get() = bodyImpl!!
|
||||||
@@ -45,54 +57,30 @@ abstract class IrLoopBase(
|
|||||||
override fun getChild(slot: Int): IrElement? =
|
override fun getChild(slot: Int): IrElement? =
|
||||||
when (slot) {
|
when (slot) {
|
||||||
LOOP_BODY_SLOT -> body
|
LOOP_BODY_SLOT -> body
|
||||||
|
LOOP_CONDITION_SLOT -> condition
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun replaceChild(slot: Int, newChild: IrElement) {
|
override fun replaceChild(slot: Int, newChild: IrElement) {
|
||||||
when (slot) {
|
when (slot) {
|
||||||
LOOP_BODY_SLOT -> body = newChild.assertCast()
|
LOOP_BODY_SLOT -> body = newChild.assertCast()
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class IrConditionalLoopBase(
|
|
||||||
startOffset: Int,
|
|
||||||
endOffset: Int
|
|
||||||
) : IrLoopBase(startOffset, endOffset) {
|
|
||||||
private var conditionImpl: IrExpression? = null
|
|
||||||
override var condition: IrExpression
|
|
||||||
get() = conditionImpl!!
|
|
||||||
set(value) {
|
|
||||||
value.assertDetached()
|
|
||||||
conditionImpl?.detach()
|
|
||||||
conditionImpl = value
|
|
||||||
value.setTreeLocation(this, LOOP_CONDITION_SLOT)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getChild(slot: Int): IrElement? =
|
|
||||||
when (slot) {
|
|
||||||
LOOP_CONDITION_SLOT -> condition
|
|
||||||
else -> super.getChild(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun replaceChild(slot: Int, newChild: IrElement) {
|
|
||||||
when (slot) {
|
|
||||||
LOOP_CONDITION_SLOT -> condition = newChild.assertCast()
|
LOOP_CONDITION_SLOT -> condition = newChild.assertCast()
|
||||||
else -> super.replaceChild(slot, newChild)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrWhileLoopImpl(
|
class IrWhileLoopImpl(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int
|
endOffset: Int,
|
||||||
) : IrConditionalLoopBase(startOffset, endOffset), IrWhileLoop {
|
operator: IrOperator?
|
||||||
|
) : IrLoopBase(startOffset, endOffset, operator), IrWhileLoop {
|
||||||
constructor(
|
constructor(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
|
operator: IrOperator?,
|
||||||
condition: IrExpression,
|
condition: IrExpression,
|
||||||
body: IrExpression
|
body: IrExpression
|
||||||
) : this(startOffset, endOffset) {
|
) : this(startOffset, endOffset, operator) {
|
||||||
this.condition = condition
|
this.condition = condition
|
||||||
this.body = body
|
this.body = body
|
||||||
}
|
}
|
||||||
@@ -109,14 +97,16 @@ class IrWhileLoopImpl(
|
|||||||
|
|
||||||
class IrDoWhileLoopImpl(
|
class IrDoWhileLoopImpl(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int
|
endOffset: Int,
|
||||||
) : IrConditionalLoopBase(startOffset, endOffset), IrDoWhileLoop {
|
operator: IrOperator?
|
||||||
|
) : IrLoopBase(startOffset, endOffset, operator), IrDoWhileLoop {
|
||||||
constructor(
|
constructor(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
|
operator: IrOperator?,
|
||||||
body: IrExpression,
|
body: IrExpression,
|
||||||
condition: IrExpression
|
condition: IrExpression
|
||||||
) : this(startOffset, endOffset) {
|
) : this(startOffset, endOffset, operator) {
|
||||||
this.condition = condition
|
this.condition = condition
|
||||||
this.body = body
|
this.body = body
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ interface IrOperator {
|
|||||||
object IF : IrOperatorImpl("IF")
|
object IF : IrOperatorImpl("IF")
|
||||||
object WHEN : IrOperatorImpl("WHEN")
|
object WHEN : IrOperatorImpl("WHEN")
|
||||||
object WHEN_COMMA : IrOperatorImpl("WHEN_COMMA")
|
object WHEN_COMMA : IrOperatorImpl("WHEN_COMMA")
|
||||||
|
object WHILE_LOOP : IrOperatorImpl("WHILE_LOOP")
|
||||||
|
object DO_WHILE_LOOP : IrOperatorImpl("DO_WHILE_LOOP")
|
||||||
|
|
||||||
data class COMPONENT_N private constructor(val index: Int) : IrOperatorImpl("COMPONENT_$index") {
|
data class COMPONENT_N private constructor(val index: Int) : IrOperatorImpl("COMPONENT_$index") {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -87,6 +89,8 @@ interface IrOperator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrOperator.isAssignmentOperatorWithResult() =
|
fun IrOperator.isAssignmentOperatorWithResult() =
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ import org.jetbrains.kotlin.ir.IrElement
|
|||||||
import org.jetbrains.kotlin.ir.SourceLocationManager
|
import org.jetbrains.kotlin.ir.SourceLocationManager
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrDoWhileLoop
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrWhen
|
import org.jetbrains.kotlin.ir.expressions.IrWhen
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrWhileLoop
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
import org.jetbrains.kotlin.utils.Printer
|
||||||
|
|
||||||
@@ -64,6 +66,20 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitWhileLoop(loop: IrWhileLoop, data: String) {
|
||||||
|
loop.dumpLabeledElementWith(data) {
|
||||||
|
loop.condition.accept(this, "condition")
|
||||||
|
loop.body.accept(this, "body")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: String) {
|
||||||
|
loop.dumpLabeledElementWith(data) {
|
||||||
|
loop.body.accept(this, "body")
|
||||||
|
loop.condition.accept(this, "condition")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
|
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
|
||||||
printer.println(accept(elementRenderer, null).withLabel(label))
|
printer.println(accept(elementRenderer, null).withLabel(label))
|
||||||
indented(body)
|
indented(body)
|
||||||
|
|||||||
@@ -100,6 +100,12 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
|||||||
override fun visitWhen(expression: IrWhen, data: Nothing?): String =
|
override fun visitWhen(expression: IrWhen, data: Nothing?): String =
|
||||||
"WHEN type=${expression.type.render()} operator=${expression.operator}"
|
"WHEN type=${expression.type.render()} operator=${expression.operator}"
|
||||||
|
|
||||||
|
override fun visitWhileLoop(loop: IrWhileLoop, data: Nothing?): String =
|
||||||
|
"WHILE operator=${loop.operator}"
|
||||||
|
|
||||||
|
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Nothing?): String =
|
||||||
|
"DO_WHILE operator=${loop.operator}"
|
||||||
|
|
||||||
override fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: Nothing?): String =
|
override fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: Nothing?): String =
|
||||||
"DUMMY ${declaration.descriptor.name}"
|
"DUMMY ${declaration.descriptor.name}"
|
||||||
|
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
fun test() {
|
||||||
|
var x = 0
|
||||||
|
while (x < 5) x++
|
||||||
|
while (x < 10) { x++ }
|
||||||
|
do x++ while (x < 15)
|
||||||
|
do { x ++ } while (x < 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testSmartcastInCondition() {
|
||||||
|
val a: Any? = null
|
||||||
|
if (a is Boolean) {
|
||||||
|
while (a) {}
|
||||||
|
do {} while (a)
|
||||||
|
}
|
||||||
|
}
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
IrFile /whileDoWhile.kt
|
||||||
|
IrFunction public fun test(): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
|
VAR var x: kotlin.Int
|
||||||
|
CONST Int type=kotlin.Int value='0'
|
||||||
|
WHILE operator=WHILE_LOOP
|
||||||
|
condition: CALL .LT0 type=kotlin.Boolean operator=LT
|
||||||
|
arg0: CALL .compareTo type=kotlin.Int operator=LT
|
||||||
|
$this: GET_VAR x type=kotlin.Int operator=null
|
||||||
|
other: CONST Int type=kotlin.Int value='5'
|
||||||
|
body: BLOCK type=kotlin.Int hasResult=true operator=POSTFIX_INCR
|
||||||
|
VAR val tmp0: kotlin.Int
|
||||||
|
GET_VAR x type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
SET_VAR x type=<no-type> operator=POSTFIX_INCR
|
||||||
|
CALL .inc type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
$this: GET_VAR tmp0 type=kotlin.Int operator=null
|
||||||
|
GET_VAR tmp0 type=kotlin.Int operator=null
|
||||||
|
WHILE operator=WHILE_LOOP
|
||||||
|
condition: CALL .LT0 type=kotlin.Boolean operator=LT
|
||||||
|
arg0: CALL .compareTo type=kotlin.Int operator=LT
|
||||||
|
$this: GET_VAR x type=kotlin.Int operator=null
|
||||||
|
other: CONST Int type=kotlin.Int value='10'
|
||||||
|
body: BLOCK type=kotlin.Int hasResult=true operator=null
|
||||||
|
BLOCK type=kotlin.Int hasResult=true operator=POSTFIX_INCR
|
||||||
|
VAR val tmp1: kotlin.Int
|
||||||
|
GET_VAR x type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
SET_VAR x type=<no-type> operator=POSTFIX_INCR
|
||||||
|
CALL .inc type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
$this: GET_VAR tmp1 type=kotlin.Int operator=null
|
||||||
|
GET_VAR tmp1 type=kotlin.Int operator=null
|
||||||
|
DO_WHILE operator=DO_WHILE_LOOP
|
||||||
|
body: BLOCK type=kotlin.Int hasResult=true operator=POSTFIX_INCR
|
||||||
|
VAR val tmp2: kotlin.Int
|
||||||
|
GET_VAR x type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
SET_VAR x type=<no-type> operator=POSTFIX_INCR
|
||||||
|
CALL .inc type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
$this: GET_VAR tmp2 type=kotlin.Int operator=null
|
||||||
|
GET_VAR tmp2 type=kotlin.Int operator=null
|
||||||
|
condition: CALL .LT0 type=kotlin.Boolean operator=LT
|
||||||
|
arg0: CALL .compareTo type=kotlin.Int operator=LT
|
||||||
|
$this: GET_VAR x type=kotlin.Int operator=null
|
||||||
|
other: CONST Int type=kotlin.Int value='15'
|
||||||
|
DO_WHILE operator=DO_WHILE_LOOP
|
||||||
|
body: BLOCK type=kotlin.Int hasResult=true operator=null
|
||||||
|
BLOCK type=kotlin.Int hasResult=true operator=POSTFIX_INCR
|
||||||
|
VAR val tmp3: kotlin.Int
|
||||||
|
GET_VAR x type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
SET_VAR x type=<no-type> operator=POSTFIX_INCR
|
||||||
|
CALL .inc type=kotlin.Int operator=POSTFIX_INCR
|
||||||
|
$this: GET_VAR tmp3 type=kotlin.Int operator=null
|
||||||
|
GET_VAR tmp3 type=kotlin.Int operator=null
|
||||||
|
condition: CALL .LT0 type=kotlin.Boolean operator=LT
|
||||||
|
arg0: CALL .compareTo type=kotlin.Int operator=LT
|
||||||
|
$this: GET_VAR x type=kotlin.Int operator=null
|
||||||
|
other: CONST Int type=kotlin.Int value='20'
|
||||||
|
IrFunction public fun testSmartcastInCondition(): kotlin.Unit
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
|
VAR val a: kotlin.Any? = null
|
||||||
|
CONST Null type=kotlin.Nothing? value='null'
|
||||||
|
WHEN type=kotlin.Unit operator=IF
|
||||||
|
if: TYPE_OP operator=INSTANCEOF typeOperand=kotlin.Boolean
|
||||||
|
GET_VAR a type=kotlin.Any? operator=null
|
||||||
|
then: BLOCK type=<no-type> hasResult=false operator=null
|
||||||
|
WHILE operator=WHILE_LOOP
|
||||||
|
condition: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Boolean
|
||||||
|
GET_VAR a type=kotlin.Any? operator=null
|
||||||
|
body: BLOCK type=<no-type> hasResult=false operator=null
|
||||||
|
DO_WHILE operator=DO_WHILE_LOOP
|
||||||
|
body: BLOCK type=<no-type> hasResult=false operator=null
|
||||||
|
condition: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Boolean
|
||||||
|
GET_VAR a type=kotlin.Any? operator=null
|
||||||
@@ -250,4 +250,10 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/when.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/when.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whileDoWhile.kt")
|
||||||
|
public void testWhileDoWhile() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/whileDoWhile.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user