Use ternary 'if' for 'when' (and also '||' as ',' in 'when').
This commit is contained in:
committed by
Dmitry Petrov
parent
c36a0d04ce
commit
c0d521266b
+1
-1
@@ -189,7 +189,7 @@ class OperatorExpressionGenerator(val statementGenerator: StatementGenerator): I
|
|||||||
IrBinaryOperatorExpressionImpl(
|
IrBinaryOperatorExpressionImpl(
|
||||||
expression.startOffset, expression.endOffset, context.builtIns.booleanType,
|
expression.startOffset, expression.endOffset, context.builtIns.booleanType,
|
||||||
irOperator, null, irCompareToCall,
|
irOperator, null, irCompareToCall,
|
||||||
IrLiteralExpressionImpl.int(expression.startOffset, expression.endOffset, context.builtIns.intType, 0)
|
IrConstExpressionImpl.int(expression.startOffset, expression.endOffset, context.builtIns.intType, 0)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-28
@@ -141,11 +141,11 @@ class StatementGenerator(
|
|||||||
|
|
||||||
return when (constantValue) {
|
return when (constantValue) {
|
||||||
is StringValue ->
|
is StringValue ->
|
||||||
IrLiteralExpressionImpl.string(expression.startOffset, expression.endOffset, constantType, constantValue.value)
|
IrConstExpressionImpl.string(expression.startOffset, expression.endOffset, constantType, constantValue.value)
|
||||||
is IntValue ->
|
is IntValue ->
|
||||||
IrLiteralExpressionImpl.int(expression.startOffset, expression.endOffset, constantType, constantValue.value)
|
IrConstExpressionImpl.int(expression.startOffset, expression.endOffset, constantType, constantValue.value)
|
||||||
is NullValue ->
|
is NullValue ->
|
||||||
IrLiteralExpressionImpl.nullLiteral(expression.startOffset, expression.endOffset, constantType)
|
IrConstExpressionImpl.constNull(expression.startOffset, expression.endOffset, constantType)
|
||||||
else ->
|
else ->
|
||||||
TODO("handle other literal types: ${constantValue.type}")
|
TODO("handle other literal types: ${constantValue.type}")
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ class StatementGenerator(
|
|||||||
return entry0.genExpr()
|
return entry0.genExpr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entries.size == 0 -> return IrLiteralExpressionImpl.string(expression.startOffset, expression.endOffset, getInferredTypeWithSmarcastsOrFail(expression), "")
|
entries.size == 0 -> return IrConstExpressionImpl.string(expression.startOffset, expression.endOffset, getInferredTypeWithSmarcastsOrFail(expression), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression))
|
val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression))
|
||||||
@@ -169,7 +169,7 @@ class StatementGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?): IrStatement =
|
override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?): IrStatement =
|
||||||
IrLiteralExpressionImpl.string(entry.startOffset, entry.endOffset, context.builtIns.stringType, entry.text)
|
IrConstExpressionImpl.string(entry.startOffset, entry.endOffset, context.builtIns.stringType, entry.text)
|
||||||
|
|
||||||
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Nothing?): IrExpression {
|
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Nothing?): IrExpression {
|
||||||
val resolvedCall = getResolvedCall(expression)!!
|
val resolvedCall = getResolvedCall(expression)!!
|
||||||
@@ -266,29 +266,11 @@ class StatementGenerator(
|
|||||||
|
|
||||||
override fun visitIfExpression(expression: KtIfExpression, data: Nothing?): IrStatement {
|
override fun visitIfExpression(expression: KtIfExpression, data: Nothing?): IrStatement {
|
||||||
val resultType = getInferredTypeWithSmartcasts(expression)
|
val resultType = getInferredTypeWithSmartcasts(expression)
|
||||||
val irWhen = IrWhenExpressionImpl(expression.startOffset, expression.endOffset, resultType)
|
val irCondition = expression.condition!!.genExpr().toExpectedType(context.builtIns.booleanType)
|
||||||
|
val irThenBranch = expression.then!!.genExpr().toExpectedType(resultType)
|
||||||
var ktBranch: KtIfExpression? = expression
|
val irElseBranch = expression.`else`?.let { it.genExpr().toExpectedType(resultType) }
|
||||||
branches@while (ktBranch != null) {
|
return IrIfExpressionImpl(expression.startOffset, expression.endOffset, resultType,
|
||||||
val irBranch = IrBranchImpl(ktBranch.startOffset, ktBranch.endOffset,
|
irCondition, irThenBranch, irElseBranch, IrOperator.IF)
|
||||||
ktBranch.condition!!.genExpr().toExpectedType(context.builtIns.booleanType),
|
|
||||||
ktBranch.then!!.genExpr().toExpectedType(resultType))
|
|
||||||
irWhen.addBranch(irBranch)
|
|
||||||
|
|
||||||
val ktElse = ktBranch.`else`
|
|
||||||
|
|
||||||
ktBranch = when (ktElse) {
|
|
||||||
is KtIfExpression -> ktElse
|
|
||||||
null ->
|
|
||||||
break@branches
|
|
||||||
else -> {
|
|
||||||
irWhen.elseExpression = ktElse.genExpr().toExpectedType(resultType)
|
|
||||||
break@branches
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return irWhen
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhenExpression(expression: KtWhenExpression, data: Nothing?): IrStatement =
|
override fun visitWhenExpression(expression: KtWhenExpression, data: Nothing?): IrStatement =
|
||||||
|
|||||||
+46
-10
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
|||||||
import org.jetbrains.kotlin.psi2ir.load
|
import org.jetbrains.kotlin.psi2ir.load
|
||||||
import org.jetbrains.kotlin.psi2ir.toExpectedType
|
import org.jetbrains.kotlin.psi2ir.toExpectedType
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class WhenExpressionGenerator(val statementGenerator: StatementGenerator) : IrGenerator {
|
class WhenExpressionGenerator(val statementGenerator: StatementGenerator) : IrGenerator {
|
||||||
override val context: GeneratorContext get() = statementGenerator.context
|
override val context: GeneratorContext get() = statementGenerator.context
|
||||||
@@ -37,31 +38,66 @@ class WhenExpressionGenerator(val statementGenerator: StatementGenerator) : IrGe
|
|||||||
|
|
||||||
val resultType = getInferredTypeWithSmartcasts(expression)
|
val resultType = getInferredTypeWithSmartcasts(expression)
|
||||||
|
|
||||||
val irWhen = IrWhenExpressionImpl(expression.startOffset, expression.endOffset, resultType, irSubject)
|
val irBranches = ArrayList<Pair<IrExpression, IrExpression>>(expression.entries.size)
|
||||||
|
var irElseExpression: IrExpression? = null
|
||||||
|
|
||||||
for (ktEntry in expression.entries) {
|
for (ktEntry in expression.entries) {
|
||||||
if (ktEntry.isElse) {
|
if (ktEntry.isElse) {
|
||||||
irWhen.elseExpression = statementGenerator.generateExpression(ktEntry.expression!!).toExpectedType(resultType)
|
irElseExpression = statementGenerator.generateExpression(ktEntry.expression!!).toExpectedType(resultType)
|
||||||
continue
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
val irBranch = IrBranchImpl(ktEntry.startOffset, ktEntry.endOffset)
|
var irBranchCondition: IrExpression? = null
|
||||||
|
|
||||||
for (ktCondition in ktEntry.conditions) {
|
for (ktCondition in ktEntry.conditions) {
|
||||||
val irCondition =
|
val irCondition =
|
||||||
if (irSubject != null)
|
if (irSubject != null)
|
||||||
generateWhenConditionWithSubject(ktCondition, conditionsGenerator, irSubject)
|
generateWhenConditionWithSubject(ktCondition, conditionsGenerator, irSubject)
|
||||||
else
|
else
|
||||||
generateWhenConditionNoSubject(ktCondition)
|
generateWhenConditionNoSubject(ktCondition)
|
||||||
irBranch.addCondition(irCondition)
|
irBranchCondition = irBranchCondition?.let { IrIfExpressionImpl.whenComma(it, irCondition) } ?: irCondition
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
irBranch.result = statementGenerator.generateExpression(ktEntry.expression!!).toExpectedType(resultType)
|
val irBranchResult = statementGenerator.generateExpression(ktEntry.expression!!).toExpectedType(resultType)
|
||||||
|
irBranches.add(Pair(irBranchCondition!!, irBranchResult))
|
||||||
irWhen.addBranch(irBranch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return irWhen
|
if (irBranches.isEmpty()) return generateWhenBody(expression, irSubject)
|
||||||
|
|
||||||
|
irBranches.reverse()
|
||||||
|
|
||||||
|
val (irLastCondition, irLastResult) = irBranches[0]
|
||||||
|
var irTopBranch = IrIfExpressionImpl(irLastCondition.startOffset, irLastCondition.endOffset, resultType,
|
||||||
|
irLastCondition, irLastResult, irElseExpression, IrOperator.WHEN)
|
||||||
|
|
||||||
|
for ((irBranchCondition, irBranchResult) in irBranches.subList(1, irBranches.size)) {
|
||||||
|
irTopBranch = IrIfExpressionImpl(irBranchCondition.startOffset, irBranchCondition.endOffset, resultType,
|
||||||
|
irBranchCondition, irBranchResult, irTopBranch, IrOperator.WHEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateWhenBody(expression, irSubject, irTopBranch)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateWhenBody(expression: KtWhenExpression, irSubject: IrVariable?, irTopBranch: IrIfExpression? = null): IrExpression {
|
||||||
|
if (irSubject == null) {
|
||||||
|
if (irTopBranch == null)
|
||||||
|
return IrBlockExpressionImpl(expression.startOffset, expression.endOffset, null, false, IrOperator.WHEN)
|
||||||
|
else
|
||||||
|
return irTopBranch
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (irTopBranch == null) {
|
||||||
|
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, null, false, IrOperator.WHEN)
|
||||||
|
irBlock.addStatement(irSubject)
|
||||||
|
return irBlock
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, irTopBranch.type, true, IrOperator.WHEN)
|
||||||
|
irBlock.addStatement(irSubject)
|
||||||
|
irBlock.addStatement(irTopBranch)
|
||||||
|
return irBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateWhenConditionNoSubject(ktCondition: KtWhenCondition): IrExpression =
|
private fun generateWhenConditionNoSubject(ktCondition: KtWhenCondition): IrExpression =
|
||||||
|
|||||||
+1
-1
@@ -124,7 +124,7 @@ class IndexedLValue(
|
|||||||
hasResult, operator)
|
hasResult, operator)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun defineTemporaryVariables(irBlock: IrBlockExpression, callGenerator: CallGenerator) {
|
private fun defineTemporaryVariables(irBlock: IrBlockExpressionImpl, callGenerator: CallGenerator) {
|
||||||
irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array"))
|
irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array"))
|
||||||
|
|
||||||
var index = 0
|
var index = 0
|
||||||
|
|||||||
+4
-4
@@ -28,17 +28,17 @@ interface IrRematerializableValue : IrValue {
|
|||||||
|
|
||||||
fun createRematerializableValue(irExpression: IrExpression): IrRematerializableValue? =
|
fun createRematerializableValue(irExpression: IrExpression): IrRematerializableValue? =
|
||||||
when (irExpression) {
|
when (irExpression) {
|
||||||
is IrLiteralExpression<*> -> IrRematerializableLiteralValue(irExpression)
|
is IrConstExpression<*> -> IrRematerializableLiteralValue(irExpression)
|
||||||
is IrGetVariableExpression -> IrRematerializableVariableValue(irExpression)
|
is IrGetVariableExpression -> IrRematerializableVariableValue(irExpression)
|
||||||
is IrGetExtensionReceiverExpression -> IrRematerializableExtensionReceiverValue(irExpression)
|
is IrGetExtensionReceiverExpression -> IrRematerializableExtensionReceiverValue(irExpression)
|
||||||
is IrThisExpression -> IrRematerializableThisValue(irExpression)
|
is IrThisExpression -> IrRematerializableThisValue(irExpression)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrRematerializableLiteralValue(override val irExpression: IrLiteralExpression<*>): IrRematerializableValue {
|
class IrRematerializableLiteralValue(override val irExpression: IrConstExpression<*>): IrRematerializableValue {
|
||||||
override fun load(): IrExpression =
|
override fun load(): IrExpression =
|
||||||
IrLiteralExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type,
|
IrConstExpressionImpl(irExpression.startOffset, irExpression.endOffset, irExpression.type,
|
||||||
irExpression.kind, irExpression.kind.valueOf(irExpression))
|
irExpression.kind, irExpression.kind.valueOf(irExpression))
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrRematerializableVariableValue(override val irExpression: IrGetVariableExpression) : IrRematerializableValue {
|
class IrRematerializableVariableValue(override val irExpression: IrGetVariableExpression) : IrRematerializableValue {
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ const val EXTENSION_RECEIVER_SLOT = -2
|
|||||||
const val FUNCTION_BODY_SLOT = 0
|
const val FUNCTION_BODY_SLOT = 0
|
||||||
const val MODULE_SLOT = 0
|
const val MODULE_SLOT = 0
|
||||||
const val INITIALIZER_SLOT = 0
|
const val INITIALIZER_SLOT = 0
|
||||||
const val WHEN_SUBJECT_VARIABLE_SLOT = -1
|
const val IF_CONDITION_SLOT = -1
|
||||||
const val WHEN_ELSE_EXPRESSION_SLOT = -2
|
const val IF_THEN_SLOT = -2
|
||||||
const val BRANCH_RESULT_SLOT = -1
|
const val IF_ELSE_SLOT = -3
|
||||||
const val LOOP_BODY_SLOT = -1
|
const val LOOP_BODY_SLOT = -1
|
||||||
const val LOOP_CONDITION_SLOT = -2
|
const val LOOP_CONDITION_SLOT = -2
|
||||||
const val SETTER_ARGUMENT_INDEX = 0
|
const val SETTER_ARGUMENT_INDEX = 0
|
||||||
@@ -26,8 +26,6 @@ interface IrFile : IrElement {
|
|||||||
val fileEntry: SourceLocationManager.FileEntry
|
val fileEntry: SourceLocationManager.FileEntry
|
||||||
val packageFragmentDescriptor: PackageFragmentDescriptor
|
val packageFragmentDescriptor: PackageFragmentDescriptor
|
||||||
val declarations: List<IrDeclaration>
|
val declarations: List<IrDeclaration>
|
||||||
|
|
||||||
fun addDeclaration(declaration: IrDeclaration)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrFileImpl(
|
class IrFileImpl(
|
||||||
@@ -37,7 +35,7 @@ class IrFileImpl(
|
|||||||
) : IrElementBase(0, fileEntry.maxOffset), IrFile {
|
) : IrElementBase(0, fileEntry.maxOffset), IrFile {
|
||||||
override val declarations: MutableList<IrDeclaration> = ArrayList()
|
override val declarations: MutableList<IrDeclaration> = ArrayList()
|
||||||
|
|
||||||
override fun addDeclaration(declaration: IrDeclaration) {
|
fun addDeclaration(declaration: IrDeclaration) {
|
||||||
declaration.assertDetached()
|
declaration.assertDetached()
|
||||||
declaration.setTreeLocation(this, declarations.size)
|
declaration.setTreeLocation(this, declarations.size)
|
||||||
declarations.add(declaration)
|
declarations.add(declaration)
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ interface IrModule : IrElement {
|
|||||||
val descriptor: ModuleDescriptor
|
val descriptor: ModuleDescriptor
|
||||||
val irBuiltins: IrBuiltIns
|
val irBuiltins: IrBuiltIns
|
||||||
val files: List<IrFile>
|
val files: List<IrFile>
|
||||||
|
|
||||||
fun addFile(file: IrFile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrModuleImpl(
|
class IrModuleImpl(
|
||||||
@@ -45,7 +43,7 @@ class IrModuleImpl(
|
|||||||
) : IrModule {
|
) : IrModule {
|
||||||
override val files: MutableList<IrFile> = ArrayList()
|
override val files: MutableList<IrFile> = ArrayList()
|
||||||
|
|
||||||
override fun addFile(file: IrFile) {
|
fun addFile(file: IrFile) {
|
||||||
file.assertDetached()
|
file.assertDetached()
|
||||||
file.setTreeLocation(this, files.size)
|
file.setTreeLocation(this, files.size)
|
||||||
files.add(file)
|
files.add(file)
|
||||||
|
|||||||
@@ -27,10 +27,9 @@ interface IrBlockExpression : IrExpression {
|
|||||||
val operator: IrOperator?
|
val operator: IrOperator?
|
||||||
|
|
||||||
val statements: List<IrStatement>
|
val statements: List<IrStatement>
|
||||||
fun addStatement(statement: IrStatement)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrBlockExpression.addIfNotNull(statement: IrStatement?) {
|
fun IrBlockExpressionImpl.addIfNotNull(statement: IrStatement?) {
|
||||||
if (statement != null) addStatement(statement)
|
if (statement != null) addStatement(statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +42,7 @@ class IrBlockExpressionImpl(
|
|||||||
) : IrExpressionBase(startOffset, endOffset, type), IrBlockExpression {
|
) : IrExpressionBase(startOffset, endOffset, type), IrBlockExpression {
|
||||||
override val statements: MutableList<IrStatement> = ArrayList()
|
override val statements: MutableList<IrStatement> = ArrayList()
|
||||||
|
|
||||||
override fun addStatement(statement: IrStatement) {
|
fun addStatement(statement: IrStatement) {
|
||||||
statement.assertDetached()
|
statement.assertDetached()
|
||||||
statement.setTreeLocation(this, statements.size)
|
statement.setTreeLocation(this, statements.size)
|
||||||
statements.add(statement)
|
statements.add(statement)
|
||||||
|
|||||||
+21
-12
@@ -19,15 +19,15 @@ package org.jetbrains.kotlin.ir.expressions
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
interface IrLiteralExpression<out T> : IrExpression {
|
interface IrConstExpression<out T> : IrExpression {
|
||||||
val kind: IrLiteralKind<T>
|
val kind: IrLiteralKind<T>
|
||||||
val value: T
|
val value: T
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class IrLiteralKind<out T>(val asString: kotlin.String) {
|
sealed class IrLiteralKind<out T>(val asString: kotlin.String) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun valueOf(literal: IrLiteralExpression<*>) =
|
fun valueOf(aConst: IrConstExpression<*>) =
|
||||||
(literal as IrLiteralExpression<T>).value
|
(aConst as IrConstExpression<T>).value
|
||||||
|
|
||||||
object Null : IrLiteralKind<Nothing?>("Null")
|
object Null : IrLiteralKind<Nothing?>("Null")
|
||||||
object Boolean : IrLiteralKind<kotlin.Boolean>("Boolean")
|
object Boolean : IrLiteralKind<kotlin.Boolean>("Boolean")
|
||||||
@@ -42,25 +42,34 @@ sealed class IrLiteralKind<out T>(val asString: kotlin.String) {
|
|||||||
override fun toString() = asString
|
override fun toString() = asString
|
||||||
}
|
}
|
||||||
|
|
||||||
class IrLiteralExpressionImpl<out T> (
|
class IrConstExpressionImpl<out T> (
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
type: KotlinType?,
|
type: KotlinType?,
|
||||||
override val kind: IrLiteralKind<T>,
|
override val kind: IrLiteralKind<T>,
|
||||||
override val value: T
|
override val value: T
|
||||||
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrLiteralExpression<T> {
|
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrConstExpression<T> {
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
visitor.visitLiteral(this, data)
|
visitor.visitConst(this, data)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun string(startOffset: Int, endOffset: Int, type: KotlinType, value: String): IrLiteralExpressionImpl<String> =
|
fun string(startOffset: Int, endOffset: Int, type: KotlinType, value: String): IrConstExpressionImpl<String> =
|
||||||
IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.String, value)
|
IrConstExpressionImpl(startOffset, endOffset, type, IrLiteralKind.String, value)
|
||||||
|
|
||||||
fun int(startOffset: Int, endOffset: Int, type: KotlinType, value: Int): IrLiteralExpressionImpl<Int> =
|
fun int(startOffset: Int, endOffset: Int, type: KotlinType, value: Int): IrConstExpressionImpl<Int> =
|
||||||
IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Int, value)
|
IrConstExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Int, value)
|
||||||
|
|
||||||
fun nullLiteral(startOffset: Int, endOffset: Int, type: KotlinType): IrLiteralExpressionImpl<Nothing?> =
|
fun constNull(startOffset: Int, endOffset: Int, type: KotlinType): IrConstExpressionImpl<Nothing?> =
|
||||||
IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Null, null)
|
IrConstExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Null, null)
|
||||||
|
|
||||||
|
fun boolean(startOffset: Int, endOffset: Int, type: KotlinType, value: Boolean): IrConstExpressionImpl<Boolean> =
|
||||||
|
IrConstExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Boolean, value)
|
||||||
|
|
||||||
|
fun constTrue(startOffset: Int, endOffset: Int, type: KotlinType): IrConstExpressionImpl<Boolean> =
|
||||||
|
boolean(startOffset, endOffset, type, true)
|
||||||
|
|
||||||
|
fun constFalse(startOffset: Int, endOffset: Int, type: KotlinType): IrConstExpressionImpl<Boolean> =
|
||||||
|
boolean(startOffset, endOffset, type, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* 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.ir.expressions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
interface IrIfExpression : IrExpression {
|
||||||
|
val operator: IrOperator?
|
||||||
|
var condition: IrExpression
|
||||||
|
var thenBranch: IrExpression
|
||||||
|
var elseBranch: IrExpression?
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrIfExpressionImpl(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType?,
|
||||||
|
override val operator: IrOperator? = null
|
||||||
|
) : IrExpressionBase(startOffset, endOffset, type), IrIfExpression {
|
||||||
|
constructor(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType?,
|
||||||
|
condition: IrExpression,
|
||||||
|
thenBranch: IrExpression,
|
||||||
|
elseBranch: IrExpression? = null,
|
||||||
|
operator: IrOperator? = null
|
||||||
|
) : this(startOffset, endOffset, type, operator) {
|
||||||
|
this.condition = condition
|
||||||
|
this.thenBranch = thenBranch
|
||||||
|
this.elseBranch = elseBranch
|
||||||
|
}
|
||||||
|
|
||||||
|
private var conditionImpl: IrExpression? = null
|
||||||
|
override var condition: IrExpression
|
||||||
|
get() = conditionImpl!!
|
||||||
|
set(value) {
|
||||||
|
value.assertDetached()
|
||||||
|
value.detach()
|
||||||
|
conditionImpl = value
|
||||||
|
value.setTreeLocation(this, IF_CONDITION_SLOT)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var thenBranchImpl: IrExpression? = null
|
||||||
|
override var thenBranch: IrExpression
|
||||||
|
get() = thenBranchImpl!!
|
||||||
|
set(value) {
|
||||||
|
value.assertDetached()
|
||||||
|
value.detach()
|
||||||
|
thenBranchImpl = value
|
||||||
|
value.setTreeLocation(this, IF_THEN_SLOT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override var elseBranch: IrExpression? = null
|
||||||
|
set(value) {
|
||||||
|
value?.assertDetached()
|
||||||
|
value?.detach()
|
||||||
|
field = value
|
||||||
|
value?.setTreeLocation(this, IF_ELSE_SLOT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getChild(slot: Int): IrElement? =
|
||||||
|
when (slot) {
|
||||||
|
IF_CONDITION_SLOT -> condition
|
||||||
|
IF_THEN_SLOT -> thenBranch
|
||||||
|
IF_ELSE_SLOT -> elseBranch
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun replaceChild(slot: Int, newChild: IrElement) {
|
||||||
|
newChild.assertDetached()
|
||||||
|
when (slot) {
|
||||||
|
IF_CONDITION_SLOT ->
|
||||||
|
condition = newChild.assertCast()
|
||||||
|
IF_THEN_SLOT ->
|
||||||
|
thenBranch = newChild.assertCast()
|
||||||
|
IF_ELSE_SLOT ->
|
||||||
|
elseBranch = newChild.assertCast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
|
visitor.visitIf(this, data)
|
||||||
|
|
||||||
|
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
|
condition.accept(visitor, data)
|
||||||
|
thenBranch.accept(visitor, data)
|
||||||
|
elseBranch?.accept(visitor, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// a || b == if (a) true else b
|
||||||
|
fun oror(a: IrExpression, b: IrExpression, operator: IrOperator = IrOperator.OROR): IrIfExpression =
|
||||||
|
IrIfExpressionImpl(b.startOffset, b.endOffset, b.type!!,
|
||||||
|
a, IrConstExpressionImpl.constTrue(b.startOffset, b.endOffset, b.type!!), b,
|
||||||
|
operator)
|
||||||
|
|
||||||
|
// a && b == if (a) b else false
|
||||||
|
fun andand(a: IrExpression, b: IrExpression): IrIfExpression =
|
||||||
|
IrIfExpressionImpl(b.startOffset, b.endOffset, b.type!!,
|
||||||
|
a, b, IrConstExpressionImpl.constFalse(b.startOffset, b.endOffset, b.type!!),
|
||||||
|
IrOperator.OROR)
|
||||||
|
|
||||||
|
fun whenComma(a: IrExpression, b: IrExpression): IrIfExpression =
|
||||||
|
oror(a, b, IrOperator.WHEN_COMMA)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,6 +70,10 @@ interface IrOperator {
|
|||||||
object GET_PROPERTY : IrOperatorImpl("GET_PROPERTY")
|
object GET_PROPERTY : IrOperatorImpl("GET_PROPERTY")
|
||||||
object SET_PROPERTY : IrOperatorImpl("SET_PROPERTY")
|
object SET_PROPERTY : IrOperatorImpl("SET_PROPERTY")
|
||||||
|
|
||||||
|
object IF : IrOperatorImpl("IF")
|
||||||
|
object WHEN : IrOperatorImpl("WHEN")
|
||||||
|
object WHEN_COMMA : IrOperatorImpl("WHEN_COMMA")
|
||||||
|
|
||||||
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 {
|
||||||
private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) }
|
private val precreatedComponents = Array(32) { i -> COMPONENT_N(i + 1) }
|
||||||
@@ -81,4 +85,5 @@ interface IrOperator {
|
|||||||
COMPONENT_N(index)
|
COMPONENT_N(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.ir.expressions
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.*
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
interface IrWhenExpression : IrExpression {
|
|
||||||
var subject: IrVariable?
|
|
||||||
val branches: List<IrBranch>
|
|
||||||
var elseExpression: IrExpression?
|
|
||||||
|
|
||||||
fun addBranch(branch: IrBranch)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IrBranch : IrElement {
|
|
||||||
val conditions: List<IrExpression>
|
|
||||||
var result: IrExpression
|
|
||||||
|
|
||||||
fun addCondition(expression: IrExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
class IrWhenExpressionImpl(
|
|
||||||
startOffset: Int,
|
|
||||||
endOffset: Int,
|
|
||||||
type: KotlinType?
|
|
||||||
) : IrExpressionBase(startOffset, endOffset, type), IrWhenExpression {
|
|
||||||
constructor(
|
|
||||||
startOffset: Int,
|
|
||||||
endOffset: Int,
|
|
||||||
type: KotlinType?,
|
|
||||||
subject: IrVariable?
|
|
||||||
) : this(startOffset, endOffset, type) {
|
|
||||||
this.subject = subject
|
|
||||||
}
|
|
||||||
|
|
||||||
override var subject: IrVariable? = null
|
|
||||||
set(value) {
|
|
||||||
value?.assertDetached()
|
|
||||||
subject?.detach()
|
|
||||||
field = value
|
|
||||||
field?.setTreeLocation(this, WHEN_SUBJECT_VARIABLE_SLOT)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val branches: MutableList<IrBranch> = ArrayList()
|
|
||||||
|
|
||||||
override var elseExpression: IrExpression? = null
|
|
||||||
set(value) {
|
|
||||||
value?.assertDetached()
|
|
||||||
subject?.detach()
|
|
||||||
field = value
|
|
||||||
field?.setTreeLocation(this, WHEN_ELSE_EXPRESSION_SLOT)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addBranch(branch: IrBranch) {
|
|
||||||
branch.assertDetached()
|
|
||||||
branch.setTreeLocation(this, branches.size)
|
|
||||||
branches.add(branch)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getChild(slot: Int): IrElement? =
|
|
||||||
when (slot) {
|
|
||||||
WHEN_SUBJECT_VARIABLE_SLOT -> subject
|
|
||||||
WHEN_ELSE_EXPRESSION_SLOT -> elseExpression
|
|
||||||
else -> branches.getOrNull(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun replaceChild(slot: Int, newChild: IrElement) {
|
|
||||||
newChild.assertDetached()
|
|
||||||
when (slot) {
|
|
||||||
WHEN_SUBJECT_VARIABLE_SLOT ->
|
|
||||||
subject = newChild.assertCast()
|
|
||||||
WHEN_ELSE_EXPRESSION_SLOT ->
|
|
||||||
elseExpression = newChild.assertCast()
|
|
||||||
in branches.indices -> {
|
|
||||||
branches[slot].detach()
|
|
||||||
branches[slot] = newChild.assertCast()
|
|
||||||
newChild.setTreeLocation(this, slot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
|
||||||
visitor.visitWhenExpression(this, data)
|
|
||||||
|
|
||||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
|
||||||
subject?.accept(visitor, data)
|
|
||||||
branches.forEach { it.accept(visitor, data) }
|
|
||||||
elseExpression?.accept(visitor, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun ifThen(startOffset: Int, endOffset: Int, type: KotlinType?, condition: IrExpression, thenExpression: IrExpression) =
|
|
||||||
IrWhenExpressionImpl(startOffset, endOffset, type).apply {
|
|
||||||
addBranch(IrBranchImpl(startOffset, endOffset, condition, thenExpression))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ifThenElse(startOffset: Int, endOffset: Int, type: KotlinType?,
|
|
||||||
condition: IrExpression, thenExpression: IrExpression, elseExpression: IrExpression) =
|
|
||||||
IrWhenExpressionImpl(startOffset, endOffset, type).apply {
|
|
||||||
addBranch(IrBranchImpl(startOffset, endOffset, condition, thenExpression))
|
|
||||||
this.elseExpression = elseExpression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IrBranchImpl(startOffset: Int, endOffset: Int) : IrElementBase(startOffset, endOffset), IrBranch {
|
|
||||||
constructor(startOffset: Int, endOffset: Int, condition: IrExpression, result: IrExpression) : this(startOffset, endOffset) {
|
|
||||||
this.result = result
|
|
||||||
addCondition(condition)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val conditions: MutableList<IrExpression> = SmartList()
|
|
||||||
|
|
||||||
override fun addCondition(expression: IrExpression) {
|
|
||||||
expression.assertDetached()
|
|
||||||
expression.setTreeLocation(this, conditions.size)
|
|
||||||
conditions.add(expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var resultImpl: IrExpression? = null
|
|
||||||
override var result: IrExpression
|
|
||||||
get() = resultImpl!!
|
|
||||||
set(value) {
|
|
||||||
value.assertDetached()
|
|
||||||
resultImpl?.detach()
|
|
||||||
resultImpl = value
|
|
||||||
value.setTreeLocation(this, BRANCH_RESULT_SLOT)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getChild(slot: Int): IrElement? =
|
|
||||||
when (slot) {
|
|
||||||
BRANCH_RESULT_SLOT -> result
|
|
||||||
else -> conditions.getOrNull(slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun replaceChild(slot: Int, newChild: IrElement) {
|
|
||||||
when (slot) {
|
|
||||||
BRANCH_RESULT_SLOT ->
|
|
||||||
result = newChild.assertCast()
|
|
||||||
in conditions.indices -> {
|
|
||||||
conditions[slot].detach()
|
|
||||||
conditions[slot] = newChild.assertCast()
|
|
||||||
newChild.setTreeLocation(this, slot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
|
||||||
visitor.visitBranch(this, data)
|
|
||||||
|
|
||||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
|
||||||
conditions.forEach { it.accept(visitor, data) }
|
|
||||||
resultImpl?.accept(visitor, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,7 @@ 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.IrCallExpression
|
import org.jetbrains.kotlin.ir.expressions.IrCallExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrWhenExpression
|
import org.jetbrains.kotlin.ir.expressions.IrIfExpression
|
||||||
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
|
||||||
|
|
||||||
@@ -54,16 +54,11 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhenExpression(expression: IrWhenExpression, data: String) {
|
override fun visitIf(expression: IrIfExpression, data: String) {
|
||||||
expression.dumpLabeledElementWith(data) {
|
expression.dumpLabeledElementWith(data) {
|
||||||
expression.subject?.let { subject ->
|
expression.condition.accept(this, "if")
|
||||||
subject.accept(this, "\$subject")
|
expression.thenBranch.accept(this, "then")
|
||||||
}
|
expression.elseBranch?.accept(this, "else")
|
||||||
for (branch in expression.branches) {
|
|
||||||
branch.conditions.forEach { it.accept(this, "if") }
|
|
||||||
branch.result.accept(this, "then")
|
|
||||||
}
|
|
||||||
expression.elseExpression?.accept(this, "else")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
|||||||
override fun visitExpression(expression: IrExpression, data: Nothing?): String =
|
override fun visitExpression(expression: IrExpression, data: Nothing?): String =
|
||||||
"? ${expression.javaClass.simpleName} type=${expression.renderType()}"
|
"? ${expression.javaClass.simpleName} type=${expression.renderType()}"
|
||||||
|
|
||||||
override fun <T> visitLiteral(expression: IrLiteralExpression<T>, data: Nothing?): String =
|
override fun <T> visitConst(expression: IrConstExpression<T>, data: Nothing?): String =
|
||||||
"LITERAL ${expression.kind} type=${expression.renderType()} value='${expression.value}'"
|
"LITERAL ${expression.kind} type=${expression.renderType()} value='${expression.value}'"
|
||||||
|
|
||||||
override fun visitBlockExpression(expression: IrBlockExpression, data: Nothing?): String =
|
override fun visitBlockExpression(expression: IrBlockExpression, data: Nothing?): String =
|
||||||
@@ -107,11 +107,8 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
|||||||
override fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: Nothing?): String =
|
override fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: Nothing?): String =
|
||||||
"TYPE_OP operator=${expression.operator} typeOperand=${expression.typeOperand.render()}"
|
"TYPE_OP operator=${expression.operator} typeOperand=${expression.typeOperand.render()}"
|
||||||
|
|
||||||
override fun visitWhenExpression(expression: IrWhenExpression, data: Nothing?): String =
|
override fun visitIf(expression: IrIfExpression, data: Nothing?): String =
|
||||||
"WHEN subject=${expression.subject?.descriptor?.name} type=${expression.type.render()}"
|
"IF type=${expression.type.render()} operator=${expression.operator}"
|
||||||
|
|
||||||
override fun visitBranch(branch: IrBranch, data: Nothing?): String =
|
|
||||||
"BRANCH"
|
|
||||||
|
|
||||||
override fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: Nothing?): String =
|
override fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: Nothing?): String =
|
||||||
"DUMMY ${declaration.descriptor.name}"
|
"DUMMY ${declaration.descriptor.name}"
|
||||||
|
|||||||
@@ -35,12 +35,11 @@ interface IrElementVisitor<out R, in D> {
|
|||||||
fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D): R = visitProperty(declaration, data)
|
fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D): R = visitProperty(declaration, data)
|
||||||
fun visitLocalVariable(declaration: IrVariable, data: D) = visitDeclaration(declaration, data)
|
fun visitLocalVariable(declaration: IrVariable, data: D) = visitDeclaration(declaration, data)
|
||||||
|
|
||||||
|
|
||||||
fun visitBody(body: IrBody, data: D): R = visitElement(body, data)
|
fun visitBody(body: IrBody, data: D): R = visitElement(body, data)
|
||||||
fun visitExpressionBody(body: IrExpressionBody, data: D): R = visitBody(body, data)
|
fun visitExpressionBody(body: IrExpressionBody, data: D): R = visitBody(body, data)
|
||||||
|
|
||||||
fun visitExpression(expression: IrExpression, data: D): R = visitElement(expression, data)
|
fun visitExpression(expression: IrExpression, data: D): R = visitElement(expression, data)
|
||||||
fun <T> visitLiteral(expression: IrLiteralExpression<T>, data: D): R = visitExpression(expression, data)
|
fun <T> visitConst(expression: IrConstExpression<T>, data: D): R = visitExpression(expression, data)
|
||||||
fun visitReturnExpression(expression: IrReturnExpression, data: D): R = visitExpression(expression, data)
|
fun visitReturnExpression(expression: IrReturnExpression, data: D): R = visitExpression(expression, data)
|
||||||
fun visitBlockExpression(expression: IrBlockExpression, data: D): R = visitExpression(expression, data)
|
fun visitBlockExpression(expression: IrBlockExpression, data: D): R = visitExpression(expression, data)
|
||||||
fun visitStringConcatenation(expression: IrStringConcatenationExpression, data: D) = visitExpression(expression, data)
|
fun visitStringConcatenation(expression: IrStringConcatenationExpression, data: D) = visitExpression(expression, data)
|
||||||
@@ -60,9 +59,7 @@ interface IrElementVisitor<out R, in D> {
|
|||||||
fun visitBinaryOperator(expression: IrBinaryOperatorExpression, data: D) = visitOperatorExpression(expression, data)
|
fun visitBinaryOperator(expression: IrBinaryOperatorExpression, data: D) = visitOperatorExpression(expression, data)
|
||||||
fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: D) = visitExpression(expression, data)
|
fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: D) = visitExpression(expression, data)
|
||||||
|
|
||||||
fun visitWhenExpression(expression: IrWhenExpression, data: D) = visitExpression(expression, data)
|
fun visitIf(expression: IrIfExpression, data: D) = visitExpression(expression, data)
|
||||||
fun visitBranch(branch: IrBranch, data: D): R = visitElement(branch, data)
|
|
||||||
|
|
||||||
fun visitLoop(loop: IrLoopExpression, data: D) = visitExpression(loop, data)
|
fun visitLoop(loop: IrLoopExpression, data: D) = visitExpression(loop, data)
|
||||||
fun visitWhileLoop(loop: IrWhileLoopExpression, data: D) = visitLoop(loop, data)
|
fun visitWhileLoop(loop: IrWhileLoopExpression, data: D) = visitLoop(loop, data)
|
||||||
fun visitDoWhileLoop(loop: IrDoWhileLoopExpression, data: D) = visitLoop(loop, data)
|
fun visitDoWhileLoop(loop: IrDoWhileLoopExpression, data: D) = visitLoop(loop, data)
|
||||||
|
|||||||
+2
-2
@@ -16,12 +16,12 @@ IrFile /elvis.kt
|
|||||||
IrFunction public fun test3(/*0*/ a: kotlin.Any?, /*1*/ b: kotlin.Any?): kotlin.String
|
IrFunction public fun test3(/*0*/ a: kotlin.Any?, /*1*/ b: kotlin.Any?): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
IF type=kotlin.Unit operator=IF
|
||||||
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
|
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
|
||||||
GET_VAR b type=kotlin.Any? operator=null
|
GET_VAR b type=kotlin.Any? operator=null
|
||||||
then: RETURN type=<no-type>
|
then: RETURN type=<no-type>
|
||||||
LITERAL String type=kotlin.String value=''
|
LITERAL String type=kotlin.String value=''
|
||||||
WHEN subject=null type=kotlin.Unit
|
IF type=kotlin.Unit operator=IF
|
||||||
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String?
|
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String?
|
||||||
GET_VAR a type=kotlin.Any? operator=null
|
GET_VAR a type=kotlin.Any? operator=null
|
||||||
then: RETURN type=<no-type>
|
then: RETURN type=<no-type>
|
||||||
|
|||||||
+7
-6
@@ -3,13 +3,14 @@ IrFile /ifElseIf.kt
|
|||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
RETURN type=<no-type>
|
RETURN type=<no-type>
|
||||||
WHEN subject=null type=kotlin.Int
|
IF type=kotlin.Int operator=IF
|
||||||
if: BINARY_OP operator=GT type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Int): kotlin.Int
|
if: BINARY_OP operator=GT type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Int): kotlin.Int
|
||||||
GET_VAR i type=kotlin.Int operator=null
|
GET_VAR i type=kotlin.Int operator=null
|
||||||
LITERAL Int type=kotlin.Int value='0'
|
LITERAL Int type=kotlin.Int value='0'
|
||||||
then: LITERAL Int type=kotlin.Int value='1'
|
then: LITERAL Int type=kotlin.Int value='1'
|
||||||
if: BINARY_OP operator=LT type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Int): kotlin.Int
|
else: IF type=kotlin.Int operator=IF
|
||||||
GET_VAR i type=kotlin.Int operator=null
|
if: BINARY_OP operator=LT type=kotlin.Boolean related=public open override /*1*/ fun compareTo(/*0*/ other: kotlin.Int): kotlin.Int
|
||||||
LITERAL Int type=kotlin.Int value='0'
|
GET_VAR i type=kotlin.Int operator=null
|
||||||
then: DUMMY MINUS type=kotlin.Int
|
LITERAL Int type=kotlin.Int value='0'
|
||||||
else: LITERAL Int type=kotlin.Int value='0'
|
then: DUMMY MINUS type=kotlin.Int
|
||||||
|
else: LITERAL Int type=kotlin.Int value='0'
|
||||||
|
|||||||
+3
-3
@@ -18,7 +18,7 @@ IrFile /smartCasts.kt
|
|||||||
IrFunction public fun test1(/*0*/ x: kotlin.Any): kotlin.Unit
|
IrFunction public fun test1(/*0*/ x: kotlin.Any): kotlin.Unit
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
IF type=kotlin.Unit operator=IF
|
||||||
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
|
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
|
||||||
GET_VAR x type=kotlin.Any operator=null
|
GET_VAR x type=kotlin.Any operator=null
|
||||||
then: RETURN type=<no-type>
|
then: RETURN type=<no-type>
|
||||||
@@ -40,7 +40,7 @@ IrFile /smartCasts.kt
|
|||||||
IrFunction public fun test2(/*0*/ x: kotlin.Any): kotlin.String
|
IrFunction public fun test2(/*0*/ x: kotlin.Any): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
IF type=kotlin.Unit operator=IF
|
||||||
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
|
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
|
||||||
GET_VAR x type=kotlin.Any operator=null
|
GET_VAR x type=kotlin.Any operator=null
|
||||||
then: RETURN type=<no-type>
|
then: RETURN type=<no-type>
|
||||||
@@ -52,7 +52,7 @@ IrFile /smartCasts.kt
|
|||||||
IrFunction public fun test3(/*0*/ x: kotlin.Any): kotlin.String
|
IrFunction public fun test3(/*0*/ x: kotlin.Any): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
IF type=kotlin.Unit operator=IF
|
||||||
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
|
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=kotlin.String
|
||||||
GET_VAR x type=kotlin.Any operator=null
|
GET_VAR x type=kotlin.Any operator=null
|
||||||
then: RETURN type=<no-type>
|
then: RETURN type=<no-type>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ IrFile /smartCastsWithDestructuring.kt
|
|||||||
IrFunction public fun test(/*0*/ x: I1): kotlin.Unit
|
IrFunction public fun test(/*0*/ x: I1): kotlin.Unit
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
WHEN subject=null type=kotlin.Unit
|
IF type=kotlin.Unit operator=IF
|
||||||
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=I2
|
if: TYPE_OP operator=NOT_INSTANCEOF typeOperand=I2
|
||||||
GET_VAR x type=I1 operator=null
|
GET_VAR x type=I1 operator=null
|
||||||
then: RETURN type=<no-type>
|
then: RETURN type=<no-type>
|
||||||
|
|||||||
Vendored
+8
@@ -17,3 +17,11 @@ fun test(x: Any?) =
|
|||||||
x in setOf<Nothing>() -> "nothingness?"
|
x in setOf<Nothing>() -> "nothingness?"
|
||||||
else -> "something"
|
else -> "something"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testComma(x: Int) =
|
||||||
|
when (x) {
|
||||||
|
1, 2, 3, 4 -> "1234"
|
||||||
|
5, 6, 7 -> "567"
|
||||||
|
8, 9 -> "89"
|
||||||
|
else -> "?"
|
||||||
|
}
|
||||||
Vendored
+91
-31
@@ -4,45 +4,105 @@ IrFile /when.kt
|
|||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
RETURN type=<no-type>
|
RETURN type=<no-type>
|
||||||
WHEN subject=tmp0_subject type=kotlin.String
|
BLOCK type=kotlin.String hasResult=true operator=WHEN
|
||||||
$subject: VAR val tmp0_subject: kotlin.Any?
|
VAR val tmp0_subject: kotlin.Any?
|
||||||
GET_VAR x type=kotlin.Any? operator=null
|
GET_VAR x type=kotlin.Any? operator=null
|
||||||
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
IF type=kotlin.String operator=WHEN
|
||||||
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
LITERAL Null type=kotlin.Nothing? value='null'
|
|
||||||
then: LITERAL String type=kotlin.String value='null'
|
|
||||||
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
|
||||||
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
|
||||||
GET_OBJECT A type=A
|
|
||||||
then: LITERAL String type=kotlin.String value='A'
|
|
||||||
if: TYPE_OP operator=INSTANCEOF typeOperand=kotlin.String
|
|
||||||
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
|
||||||
then: LITERAL String type=kotlin.String value='String'
|
|
||||||
if: CALL .contains type=kotlin.Boolean operator=IN
|
|
||||||
$receiver: CALL .setOf type=kotlin.collections.Set<kotlin.Nothing> operator=null
|
|
||||||
element: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Any
|
|
||||||
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
||||||
then: LITERAL String type=kotlin.String value='nothingness?'
|
LITERAL Null type=kotlin.Nothing? value='null'
|
||||||
else: LITERAL String type=kotlin.String value='something'
|
then: LITERAL String type=kotlin.String value='null'
|
||||||
|
else: IF type=kotlin.String operator=WHEN
|
||||||
|
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
||||||
|
GET_OBJECT A type=A
|
||||||
|
then: LITERAL String type=kotlin.String value='A'
|
||||||
|
else: IF type=kotlin.String operator=WHEN
|
||||||
|
if: TYPE_OP operator=INSTANCEOF typeOperand=kotlin.String
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
||||||
|
then: LITERAL String type=kotlin.String value='String'
|
||||||
|
else: IF type=kotlin.String operator=WHEN
|
||||||
|
if: CALL .contains type=kotlin.Boolean operator=IN
|
||||||
|
$receiver: CALL .setOf type=kotlin.collections.Set<kotlin.Nothing> operator=null
|
||||||
|
element: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
||||||
|
then: LITERAL String type=kotlin.String value='nothingness?'
|
||||||
|
else: LITERAL String type=kotlin.String value='something'
|
||||||
IrFunction public fun test(/*0*/ x: kotlin.Any?): kotlin.String
|
IrFunction public fun test(/*0*/ x: kotlin.Any?): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
BLOCK type=<no-type> hasResult=false operator=null
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
RETURN type=<no-type>
|
RETURN type=<no-type>
|
||||||
WHEN subject=null type=kotlin.String
|
IF type=kotlin.String operator=WHEN
|
||||||
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=public open operator fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=public open operator fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
GET_VAR x type=kotlin.Any? operator=null
|
GET_VAR x type=kotlin.Any? operator=null
|
||||||
LITERAL Null type=kotlin.Nothing? value='null'
|
LITERAL Null type=kotlin.Nothing? value='null'
|
||||||
then: LITERAL String type=kotlin.String value='null'
|
then: LITERAL String type=kotlin.String value='null'
|
||||||
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=public open operator fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
else: IF type=kotlin.String operator=WHEN
|
||||||
GET_VAR x type=kotlin.Any? operator=null
|
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=public open operator fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
GET_OBJECT A type=A
|
|
||||||
then: LITERAL String type=kotlin.String value='A'
|
|
||||||
if: TYPE_OP operator=INSTANCEOF typeOperand=kotlin.String
|
|
||||||
GET_VAR x type=kotlin.Any? operator=null
|
|
||||||
then: LITERAL String type=kotlin.String value='String'
|
|
||||||
if: CALL .contains type=kotlin.Boolean operator=IN
|
|
||||||
$receiver: CALL .setOf type=kotlin.collections.Set<kotlin.Nothing> operator=null
|
|
||||||
element: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Any
|
|
||||||
GET_VAR x type=kotlin.Any? operator=null
|
GET_VAR x type=kotlin.Any? operator=null
|
||||||
then: LITERAL String type=kotlin.String value='nothingness?'
|
GET_OBJECT A type=A
|
||||||
else: LITERAL String type=kotlin.String value='something'
|
then: LITERAL String type=kotlin.String value='A'
|
||||||
|
else: IF type=kotlin.String operator=WHEN
|
||||||
|
if: TYPE_OP operator=INSTANCEOF typeOperand=kotlin.String
|
||||||
|
GET_VAR x type=kotlin.Any? operator=null
|
||||||
|
then: LITERAL String type=kotlin.String value='String'
|
||||||
|
else: IF type=kotlin.String operator=WHEN
|
||||||
|
if: CALL .contains type=kotlin.Boolean operator=IN
|
||||||
|
$receiver: CALL .setOf type=kotlin.collections.Set<kotlin.Nothing> operator=null
|
||||||
|
element: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||||
|
GET_VAR x type=kotlin.Any? operator=null
|
||||||
|
then: LITERAL String type=kotlin.String value='nothingness?'
|
||||||
|
else: LITERAL String type=kotlin.String value='something'
|
||||||
|
IrFunction public fun testComma(/*0*/ x: kotlin.Int): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=<no-type> hasResult=false operator=null
|
||||||
|
RETURN type=<no-type>
|
||||||
|
BLOCK type=kotlin.String hasResult=true operator=WHEN
|
||||||
|
VAR val tmp0_subject: kotlin.Int
|
||||||
|
GET_VAR x type=kotlin.Int operator=null
|
||||||
|
IF type=kotlin.String operator=WHEN
|
||||||
|
if: IF type=kotlin.Boolean operator=WHEN_COMMA
|
||||||
|
if: IF type=kotlin.Boolean operator=WHEN_COMMA
|
||||||
|
if: IF type=kotlin.Boolean operator=WHEN_COMMA
|
||||||
|
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='1'
|
||||||
|
then: LITERAL Boolean type=kotlin.Boolean value='true'
|
||||||
|
else: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='2'
|
||||||
|
then: LITERAL Boolean type=kotlin.Boolean value='true'
|
||||||
|
else: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='3'
|
||||||
|
then: LITERAL Boolean type=kotlin.Boolean value='true'
|
||||||
|
else: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='4'
|
||||||
|
then: LITERAL String type=kotlin.String value='1234'
|
||||||
|
else: IF type=kotlin.String operator=WHEN
|
||||||
|
if: IF type=kotlin.Boolean operator=WHEN_COMMA
|
||||||
|
if: IF type=kotlin.Boolean operator=WHEN_COMMA
|
||||||
|
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='5'
|
||||||
|
then: LITERAL Boolean type=kotlin.Boolean value='true'
|
||||||
|
else: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='6'
|
||||||
|
then: LITERAL Boolean type=kotlin.Boolean value='true'
|
||||||
|
else: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='7'
|
||||||
|
then: LITERAL String type=kotlin.String value='567'
|
||||||
|
else: IF type=kotlin.String operator=WHEN
|
||||||
|
if: IF type=kotlin.Boolean operator=WHEN_COMMA
|
||||||
|
if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='8'
|
||||||
|
then: LITERAL Boolean type=kotlin.Boolean value='true'
|
||||||
|
else: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null
|
||||||
|
GET_VAR tmp0_subject type=kotlin.Int operator=null
|
||||||
|
LITERAL Int type=kotlin.Int value='9'
|
||||||
|
then: LITERAL String type=kotlin.String value='89'
|
||||||
|
else: LITERAL String type=kotlin.String value='?'
|
||||||
|
|||||||
Reference in New Issue
Block a user