Refactoring.

'if' expressions (represented as 'when' without subject).
This commit is contained in:
Dmitry Petrov
2016-08-19 10:55:14 +03:00
committed by Dmitry Petrov
parent 1ddf889d8a
commit 5709826096
28 changed files with 362 additions and 91 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.psi2ir package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -24,6 +25,8 @@ import org.jetbrains.kotlin.types.isNullabilityFlexible
fun IrExpression.toExpectedType(expectedType: KotlinType?): IrExpression { fun IrExpression.toExpectedType(expectedType: KotlinType?): IrExpression {
if (expectedType == null) return this if (expectedType == null) return this
if (KotlinBuiltIns.isUnit(expectedType)) return this // TODO expose coercion to Unit in IR?
val valueType = type ?: throw AssertionError("expectedType != null, valueType == null: $this") val valueType = type ?: throw AssertionError("expectedType != null, valueType == null: $this")
if (valueType.isNullabilityFlexible() && !expectedType.isMarkedNullable) { if (valueType.isNullabilityFlexible() && !expectedType.isMarkedNullable) {
@@ -20,8 +20,8 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrModule import org.jetbrains.kotlin.ir.declarations.IrModule
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.generators.IrGeneratorContext import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.IrModuleGenerator import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator
import org.jetbrains.kotlin.psi2ir.transformations.foldStringConcatenation import org.jetbrains.kotlin.psi2ir.transformations.foldStringConcatenation
import org.jetbrains.kotlin.psi2ir.transformations.inlineDesugaredBlocks import org.jetbrains.kotlin.psi2ir.transformations.inlineDesugaredBlocks
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -33,8 +33,8 @@ class Psi2IrTranslator(val configuration: Configuration = Configuration()) {
) )
fun generateModule(moduleDescriptor: ModuleDescriptor, ktFiles: List<KtFile>, bindingContext: BindingContext): IrModule { fun generateModule(moduleDescriptor: ModuleDescriptor, ktFiles: List<KtFile>, bindingContext: BindingContext): IrModule {
val irGeneratorContext = IrGeneratorContext(moduleDescriptor, bindingContext) val irGeneratorContext = GeneratorContext(moduleDescriptor, bindingContext)
val irModule = IrModuleGenerator(irGeneratorContext).generateModule(ktFiles) val irModule = ModuleGenerator(irGeneratorContext).generateModule(ktFiles)
postprocess(irModule) postprocess(irModule)
return irModule return irModule
} }
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
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.generators.values.IrVariableLValue import org.jetbrains.kotlin.psi2ir.generators.values.VariableLValue
import org.jetbrains.kotlin.psi2ir.generators.values.IrValue import org.jetbrains.kotlin.psi2ir.generators.values.IrValue
import org.jetbrains.kotlin.psi2ir.generators.values.createRematerializableValue import org.jetbrains.kotlin.psi2ir.generators.values.createRematerializableValue
import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.psi2ir.toExpectedType
@@ -32,12 +32,12 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import java.util.* import java.util.*
class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenerator { class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator {
override val context: IrGeneratorContext get() = override val context: GeneratorContext get() =
irStatementGenerator.context statementGenerator.context
private val temporaryVariableFactory: IrTemporaryVariableFactory get() = private val temporaryVariableFactory: TemporaryVariableFactory get() =
irStatementGenerator.temporaryVariableFactory statementGenerator.temporaryVariableFactory
private val expressionValues = HashMap<KtExpression, IrValue>() private val expressionValues = HashMap<KtExpression, IrValue>()
private val receiverValues = HashMap<ReceiverValue, IrValue>() private val receiverValues = HashMap<ReceiverValue, IrValue>()
@@ -51,7 +51,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
} }
val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint) val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint)
putValue(ktExpression, IrVariableLValue(irTmpVar)) putValue(ktExpression, VariableLValue(irTmpVar))
return irTmpVar return irTmpVar
} }
@@ -63,7 +63,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
} }
val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, valueParameterDescriptor.name.asString()) val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, valueParameterDescriptor.name.asString())
putValue(valueParameterDescriptor, IrVariableLValue(irTmpVar)) putValue(valueParameterDescriptor, VariableLValue(irTmpVar))
return irTmpVar return irTmpVar
} }
@@ -249,6 +249,6 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
} }
private fun generateExpression(ktExpression: KtExpression): IrExpression = private fun generateExpression(ktExpression: KtExpression): IrExpression =
expressionValues[ktExpression]?.load() ?: irStatementGenerator.generateExpression(ktExpression) expressionValues[ktExpression]?.load() ?: statementGenerator.generateExpression(ktExpression)
} }
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.singletonList import org.jetbrains.kotlin.utils.addToStdlib.singletonList
class IrDeclarationGenerator(override val context: IrGeneratorContext) : IrGenerator { class DeclarationGenerator(override val context: GeneratorContext) : IrGenerator {
fun generateAnnotationEntries(annotationEntries: List<KtAnnotationEntry>) { fun generateAnnotationEntries(annotationEntries: List<KtAnnotationEntry>) {
// TODO create IrAnnotation's for each KtAnnotationEntry // TODO create IrAnnotation's for each KtAnnotationEntry
} }
@@ -140,7 +140,7 @@ class IrDeclarationGenerator(override val context: IrGeneratorContext) : IrGener
} }
private fun generateExpressionWithinContext(ktExpression: KtExpression, scopeOwner: DeclarationDescriptor): IrExpression = private fun generateExpressionWithinContext(ktExpression: KtExpression, scopeOwner: DeclarationDescriptor): IrExpression =
IrStatementGenerator(context, scopeOwner, IrTemporaryVariableFactory(scopeOwner)) StatementGenerator(context, scopeOwner, TemporaryVariableFactory(scopeOwner))
.generateExpression(ktExpression) .generateExpression(ktExpression)
.toExpectedType(getExpectedTypeForLastInferredCall(ktExpression)) .toExpectedType(getExpectedTypeForLastInferredCall(ktExpression))
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
interface IrGenerator { interface IrGenerator {
val context: IrGeneratorContext val context: GeneratorContext
} }
fun <K, V : Any> IrGenerator.get(slice: ReadOnlySlice<K, V>, key: K): V? = fun <K, V : Any> IrGenerator.get(slice: ReadOnlySlice<K, V>, key: K): V? =
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.psi2ir.PsiSourceManager
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
class IrGeneratorContext( class GeneratorContext(
val moduleDescriptor: ModuleDescriptor, val moduleDescriptor: ModuleDescriptor,
val bindingContext: BindingContext val bindingContext: BindingContext
) { ) {
@@ -20,9 +20,9 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
class IrModuleGenerator(override val context: IrGeneratorContext) : IrGenerator { class ModuleGenerator(override val context: GeneratorContext) : IrGenerator {
fun generateModule(ktFiles: List<KtFile>): IrModule { fun generateModule(ktFiles: List<KtFile>): IrModule {
val irDeclarationGenerator = IrDeclarationGenerator(context) val irDeclarationGenerator = DeclarationGenerator(context)
val irModule = IrModuleImpl(context.moduleDescriptor) val irModule = IrModuleImpl(context.moduleDescriptor)
for (ktFile in ktFiles) { for (ktFile in ktFiles) {
@@ -20,12 +20,10 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtArrayAccessExpression import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPrefixExpression
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.generators.values.* import org.jetbrains.kotlin.psi2ir.generators.values.*
@@ -36,8 +34,8 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator { class OperatorExpressionGenerator(val statementGenerator: StatementGenerator): IrGenerator {
override val context: IrGeneratorContext get() = irStatementGenerator.context override val context: GeneratorContext get() = statementGenerator.context
fun generatePrefixExpression(expression: KtPrefixExpression): IrExpression { fun generatePrefixExpression(expression: KtPrefixExpression): IrExpression {
val ktOperator = expression.operationReference.getReferencedNameElementType() val ktOperator = expression.operationReference.getReferencedNameElementType()
@@ -50,6 +48,10 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
} }
} }
fun generatePostfixExpression(expression: KtPostfixExpression): IrExpression {
TODO("not implemented")
}
fun generateBinaryExpression(expression: KtBinaryExpression): IrExpression { fun generateBinaryExpression(expression: KtBinaryExpression): IrExpression {
val ktOperator = expression.operationReference.getReferencedNameElementType() val ktOperator = expression.operationReference.getReferencedNameElementType()
if (ktOperator == KtTokens.IDENTIFIER) { if (ktOperator == KtTokens.IDENTIFIER) {
@@ -77,8 +79,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
// TODO desugar '?:' to 'if'? // TODO desugar '?:' to 'if'?
val specialCallForElvis = getResolvedCall(expression)!! val specialCallForElvis = getResolvedCall(expression)!!
val returnType = specialCallForElvis.resultingDescriptor.returnType!! val returnType = specialCallForElvis.resultingDescriptor.returnType!!
val irArgument0 = irStatementGenerator.generateExpression(expression.left!!).toExpectedType(returnType.makeNullable()) val irArgument0 = statementGenerator.generateExpression(expression.left!!).toExpectedType(returnType.makeNullable())
val irArgument1 = irStatementGenerator.generateExpression(expression.right!!).toExpectedType(returnType) val irArgument1 = statementGenerator.generateExpression(expression.right!!).toExpectedType(returnType)
return IrBinaryOperatorExpressionImpl( return IrBinaryOperatorExpressionImpl(
expression.startOffset, expression.endOffset, returnType, expression.startOffset, expression.endOffset, returnType,
IrOperator.ELVIS, null, irArgument0, irArgument1 IrOperator.ELVIS, null, irArgument0, irArgument1
@@ -86,8 +88,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
} }
private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrBinaryOperator): IrExpression { private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrBinaryOperator): IrExpression {
val irArgument0 = irStatementGenerator.generateExpression(expression.left!!).toExpectedType(context.builtIns.booleanType) val irArgument0 = statementGenerator.generateExpression(expression.left!!).toExpectedType(context.builtIns.booleanType)
val irArgument1 = irStatementGenerator.generateExpression(expression.right!!).toExpectedType(context.builtIns.booleanType) val irArgument1 = statementGenerator.generateExpression(expression.right!!).toExpectedType(context.builtIns.booleanType)
return IrBinaryOperatorExpressionImpl( return IrBinaryOperatorExpressionImpl(
expression.startOffset, expression.endOffset, context.builtIns.booleanType, expression.startOffset, expression.endOffset, context.builtIns.booleanType,
irOperator, getResolvedCall(expression)?.resultingDescriptor, irArgument0, irArgument1 irOperator, getResolvedCall(expression)?.resultingDescriptor, irArgument0, irArgument1
@@ -97,7 +99,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
private fun generateInOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression { private fun generateInOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
val operatorCall = getResolvedCall(expression)!! val operatorCall = getResolvedCall(expression)!!
val irOperatorCall = IrCallGenerator(irStatementGenerator).generateCall(expression, operatorCall, irOperator) val irOperatorCall = CallGenerator(statementGenerator).generateCall(expression, operatorCall, irOperator)
return if (irOperator == IrOperator.IN) return if (irOperator == IrOperator.IN)
irOperatorCall irOperatorCall
@@ -107,8 +109,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
} }
private fun generateIdentityOperator(expression: KtBinaryExpression, irOperator: IrBinaryOperator): IrExpression { private fun generateIdentityOperator(expression: KtBinaryExpression, irOperator: IrBinaryOperator): IrExpression {
val irArgument0 = irStatementGenerator.generateExpression(expression.left!!) val irArgument0 = statementGenerator.generateExpression(expression.left!!)
val irArgument1 = irStatementGenerator.generateExpression(expression.right!!) val irArgument1 = statementGenerator.generateExpression(expression.right!!)
return IrBinaryOperatorExpressionImpl( return IrBinaryOperatorExpressionImpl(
expression.startOffset, expression.endOffset, context.builtIns.booleanType, expression.startOffset, expression.endOffset, context.builtIns.booleanType,
irOperator, null, irArgument0, irArgument1 irOperator, null, irArgument0, irArgument1
@@ -119,7 +121,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
val relatedCall = getResolvedCall(expression)!! val relatedCall = getResolvedCall(expression)!!
val relatedDescriptor = relatedCall.resultingDescriptor val relatedDescriptor = relatedCall.resultingDescriptor
val irCallGenerator = IrCallGenerator(irStatementGenerator) val irCallGenerator = CallGenerator(statementGenerator)
// NB special typing rules for equality operators: both arguments are nullable // NB special typing rules for equality operators: both arguments are nullable
@@ -144,7 +146,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
val compareToCall = getResolvedCall(expression)!! val compareToCall = getResolvedCall(expression)!!
val compareToDescriptor = compareToCall.resultingDescriptor val compareToDescriptor = compareToCall.resultingDescriptor
val irCallGenerator = IrCallGenerator(irStatementGenerator) val irCallGenerator = CallGenerator(statementGenerator)
return if (shouldKeepComparisonAsBinaryOperation(compareToDescriptor)) { return if (shouldKeepComparisonAsBinaryOperation(compareToDescriptor)) {
val irArgument0 = irCallGenerator.generateReceiver(expression.left!!, compareToCall.dispatchReceiver, compareToDescriptor.dispatchReceiverParameter!!)!! val irArgument0 = irCallGenerator.generateReceiver(expression.left!!, compareToCall.dispatchReceiver, compareToDescriptor.dispatchReceiverParameter!!)!!
@@ -172,7 +174,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
private fun generateBinaryOperatorWithConventionalCall(expression: KtBinaryExpression, irOperator: IrOperator?): IrExpression { private fun generateBinaryOperatorWithConventionalCall(expression: KtBinaryExpression, irOperator: IrOperator?): IrExpression {
val operatorCall = getResolvedCall(expression)!! val operatorCall = getResolvedCall(expression)!!
return IrCallGenerator(irStatementGenerator).generateCall(expression, operatorCall, irOperator) return CallGenerator(statementGenerator).generateCall(expression, operatorCall, irOperator)
} }
private fun generatePrefixIncrementDecrementOperator(expression: KtPrefixExpression, irOperator: IrOperator): IrExpression { private fun generatePrefixIncrementDecrementOperator(expression: KtPrefixExpression, irOperator: IrOperator): IrExpression {
@@ -184,10 +186,10 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
return irLValue.prefixAugmentedStore(operatorCall, irOperator) return irLValue.prefixAugmentedStore(operatorCall, irOperator)
} }
val opCallGenerator = IrCallGenerator(irStatementGenerator).apply { putValue(ktBaseExpression, irLValue) } val opCallGenerator = CallGenerator(statementGenerator).apply { putValue(ktBaseExpression, irLValue) }
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, irLValue.type, true, irOperator) val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, irLValue.type, true, irOperator)
val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator) val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator)
val irTmp = irStatementGenerator.temporaryVariableFactory.createTemporaryVariable(irOpCall) val irTmp = statementGenerator.temporaryVariableFactory.createTemporaryVariable(irOpCall)
irBlock.addStatement(irTmp) irBlock.addStatement(irTmp)
irBlock.addStatement(irLValue.store(irTmp.load())) irBlock.addStatement(irLValue.store(irTmp.load()))
irBlock.addStatement(irTmp.load()) irBlock.addStatement(irTmp.load())
@@ -202,10 +204,10 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false
if (isSimpleAssignment && irLValue is IrLValueWithAugmentedStore) { if (isSimpleAssignment && irLValue is IrLValueWithAugmentedStore) {
return irLValue.augmentedStore(operatorCall, irOperator, irStatementGenerator.generateExpression(expression.right!!)) return irLValue.augmentedStore(operatorCall, irOperator, statementGenerator.generateExpression(expression.right!!))
} }
val opCallGenerator = IrCallGenerator(irStatementGenerator).apply { putValue(ktLeft, irLValue) } val opCallGenerator = CallGenerator(statementGenerator).apply { putValue(ktLeft, irLValue) }
val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator) val irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator)
return if (isSimpleAssignment) { return if (isSimpleAssignment) {
@@ -222,20 +224,20 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
val ktLeft = expression.left!! val ktLeft = expression.left!!
val ktRight = expression.right!! val ktRight = expression.right!!
val irLValue = generateLValue(ktLeft, IrOperator.EQ) val irLValue = generateLValue(ktLeft, IrOperator.EQ)
return irLValue.store(irStatementGenerator.generateExpression(ktRight)) return irLValue.store(statementGenerator.generateExpression(ktRight))
} }
private fun generateLValue(ktLeft: KtExpression, irOperator: IrOperator?): IrLValue { private fun generateLValue(ktLeft: KtExpression, irOperator: IrOperator?): IrLValue {
if (ktLeft is KtArrayAccessExpression) { if (ktLeft is KtArrayAccessExpression) {
val irArrayValue = irStatementGenerator.generateExpression(ktLeft.arrayExpression!!) val irArrayValue = statementGenerator.generateExpression(ktLeft.arrayExpression!!)
val indexExpressions = ktLeft.indexExpressions.map { it to irStatementGenerator.generateExpression(it) } val indexExpressions = ktLeft.indexExpressions.map { it to statementGenerator.generateExpression(it) }
val indexedGetCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft) val indexedGetCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft)
val indexedSetCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft) val indexedSetCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft)
val type = indexedGetCall?.run { resultingDescriptor.returnType } val type = indexedGetCall?.run { resultingDescriptor.returnType }
?: indexedSetCall?.run { resultingDescriptor.valueParameters.last().type } ?: indexedSetCall?.run { resultingDescriptor.valueParameters.last().type }
?: throw AssertionError("Either 'get' or 'set' call should be present for an indexed LValue: ${ktLeft.text}") ?: throw AssertionError("Either 'get' or 'set' call should be present for an indexed LValue: ${ktLeft.text}")
return IrIndexedLValue(irStatementGenerator, ktLeft, irOperator, return IndexedLValue(statementGenerator, ktLeft, irOperator,
irArrayValue, type, indexExpressions, indexedGetCall, indexedSetCall) irArrayValue, type, indexExpressions, indexedGetCall, indexedSetCall)
} }
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS") val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
@@ -246,10 +248,10 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
if (descriptor.isDelegated) if (descriptor.isDelegated)
TODO("Delegated local variable") TODO("Delegated local variable")
else else
IrVariableLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, irOperator) VariableLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, irOperator)
is PropertyDescriptor -> is PropertyDescriptor ->
IrCallGenerator(irStatementGenerator).run { CallGenerator(statementGenerator).run {
IrPropertyLValue( PropertyLValue(
ktLeft, irOperator, descriptor, ktLeft, irOperator, descriptor,
generateReceiver(ktLeft, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter), generateReceiver(ktLeft, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter),
generateReceiver(ktLeft, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter), generateReceiver(ktLeft, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter),
@@ -26,7 +26,7 @@ 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.deparenthesize import org.jetbrains.kotlin.psi2ir.deparenthesize
import org.jetbrains.kotlin.psi2ir.generators.values.IrVariableLValue import org.jetbrains.kotlin.psi2ir.generators.values.VariableLValue
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 org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.BindingContextUtils
@@ -38,17 +38,17 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat
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
class IrStatementGenerator( class StatementGenerator(
override val context: IrGeneratorContext, override val context: GeneratorContext,
val scopeOwner: DeclarationDescriptor, val scopeOwner: DeclarationDescriptor,
val temporaryVariableFactory: IrTemporaryVariableFactory val temporaryVariableFactory: TemporaryVariableFactory
) : KtVisitor<IrStatement, Nothing?>(), IrGenerator { ) : KtVisitor<IrStatement, Nothing?>(), IrGenerator {
fun generateExpression(ktExpression: KtExpression): IrExpression = fun generateExpression(ktExpression: KtExpression): IrExpression =
ktExpression.genExpr() ktExpression.genExpr()
private fun KtElement.genStmt(): IrStatement = private fun KtElement.genStmt(): IrStatement =
deparenthesize().accept(this@IrStatementGenerator, null) deparenthesize().accept(this@StatementGenerator, null)
private fun KtElement.genExpr(): IrExpression = private fun KtElement.genExpr(): IrExpression =
genStmt().assertCast() genStmt().assertCast()
@@ -77,8 +77,8 @@ class IrStatementGenerator(
val irTmpInitializer = temporaryVariableFactory.createTemporaryVariable(ktInitializer.genExpr()) val irTmpInitializer = temporaryVariableFactory.createTemporaryVariable(ktInitializer.genExpr())
irBlock.addStatement(irTmpInitializer) irBlock.addStatement(irTmpInitializer)
val irCallGenerator = IrCallGenerator(this) val irCallGenerator = CallGenerator(this)
irCallGenerator.putValue(ktInitializer, IrVariableLValue(irTmpInitializer)) irCallGenerator.putValue(ktInitializer, VariableLValue(irTmpInitializer))
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) { for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry) val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
@@ -188,7 +188,7 @@ class IrStatementGenerator(
companionObjectDescriptor) companionObjectDescriptor)
} }
is PropertyDescriptor -> { is PropertyDescriptor -> {
IrCallGenerator(this).generateCall(expression, resolvedCall) CallGenerator(this).generateCall(expression, resolvedCall)
} }
is VariableDescriptor -> is VariableDescriptor ->
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor) IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor)
@@ -207,7 +207,7 @@ class IrStatementGenerator(
TODO("VariableAsFunctionResolvedCall = variable call + invoke call") TODO("VariableAsFunctionResolvedCall = variable call + invoke call")
} }
return IrCallGenerator(this).generateCall(expression, resolvedCall) return CallGenerator(this).generateCall(expression, resolvedCall)
} }
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Nothing?): IrStatement = override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Nothing?): IrStatement =
@@ -239,8 +239,38 @@ class IrStatementGenerator(
} }
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Nothing?): IrStatement = override fun visitBinaryExpression(expression: KtBinaryExpression, data: Nothing?): IrStatement =
IrOperatorExpressionGenerator(this).generateBinaryExpression(expression) OperatorExpressionGenerator(this).generateBinaryExpression(expression)
override fun visitPrefixExpression(expression: KtPrefixExpression, data: Nothing?): IrStatement = override fun visitPrefixExpression(expression: KtPrefixExpression, data: Nothing?): IrStatement =
IrOperatorExpressionGenerator(this).generatePrefixExpression(expression) OperatorExpressionGenerator(this).generatePrefixExpression(expression)
override fun visitPostfixExpression(expression: KtPostfixExpression, data: Nothing?): IrStatement =
OperatorExpressionGenerator(this).generatePostfixExpression(expression)
override fun visitIfExpression(expression: KtIfExpression, data: Nothing?): IrStatement {
val resultType = getInferredTypeWithSmartcasts(expression)
val irWhen = IrWhenExpressionImpl(expression.startOffset, expression.endOffset, resultType)
var ktBranch: KtIfExpression? = expression
branches@while (ktBranch != null) {
val irBranch = IrBranchImpl(ktBranch.startOffset, ktBranch.endOffset,
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
}
} }
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class IrTemporaryVariableFactory(val scopeOwner: DeclarationDescriptor) { class TemporaryVariableFactory(val scopeOwner: DeclarationDescriptor) {
private var lastTemporaryIndex = 0 private var lastTemporaryIndex = 0
private fun nextTemporaryIndex() = lastTemporaryIndex++ private fun nextTemporaryIndex() = lastTemporaryIndex++
@@ -22,13 +22,13 @@ import org.jetbrains.kotlin.psi.KtExpression
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.load import org.jetbrains.kotlin.psi2ir.load
import org.jetbrains.kotlin.psi2ir.generators.IrCallGenerator import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
import org.jetbrains.kotlin.psi2ir.generators.IrStatementGenerator import org.jetbrains.kotlin.psi2ir.generators.StatementGenerator
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class IrIndexedLValue( class IndexedLValue(
var irStatementGenerator: IrStatementGenerator, var statementGenerator: StatementGenerator,
val ktArrayAccessExpression: KtArrayAccessExpression, val ktArrayAccessExpression: KtArrayAccessExpression,
val irOperator: IrOperator?, val irOperator: IrOperator?,
val irArray: IrExpression, val irArray: IrExpression,
@@ -50,7 +50,7 @@ class IrIndexedLValue(
} }
private fun generateGetOrSetCallAsDesugaredBlock(call: ResolvedCall<*>, irArgument: IrExpression? = null): IrExpression { private fun generateGetOrSetCallAsDesugaredBlock(call: ResolvedCall<*>, irArgument: IrExpression? = null): IrExpression {
val callGenerator = IrCallGenerator(irStatementGenerator) val callGenerator = CallGenerator(statementGenerator)
setupCallGeneratorContext(callGenerator) setupCallGeneratorContext(callGenerator)
if (irArgument != null) { if (irArgument != null) {
@@ -64,19 +64,19 @@ class IrIndexedLValue(
if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}") if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}")
if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}") if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}")
val callGenerator = IrCallGenerator(irStatementGenerator) val callGenerator = CallGenerator(statementGenerator)
val irBlock = createDesugaredBlockWithTemporaries(indexedSetCall, callGenerator, true, irOperator) val irBlock = createDesugaredBlockWithTemporaries(indexedSetCall, callGenerator, true, irOperator)
val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver
callGenerator.putValue(operatorCallReceiver!!, callGenerator.putValue(operatorCallReceiver!!,
IrSingleExpressionValue(callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator))) IrSingleExpressionValue(callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator)))
val irTmp = irStatementGenerator.temporaryVariableFactory.createTemporaryVariable( val irTmp = statementGenerator.temporaryVariableFactory.createTemporaryVariable(
callGenerator.generateCall(ktArrayAccessExpression, operatorCall, irOperator)) callGenerator.generateCall(ktArrayAccessExpression, operatorCall, irOperator))
irBlock.addStatement(irTmp) irBlock.addStatement(irTmp)
callGenerator.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(), callGenerator.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(),
IrVariableLValue(irTmp)) VariableLValue(irTmp))
irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator)) irBlock.addStatement(callGenerator.generateCall(ktArrayAccessExpression, indexedSetCall, irOperator))
@@ -89,7 +89,7 @@ class IrIndexedLValue(
if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}") if (indexedGetCall == null) throw AssertionError("Indexed LValue has no 'get' call: ${ktArrayAccessExpression.text}")
if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}") if (indexedSetCall == null) throw AssertionError("Indexed LValue has no 'set' call: ${ktArrayAccessExpression.text}")
val callGenerator = IrCallGenerator(irStatementGenerator) val callGenerator = CallGenerator(statementGenerator)
val irBlock = createDesugaredBlockWithTemporaries(indexedSetCall, callGenerator, false, irOperator) val irBlock = createDesugaredBlockWithTemporaries(indexedSetCall, callGenerator, false, irOperator)
@@ -109,7 +109,7 @@ class IrIndexedLValue(
private fun createDesugaredBlockWithTemporaries( private fun createDesugaredBlockWithTemporaries(
call: ResolvedCall<*>, call: ResolvedCall<*>,
callGenerator: IrCallGenerator, callGenerator: CallGenerator,
hasResult: Boolean, hasResult: Boolean,
operator: IrOperator? operator: IrOperator?
): IrBlockExpressionImpl { ): IrBlockExpressionImpl {
@@ -124,7 +124,7 @@ class IrIndexedLValue(
hasResult, operator) hasResult, operator)
} }
private fun defineTemporaryVariables(irBlock: IrBlockExpression, callGenerator: IrCallGenerator) { private fun defineTemporaryVariables(irBlock: IrBlockExpression, callGenerator: CallGenerator) {
irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array")) irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array"))
var index = 0 var index = 0
@@ -133,7 +133,7 @@ class IrIndexedLValue(
} }
} }
private fun setupCallGeneratorContext(callGenerator: IrCallGenerator) { private fun setupCallGeneratorContext(callGenerator: CallGenerator) {
callGenerator.putValue(ktArrayAccessExpression.arrayExpression!!, IrSingleExpressionValue(irArray)) callGenerator.putValue(ktArrayAccessExpression.arrayExpression!!, IrSingleExpressionValue(irArray))
for ((ktIndexExpression, irIndexValue) in indexValues) { for ((ktIndexExpression, irIndexValue) in indexValues) {
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class IrPropertyLValue( class PropertyLValue(
val ktElement: KtElement, val ktElement: KtElement,
val irOperator: IrOperator?, val irOperator: IrOperator?,
val descriptor: PropertyDescriptor, val descriptor: PropertyDescriptor,
@@ -37,8 +37,8 @@ class IrPropertyLValue(
private fun IrPropertyAccessExpression.setReceivers() = private fun IrPropertyAccessExpression.setReceivers() =
apply { apply {
dispatchReceiver = this@IrPropertyLValue.dispatchReceiver dispatchReceiver = this@PropertyLValue.dispatchReceiver
extensionReceiver = this@IrPropertyLValue.extensionReceiver extensionReceiver = this@PropertyLValue.extensionReceiver
} }
override fun load(): IrExpression = override fun load(): IrExpression =
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.ir.expressions.IrSetVariableExpressionImpl
import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.psi2ir.toExpectedType
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
class IrVariableLValue( class VariableLValue(
val startOffset: Int, val startOffset: Int,
val endOffset: Int, val endOffset: Int,
val descriptor: VariableDescriptor, val descriptor: VariableDescriptor,
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.ir package org.jetbrains.kotlin.ir
const val CHILD_DECLARATION_SLOT = 0
const val DETACHED_SLOT = Int.MIN_VALUE const val DETACHED_SLOT = Int.MIN_VALUE
const val CHILD_EXPRESSION_SLOT = 0 const val CHILD_EXPRESSION_SLOT = 0
const val ARGUMENT0_SLOT = 0 const val ARGUMENT0_SLOT = 0
@@ -26,3 +25,7 @@ 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 WHEN_ELSE_EXPRESSION_SLOT = -2
const val BRANCH_CONDITION_SLOT = -1
const val BRANCH_RESULT_SLOT = -2
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.ir.expressions package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.assertCast
import org.jetbrains.kotlin.ir.assertDetached
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
import java.util.* import java.util.*
@@ -56,8 +53,11 @@ class IrBlockExpressionImpl(
statements.getOrNull(slot) statements.getOrNull(slot)
override fun replaceChild(slot: Int, newChild: IrElement) { override fun replaceChild(slot: Int, newChild: IrElement) {
newChild.assertDetached()
if (0 <= slot && slot < statements.size) { if (0 <= slot && slot < statements.size) {
statements[slot].detach()
statements[slot] = newChild.assertCast() statements[slot] = newChild.assertCast()
newChild.setTreeLocation(this, slot)
} }
} }
@@ -0,0 +1,171 @@
/*
* 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 java.util.*
interface IrWhenExpression : IrExpression {
var subject: IrVariable?
val branches: List<IrBranch>
var elseExpression: IrExpression?
fun addBranch(branch: IrBranch)
}
interface IrBranch : IrElement {
var condition: IrExpression
var result: 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.condition = condition
this.result = result
}
private var conditionImpl: IrExpression? = null
override var condition: IrExpression
get() = conditionImpl!!
set(value) {
value.assertDetached()
conditionImpl?.detach()
conditionImpl = value
value.setTreeLocation(this, BRANCH_CONDITION_SLOT)
}
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_CONDITION_SLOT -> condition
BRANCH_RESULT_SLOT -> result
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
BRANCH_CONDITION_SLOT ->
condition = newChild.assertCast()
BRANCH_RESULT_SLOT ->
result = newChild.assertCast()
}
}
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) {
conditionImpl?.accept(visitor, data)
resultImpl?.accept(visitor, data)
}
}
@@ -22,6 +22,7 @@ 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.IrGetPropertyExpression import org.jetbrains.kotlin.ir.expressions.IrGetPropertyExpression
import org.jetbrains.kotlin.ir.expressions.IrSetPropertyExpression import org.jetbrains.kotlin.ir.expressions.IrSetPropertyExpression
import org.jetbrains.kotlin.ir.expressions.IrWhenExpression
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
@@ -70,6 +71,19 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
} }
} }
override fun visitWhenExpression(expression: IrWhenExpression, data: String) {
expression.dumpLabeledElementWith(data) {
expression.subject?.let { subject ->
subject.accept(this, "\$subject:")
}
for (branch in expression.branches) {
branch.condition.accept(this, "if")
branch.result.accept(this, "then")
}
expression.elseExpression?.accept(this, "else")
}
}
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)
@@ -112,9 +112,14 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitStringConcatenation(expression: IrStringConcatenationExpression, data: Nothing?): String = override fun visitStringConcatenation(expression: IrStringConcatenationExpression, data: Nothing?): String =
"STRING_CONCATENATION type=${expression.renderType()}" "STRING_CONCATENATION type=${expression.renderType()}"
override fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: Nothing?): String { override fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: Nothing?): String =
return "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 =
"WHEN subject=${expression.subject?.descriptor?.name} type=${expression.type.render()}"
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}"
@@ -63,8 +63,10 @@ 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 visitBranch(branch: IrBranch, data: D): R = visitElement(branch, data)
// NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered // NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered
fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: D) = visitDeclaration(declaration, data) fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: D) = visitDeclaration(declaration, data)
fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data) fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data)
} }
+8 -2
View File
@@ -16,8 +16,14 @@ 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
DUMMY KtIfExpression type=kotlin.Unit WHEN subject=null type=kotlin.Unit
DUMMY KtIfExpression type=kotlin.Unit if: DUMMY KtIsExpression type=kotlin.Boolean
then: RETURN type=<no-type>
LITERAL String type=kotlin.String value=''
WHEN subject=null type=kotlin.Unit
if: DUMMY KtIsExpression type=kotlin.Boolean
then: RETURN type=<no-type>
LITERAL String type=kotlin.String value=''
RETURN type=<no-type> RETURN type=<no-type>
BINARY_OP operator=ELVIS type=kotlin.String related=null BINARY_OP operator=ELVIS type=kotlin.String related=null
TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String? TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String?
+4
View File
@@ -0,0 +1,4 @@
fun test(i: Int) =
if (i > 0) 1
else if (i < 0) -1
else 0
+15
View File
@@ -0,0 +1,15 @@
IrFile /ifElseIf.kt
IrFunction public fun test(/*0*/ i: kotlin.Int): kotlin.Int
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
RETURN type=<no-type>
WHEN subject=null type=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
LITERAL Int type=kotlin.Int value='0'
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
GET_VAR i type=kotlin.Int operator=null
LITERAL Int type=kotlin.Int value='0'
then: DUMMY MINUS type=kotlin.Int
else: LITERAL Int type=kotlin.Int value='0'
+11 -3
View File
@@ -18,7 +18,9 @@ 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
DUMMY KtIfExpression type=kotlin.Unit WHEN subject=null type=kotlin.Unit
if: DUMMY KtIsExpression type=kotlin.Boolean
then: RETURN type=<no-type>
CALL .println type=kotlin.Unit operator=null CALL .println type=kotlin.Unit operator=null
message: GET_PROPERTY .length type=kotlin.Int operator=null message: GET_PROPERTY .length type=kotlin.Int operator=null
$this: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String $this: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
@@ -37,7 +39,10 @@ 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
DUMMY KtIfExpression type=kotlin.Unit WHEN subject=null type=kotlin.Unit
if: DUMMY KtIsExpression type=kotlin.Boolean
then: RETURN type=<no-type>
LITERAL String type=kotlin.String value=''
RETURN type=<no-type> RETURN type=<no-type>
CALL .overloaded type=kotlin.String operator=null CALL .overloaded type=kotlin.String operator=null
s: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String s: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
@@ -45,7 +50,10 @@ 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
DUMMY KtIfExpression type=kotlin.Unit WHEN subject=null type=kotlin.Unit
if: DUMMY KtIsExpression type=kotlin.Boolean
then: RETURN type=<no-type>
LITERAL String type=kotlin.String value=''
RETURN type=<no-type> RETURN type=<no-type>
TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR x type=kotlin.Any operator=null GET_VAR x type=kotlin.Any operator=null
@@ -14,7 +14,9 @@ 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
DUMMY KtIfExpression type=kotlin.Unit WHEN subject=null type=kotlin.Unit
if: DUMMY KtIsExpression type=kotlin.Boolean
then: RETURN type=<no-type>
BLOCK type=<no-type> hasResult=false operator=SYNTHETIC_BLOCK BLOCK type=<no-type> hasResult=false operator=SYNTHETIC_BLOCK
VAR val tmp0: I1 VAR val tmp0: I1
GET_VAR x type=I1 operator=null GET_VAR x type=I1 operator=null
@@ -137,6 +137,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("ifElseIf.kt")
public void testIfElseIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/ifElseIf.kt");
doTest(fileName);
}
@TestMetadata("implicitCastOnPlatformType.kt") @TestMetadata("implicitCastOnPlatformType.kt")
public void testImplicitCastOnPlatformType() throws Exception { public void testImplicitCastOnPlatformType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/implicitCastOnPlatformType.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/implicitCastOnPlatformType.kt");