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
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.types.KotlinType
@@ -24,6 +25,8 @@ import org.jetbrains.kotlin.types.isNullabilityFlexible
fun IrExpression.toExpectedType(expectedType: KotlinType?): IrExpression {
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")
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.declarations.IrModule
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.generators.IrGeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.IrModuleGenerator
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator
import org.jetbrains.kotlin.psi2ir.transformations.foldStringConcatenation
import org.jetbrains.kotlin.psi2ir.transformations.inlineDesugaredBlocks
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 {
val irGeneratorContext = IrGeneratorContext(moduleDescriptor, bindingContext)
val irModule = IrModuleGenerator(irGeneratorContext).generateModule(ktFiles)
val irGeneratorContext = GeneratorContext(moduleDescriptor, bindingContext)
val irModule = ModuleGenerator(irGeneratorContext).generateModule(ktFiles)
postprocess(irModule)
return irModule
}
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
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.createRematerializableValue
import org.jetbrains.kotlin.psi2ir.toExpectedType
@@ -32,12 +32,12 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenerator {
override val context: IrGeneratorContext get() =
irStatementGenerator.context
class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator {
override val context: GeneratorContext get() =
statementGenerator.context
private val temporaryVariableFactory: IrTemporaryVariableFactory get() =
irStatementGenerator.temporaryVariableFactory
private val temporaryVariableFactory: TemporaryVariableFactory get() =
statementGenerator.temporaryVariableFactory
private val expressionValues = HashMap<KtExpression, IrValue>()
private val receiverValues = HashMap<ReceiverValue, IrValue>()
@@ -51,7 +51,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
}
val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint)
putValue(ktExpression, IrVariableLValue(irTmpVar))
putValue(ktExpression, VariableLValue(irTmpVar))
return irTmpVar
}
@@ -63,7 +63,7 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
}
val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, valueParameterDescriptor.name.asString())
putValue(valueParameterDescriptor, IrVariableLValue(irTmpVar))
putValue(valueParameterDescriptor, VariableLValue(irTmpVar))
return irTmpVar
}
@@ -249,6 +249,6 @@ class IrCallGenerator(val irStatementGenerator: IrStatementGenerator) : IrGenera
}
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.addToStdlib.singletonList
class IrDeclarationGenerator(override val context: IrGeneratorContext) : IrGenerator {
class DeclarationGenerator(override val context: GeneratorContext) : IrGenerator {
fun generateAnnotationEntries(annotationEntries: List<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 =
IrStatementGenerator(context, scopeOwner, IrTemporaryVariableFactory(scopeOwner))
StatementGenerator(context, scopeOwner, TemporaryVariableFactory(scopeOwner))
.generateExpression(ktExpression)
.toExpectedType(getExpectedTypeForLastInferredCall(ktExpression))
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
interface IrGenerator {
val context: IrGeneratorContext
val context: GeneratorContext
}
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.resolve.BindingContext
class IrGeneratorContext(
class GeneratorContext(
val moduleDescriptor: ModuleDescriptor,
val bindingContext: BindingContext
) {
@@ -20,9 +20,9 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.psi.KtFile
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 {
val irDeclarationGenerator = IrDeclarationGenerator(context)
val irDeclarationGenerator = DeclarationGenerator(context)
val irModule = IrModuleImpl(context.moduleDescriptor)
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.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPrefixExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
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
class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerator): IrGenerator {
override val context: IrGeneratorContext get() = irStatementGenerator.context
class OperatorExpressionGenerator(val statementGenerator: StatementGenerator): IrGenerator {
override val context: GeneratorContext get() = statementGenerator.context
fun generatePrefixExpression(expression: KtPrefixExpression): IrExpression {
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 {
val ktOperator = expression.operationReference.getReferencedNameElementType()
if (ktOperator == KtTokens.IDENTIFIER) {
@@ -77,8 +79,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
// TODO desugar '?:' to 'if'?
val specialCallForElvis = getResolvedCall(expression)!!
val returnType = specialCallForElvis.resultingDescriptor.returnType!!
val irArgument0 = irStatementGenerator.generateExpression(expression.left!!).toExpectedType(returnType.makeNullable())
val irArgument1 = irStatementGenerator.generateExpression(expression.right!!).toExpectedType(returnType)
val irArgument0 = statementGenerator.generateExpression(expression.left!!).toExpectedType(returnType.makeNullable())
val irArgument1 = statementGenerator.generateExpression(expression.right!!).toExpectedType(returnType)
return IrBinaryOperatorExpressionImpl(
expression.startOffset, expression.endOffset, returnType,
IrOperator.ELVIS, null, irArgument0, irArgument1
@@ -86,8 +88,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
}
private fun generateBinaryBooleanOperator(expression: KtBinaryExpression, irOperator: IrBinaryOperator): IrExpression {
val irArgument0 = irStatementGenerator.generateExpression(expression.left!!).toExpectedType(context.builtIns.booleanType)
val irArgument1 = irStatementGenerator.generateExpression(expression.right!!).toExpectedType(context.builtIns.booleanType)
val irArgument0 = statementGenerator.generateExpression(expression.left!!).toExpectedType(context.builtIns.booleanType)
val irArgument1 = statementGenerator.generateExpression(expression.right!!).toExpectedType(context.builtIns.booleanType)
return IrBinaryOperatorExpressionImpl(
expression.startOffset, expression.endOffset, context.builtIns.booleanType,
irOperator, getResolvedCall(expression)?.resultingDescriptor, irArgument0, irArgument1
@@ -97,7 +99,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
private fun generateInOperator(expression: KtBinaryExpression, irOperator: IrOperator): IrExpression {
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)
irOperatorCall
@@ -107,8 +109,8 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
}
private fun generateIdentityOperator(expression: KtBinaryExpression, irOperator: IrBinaryOperator): IrExpression {
val irArgument0 = irStatementGenerator.generateExpression(expression.left!!)
val irArgument1 = irStatementGenerator.generateExpression(expression.right!!)
val irArgument0 = statementGenerator.generateExpression(expression.left!!)
val irArgument1 = statementGenerator.generateExpression(expression.right!!)
return IrBinaryOperatorExpressionImpl(
expression.startOffset, expression.endOffset, context.builtIns.booleanType,
irOperator, null, irArgument0, irArgument1
@@ -119,7 +121,7 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
val relatedCall = getResolvedCall(expression)!!
val relatedDescriptor = relatedCall.resultingDescriptor
val irCallGenerator = IrCallGenerator(irStatementGenerator)
val irCallGenerator = CallGenerator(statementGenerator)
// 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 compareToDescriptor = compareToCall.resultingDescriptor
val irCallGenerator = IrCallGenerator(irStatementGenerator)
val irCallGenerator = CallGenerator(statementGenerator)
return if (shouldKeepComparisonAsBinaryOperation(compareToDescriptor)) {
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 {
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 {
@@ -184,10 +186,10 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
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 irOpCall = opCallGenerator.generateCall(expression, operatorCall, irOperator)
val irTmp = irStatementGenerator.temporaryVariableFactory.createTemporaryVariable(irOpCall)
val irTmp = statementGenerator.temporaryVariableFactory.createTemporaryVariable(irOpCall)
irBlock.addStatement(irTmp)
irBlock.addStatement(irLValue.store(irTmp.load()))
irBlock.addStatement(irTmp.load())
@@ -202,10 +204,10 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
val isSimpleAssignment = get(BindingContext.VARIABLE_REASSIGNMENT, expression) ?: false
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)
return if (isSimpleAssignment) {
@@ -222,20 +224,20 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
val ktLeft = expression.left!!
val ktRight = expression.right!!
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 {
if (ktLeft is KtArrayAccessExpression) {
val irArrayValue = irStatementGenerator.generateExpression(ktLeft.arrayExpression!!)
val indexExpressions = ktLeft.indexExpressions.map { it to irStatementGenerator.generateExpression(it) }
val irArrayValue = statementGenerator.generateExpression(ktLeft.arrayExpression!!)
val indexExpressions = ktLeft.indexExpressions.map { it to statementGenerator.generateExpression(it) }
val indexedGetCall = get(BindingContext.INDEXED_LVALUE_GET, ktLeft)
val indexedSetCall = get(BindingContext.INDEXED_LVALUE_SET, ktLeft)
val type = indexedGetCall?.run { resultingDescriptor.returnType }
?: indexedSetCall?.run { resultingDescriptor.valueParameters.last().type }
?: throw AssertionError("Either 'get' or 'set' call should be present for an indexed LValue: ${ktLeft.text}")
return IrIndexedLValue(irStatementGenerator, ktLeft, irOperator,
irArrayValue, type, indexExpressions, indexedGetCall, indexedSetCall)
return IndexedLValue(statementGenerator, ktLeft, irOperator,
irArrayValue, type, indexExpressions, indexedGetCall, indexedSetCall)
}
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
@@ -246,10 +248,10 @@ class IrOperatorExpressionGenerator(val irStatementGenerator: IrStatementGenerat
if (descriptor.isDelegated)
TODO("Delegated local variable")
else
IrVariableLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, irOperator)
VariableLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor, irOperator)
is PropertyDescriptor ->
IrCallGenerator(irStatementGenerator).run {
IrPropertyLValue(
CallGenerator(statementGenerator).run {
PropertyLValue(
ktLeft, irOperator, descriptor,
generateReceiver(ktLeft, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter),
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.startOffset
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.resolve.BindingContext
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.types.expressions.ExpressionTypingUtils
class IrStatementGenerator(
override val context: IrGeneratorContext,
class StatementGenerator(
override val context: GeneratorContext,
val scopeOwner: DeclarationDescriptor,
val temporaryVariableFactory: IrTemporaryVariableFactory
val temporaryVariableFactory: TemporaryVariableFactory
) : KtVisitor<IrStatement, Nothing?>(), IrGenerator {
fun generateExpression(ktExpression: KtExpression): IrExpression =
ktExpression.genExpr()
private fun KtElement.genStmt(): IrStatement =
deparenthesize().accept(this@IrStatementGenerator, null)
deparenthesize().accept(this@StatementGenerator, null)
private fun KtElement.genExpr(): IrExpression =
genStmt().assertCast()
@@ -77,8 +77,8 @@ class IrStatementGenerator(
val irTmpInitializer = temporaryVariableFactory.createTemporaryVariable(ktInitializer.genExpr())
irBlock.addStatement(irTmpInitializer)
val irCallGenerator = IrCallGenerator(this)
irCallGenerator.putValue(ktInitializer, IrVariableLValue(irTmpInitializer))
val irCallGenerator = CallGenerator(this)
irCallGenerator.putValue(ktInitializer, VariableLValue(irTmpInitializer))
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
@@ -188,7 +188,7 @@ class IrStatementGenerator(
companionObjectDescriptor)
}
is PropertyDescriptor -> {
IrCallGenerator(this).generateCall(expression, resolvedCall)
CallGenerator(this).generateCall(expression, resolvedCall)
}
is VariableDescriptor ->
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor)
@@ -207,7 +207,7 @@ class IrStatementGenerator(
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 =
@@ -239,8 +239,38 @@ class IrStatementGenerator(
}
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Nothing?): IrStatement =
IrOperatorExpressionGenerator(this).generateBinaryExpression(expression)
OperatorExpressionGenerator(this).generateBinaryExpression(expression)
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.types.KotlinType
class IrTemporaryVariableFactory(val scopeOwner: DeclarationDescriptor) {
class TemporaryVariableFactory(val scopeOwner: DeclarationDescriptor) {
private var lastTemporaryIndex = 0
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.startOffset
import org.jetbrains.kotlin.psi2ir.load
import org.jetbrains.kotlin.psi2ir.generators.IrCallGenerator
import org.jetbrains.kotlin.psi2ir.generators.IrStatementGenerator
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
import org.jetbrains.kotlin.psi2ir.generators.StatementGenerator
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
class IrIndexedLValue(
var irStatementGenerator: IrStatementGenerator,
class IndexedLValue(
var statementGenerator: StatementGenerator,
val ktArrayAccessExpression: KtArrayAccessExpression,
val irOperator: IrOperator?,
val irArray: IrExpression,
@@ -50,7 +50,7 @@ class IrIndexedLValue(
}
private fun generateGetOrSetCallAsDesugaredBlock(call: ResolvedCall<*>, irArgument: IrExpression? = null): IrExpression {
val callGenerator = IrCallGenerator(irStatementGenerator)
val callGenerator = CallGenerator(statementGenerator)
setupCallGeneratorContext(callGenerator)
if (irArgument != null) {
@@ -64,19 +64,19 @@ class IrIndexedLValue(
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}")
val callGenerator = IrCallGenerator(irStatementGenerator)
val callGenerator = CallGenerator(statementGenerator)
val irBlock = createDesugaredBlockWithTemporaries(indexedSetCall, callGenerator, true, irOperator)
val operatorCallReceiver = operatorCall.extensionReceiver ?: operatorCall.dispatchReceiver
callGenerator.putValue(operatorCallReceiver!!,
IrSingleExpressionValue(callGenerator.generateCall(ktArrayAccessExpression, indexedGetCall, irOperator)))
val irTmp = irStatementGenerator.temporaryVariableFactory.createTemporaryVariable(
val irTmp = statementGenerator.temporaryVariableFactory.createTemporaryVariable(
callGenerator.generateCall(ktArrayAccessExpression, operatorCall, irOperator))
irBlock.addStatement(irTmp)
callGenerator.putValue(indexedSetCall.resultingDescriptor.valueParameters.last(),
IrVariableLValue(irTmp))
VariableLValue(irTmp))
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 (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)
@@ -109,7 +109,7 @@ class IrIndexedLValue(
private fun createDesugaredBlockWithTemporaries(
call: ResolvedCall<*>,
callGenerator: IrCallGenerator,
callGenerator: CallGenerator,
hasResult: Boolean,
operator: IrOperator?
): IrBlockExpressionImpl {
@@ -124,7 +124,7 @@ class IrIndexedLValue(
hasResult, operator)
}
private fun defineTemporaryVariables(irBlock: IrBlockExpression, callGenerator: IrCallGenerator) {
private fun defineTemporaryVariables(irBlock: IrBlockExpression, callGenerator: CallGenerator) {
irBlock.addIfNotNull(callGenerator.introduceTemporary(ktArrayAccessExpression.arrayExpression!!, irArray, "array"))
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))
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.types.KotlinType
class IrPropertyLValue(
class PropertyLValue(
val ktElement: KtElement,
val irOperator: IrOperator?,
val descriptor: PropertyDescriptor,
@@ -37,8 +37,8 @@ class IrPropertyLValue(
private fun IrPropertyAccessExpression.setReceivers() =
apply {
dispatchReceiver = this@IrPropertyLValue.dispatchReceiver
extensionReceiver = this@IrPropertyLValue.extensionReceiver
dispatchReceiver = this@PropertyLValue.dispatchReceiver
extensionReceiver = this@PropertyLValue.extensionReceiver
}
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.types.KotlinType
class IrVariableLValue(
class VariableLValue(
val startOffset: Int,
val endOffset: Int,
val descriptor: VariableDescriptor,
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.ir
const val CHILD_DECLARATION_SLOT = 0
const val DETACHED_SLOT = Int.MIN_VALUE
const val CHILD_EXPRESSION_SLOT = 0
const val ARGUMENT0_SLOT = 0
@@ -25,4 +24,8 @@ const val DISPATCH_RECEIVER_SLOT = -1
const val EXTENSION_RECEIVER_SLOT = -2
const val FUNCTION_BODY_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
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.assertCast
import org.jetbrains.kotlin.ir.assertDetached
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
@@ -56,8 +53,11 @@ class IrBlockExpressionImpl(
statements.getOrNull(slot)
override fun replaceChild(slot: Int, newChild: IrElement) {
newChild.assertDetached()
if (0 <= slot && slot < statements.size) {
statements[slot].detach()
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.IrGetPropertyExpression
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.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) {
printer.println(accept(elementRenderer, null).withLabel(label))
indented(body)
@@ -112,9 +112,14 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitStringConcatenation(expression: IrStringConcatenationExpression, data: Nothing?): String =
"STRING_CONCATENATION type=${expression.renderType()}"
override fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: Nothing?): String {
return "TYPE_OP operator=${expression.operator} typeOperand=${expression.typeOperand.render()}"
}
override fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: Nothing?): String =
"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 =
"DUMMY ${declaration.descriptor.name}"
@@ -63,8 +63,10 @@ interface IrElementVisitor<out R, in D> {
fun visitBinaryOperator(expression: IrBinaryOperatorExpression, data: D) = visitOperatorExpression(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
fun visitDummyDeclaration(declaration: IrDummyDeclaration, data: D) = visitDeclaration(declaration, 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
IrExpressionBody
BLOCK type=<no-type> hasResult=false operator=null
DUMMY KtIfExpression type=kotlin.Unit
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=''
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>
BINARY_OP operator=ELVIS type=kotlin.String related=null
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
IrExpressionBody
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
message: GET_PROPERTY .length type=kotlin.Int operator=null
$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
IrExpressionBody
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>
CALL .overloaded type=kotlin.String operator=null
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
IrExpressionBody
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>
TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.String
GET_VAR x type=kotlin.Any operator=null
@@ -14,7 +14,9 @@ IrFile /smartCastsWithDestructuring.kt
IrFunction public fun test(/*0*/ x: I1): kotlin.Unit
IrExpressionBody
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
VAR val tmp0: I1
GET_VAR x type=I1 operator=null
@@ -137,6 +137,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
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")
public void testImplicitCastOnPlatformType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/implicitCastOnPlatformType.kt");