diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index 942b8ed7574..1e032dd295a 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset @@ -50,6 +51,10 @@ class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator { return null } + return createTemporary(ktExpression, irExpression, nameHint) + } + + fun createTemporary(ktExpression: KtExpression, irExpression: IrExpression, nameHint: String?): IrVariable { val irTmpVar = temporaryVariableFactory.createTemporaryVariable(irExpression, nameHint) putValue(ktExpression, VariableLValue(irTmpVar)) return irTmpVar @@ -75,12 +80,16 @@ class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator { receiverValues[receiver] = irValue } - fun putValue(valueArgument: ValueParameterDescriptor, irValue: IrValue) { - valueArgumentValues[valueArgument] = irValue + fun putValue(parameter: ValueParameterDescriptor, irValue: IrValue) { + valueArgumentValues[parameter] = irValue } + fun valueOf(ktExpression: KtExpression) = expressionValues[ktExpression]?.load() + fun valueOf(receiver: ReceiverValue) = receiverValues[receiver]?.load() + fun valueOf(parameter: ValueParameterDescriptor) = valueArgumentValues[parameter]?.load() + fun generateCall( - ktExpression: KtExpression, + ktElement: KtElement, resolvedCall: ResolvedCall, operator: IrOperator? = null, superQualifier: ClassDescriptor? = null @@ -91,15 +100,15 @@ class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator { return when (descriptor) { is PropertyDescriptor -> IrGetPropertyExpressionImpl( - ktExpression.startOffset, ktExpression.endOffset, + ktElement.startOffset, ktElement.endOffset, returnType, resolvedCall.call.isSafeCall(), descriptor ).apply { - dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter) - extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter) + dispatchReceiver = generateReceiver(ktElement, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter) + extensionReceiver = generateReceiver(ktElement, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter) } is FunctionDescriptor -> - generateFunctionCall(descriptor, ktExpression, returnType, operator, resolvedCall, superQualifier) + generateFunctionCall(descriptor, ktElement, returnType, operator, resolvedCall, superQualifier) else -> TODO("Unexpected callable descriptor: $descriptor ${descriptor.javaClass.simpleName}") } @@ -121,21 +130,21 @@ class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator { private fun generateFunctionCall( descriptor: FunctionDescriptor, - ktExpression: KtExpression, + ktElement: KtElement, resultType: KotlinType?, operator: IrOperator?, resolvedCall: ResolvedCall, superQualifier: ClassDescriptor? ): IrExpression { val irCall = IrCallExpressionImpl( - ktExpression.startOffset, ktExpression.endOffset, resultType, + ktElement.startOffset, ktElement.endOffset, resultType, descriptor, resolvedCall.call.isSafeCall(), operator, superQualifier ) - irCall.dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter) - irCall.extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter) + irCall.dispatchReceiver = generateReceiver(ktElement, resolvedCall.dispatchReceiver, descriptor.dispatchReceiverParameter) + irCall.extensionReceiver = generateReceiver(ktElement, resolvedCall.extensionReceiver, descriptor.extensionReceiverParameter) return if (resolvedCall.requiresArgumentReordering()) { - generateCallWithArgumentReordering(irCall, ktExpression, resolvedCall, resultType) + generateCallWithArgumentReordering(irCall, ktElement, resolvedCall, resultType) } else { irCall.apply { @@ -152,7 +161,7 @@ class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator { private fun generateCallWithArgumentReordering( irCall: IrCallExpression, - ktExpression: KtExpression, + ktElement: KtElement, resolvedCall: ResolvedCall, resultType: KotlinType? ): IrExpression { @@ -161,8 +170,8 @@ class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator { val valueArgumentsInEvaluationOrder = resolvedCall.valueArguments.values val valueParameters = resolvedCall.resultingDescriptor.valueParameters - val hasResult = isUsedAsExpression(ktExpression) - val irBlock = IrBlockExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, resultType, hasResult, + val hasResult = isUsedAsExpression(ktElement) + val irBlock = IrBlockExpressionImpl(ktElement.startOffset, ktElement.endOffset, resultType, hasResult, IrOperator.SYNTHETIC_BLOCK) val valueArgumentsToValueParameters = HashMap() @@ -189,22 +198,22 @@ class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator { return irBlock } - fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?, receiverParameterDescriptor: ReceiverParameterDescriptor?) = - generateReceiver(ktExpression, receiver, receiverParameterDescriptor?.type) + fun generateReceiver(ktElement: KtElement, receiver: ReceiverValue?, receiverParameterDescriptor: ReceiverParameterDescriptor?) = + generateReceiver(ktElement, receiver, receiverParameterDescriptor?.type) - fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?, expectedType: KotlinType?) = - generateReceiver(ktExpression, receiver)?.toExpectedType(expectedType) + fun generateReceiver(ktElement: KtElement, receiver: ReceiverValue?, expectedType: KotlinType?) = + generateReceiver(ktElement, receiver)?.toExpectedType(expectedType) - fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? = + fun generateReceiver(ktElement: KtElement, receiver: ReceiverValue?): IrExpression? = if (receiver == null) null else - receiverValues[receiver]?.load() ?: doGenerateReceiver(ktExpression, receiver) + receiverValues[receiver]?.load() ?: doGenerateReceiver(ktElement, receiver) - fun doGenerateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? = + fun doGenerateReceiver(ktElement: KtElement, receiver: ReceiverValue?): IrExpression? = when (receiver) { is ImplicitClassReceiver -> - IrThisExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type, receiver.classDescriptor) + IrThisExpressionImpl(ktElement.startOffset, ktElement.startOffset, receiver.type, receiver.classDescriptor) is ThisClassReceiver -> (receiver as? ExpressionReceiver)?.expression?.let { receiverExpression -> IrThisExpressionImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor) @@ -215,7 +224,7 @@ class CallGenerator(val statementGenerator: StatementGenerator) : IrGenerator { IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type, receiver.classQualifier.descriptor) is ExtensionReceiver -> - IrGetExtensionReceiverExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type, + IrGetExtensionReceiverExpressionImpl(ktElement.startOffset, ktElement.startOffset, receiver.type, receiver.declarationDescriptor.extensionReceiverParameter!!) null -> null diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt index 3377428f442..2496b11e2cf 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/Generator.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.ir.expressions.IrDummyExpression import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset @@ -54,8 +55,8 @@ fun IrGenerator.getExpectedTypeForLastInferredCall(key: KtExpression): KotlinTyp fun IrGenerator.getInferredTypeWithSmarcastsOrFail(key: KtExpression): KotlinType = getInferredTypeWithSmartcasts(key) ?: TODO("No type for expression: ${key.text}") -fun IrGenerator.isUsedAsExpression(ktExpression: KtExpression) = - get(BindingContext.USED_AS_EXPRESSION, ktExpression) ?: false +fun IrGenerator.isUsedAsExpression(ktElement: KtElement) = + get(BindingContext.USED_AS_EXPRESSION, ktElement) ?: false fun IrGenerator.getResolvedCall(key: KtExpression): ResolvedCall? = key.getResolvedCall(context.bindingContext) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt index 2491003f4ce..8103ae7aac4 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/StatementGenerator.kt @@ -31,8 +31,11 @@ import org.jetbrains.kotlin.psi2ir.toExpectedType import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall +import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.constants.IntValue +import org.jetbrains.kotlin.resolve.constants.NullValue import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType @@ -140,6 +143,8 @@ class StatementGenerator( IrLiteralExpressionImpl.string(expression.startOffset, expression.endOffset, constantType, constantValue.value) is IntValue -> IrLiteralExpressionImpl.int(expression.startOffset, expression.endOffset, constantType, constantValue.value) + is NullValue -> + IrLiteralExpressionImpl.nullLiteral(expression.startOffset, expression.endOffset, constantType) else -> TODO("handle other literal types: ${constantValue.type}") } @@ -166,40 +171,45 @@ class StatementGenerator( IrLiteralExpressionImpl.string(entry.startOffset, entry.endOffset, context.builtIns.stringType, entry.text) override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Nothing?): IrExpression { - val resolvedCall = getResolvedCall(expression) + val resolvedCall = getResolvedCall(expression)!! if (resolvedCall is VariableAsFunctionResolvedCall) { TODO("Unexpected VariableAsFunctionResolvedCall") } - val descriptor = resolvedCall?.resultingDescriptor + val descriptor = resolvedCall.resultingDescriptor - return when (descriptor) { - is ClassDescriptor -> - if (DescriptorUtils.isObject(descriptor)) - IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor) - else if (DescriptorUtils.isEnumEntry(descriptor)) - IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor) - else { - val companionObjectDescriptor = descriptor.companionObjectDescriptor - ?: error("Class value without companion object: $descriptor") - IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, - descriptor.classValueType, - companionObjectDescriptor) - } - is PropertyDescriptor -> { - CallGenerator(this).generateCall(expression, resolvedCall) - } - is VariableDescriptor -> - IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor) - else -> - IrDummyExpression( - expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression), - expression.getReferencedName() + ": ${descriptor?.name} ${descriptor?.javaClass?.simpleName}" - ) - } + return generateExpressionForReferencedDescriptor(descriptor, expression, resolvedCall) } + private fun generateExpressionForReferencedDescriptor(descriptor: DeclarationDescriptor, expression: KtExpression, resolvedCall: ResolvedCall<*>): IrExpression = + when (descriptor) { + is FakeCallableDescriptorForObject -> + generateExpressionForReferencedDescriptor(descriptor.getReferencedDescriptor(), expression, resolvedCall) + is ClassDescriptor -> + if (DescriptorUtils.isObject(descriptor)) + IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor) + else if (DescriptorUtils.isEnumEntry(descriptor)) + IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, descriptor.classValueType, descriptor) + else { + val companionObjectDescriptor = descriptor.companionObjectDescriptor + ?: error("Class value without companion object: $descriptor") + IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, + descriptor.classValueType, + companionObjectDescriptor) + } + is PropertyDescriptor -> { + CallGenerator(this).generateCall(expression, resolvedCall) + } + is VariableDescriptor -> + IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, descriptor) + else -> + IrDummyExpression( + expression.startOffset, expression.endOffset, getInferredTypeWithSmartcasts(expression), + expression.text + ": ${descriptor.name} ${descriptor.javaClass.simpleName}" + ) + } + override fun visitCallExpression(expression: KtCallExpression, data: Nothing?): IrStatement { val resolvedCall = getResolvedCall(expression) ?: TODO("No resolved call for call expression") @@ -280,5 +290,6 @@ class StatementGenerator( return irWhen } - + override fun visitWhenExpression(expression: KtWhenExpression, data: Nothing?): IrStatement = + WhenExpressionGenerator(this).generate(expression) } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/WhenExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/WhenExpressionGenerator.kt new file mode 100644 index 00000000000..e07131f6427 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/WhenExpressionGenerator.kt @@ -0,0 +1,115 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.psi2ir.generators + +import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.psi.* +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.toExpectedType +import org.jetbrains.kotlin.resolve.BindingContext + +class WhenExpressionGenerator(val statementGenerator: StatementGenerator) : IrGenerator { + override val context: GeneratorContext get() = statementGenerator.context + + fun generate(expression: KtWhenExpression): IrExpression { + val conditionsGenerator = CallGenerator(statementGenerator) + + val irSubject = expression.subjectExpression?.let { + conditionsGenerator.createTemporary(it, statementGenerator.generateExpression(it), "subject") + } + + val resultType = getInferredTypeWithSmartcasts(expression) + + val irWhen = IrWhenExpressionImpl(expression.startOffset, expression.endOffset, resultType, irSubject) + + for (ktEntry in expression.entries) { + if (ktEntry.isElse) { + irWhen.elseExpression = statementGenerator.generateExpression(ktEntry.expression!!).toExpectedType(resultType) + continue + } + + val irBranch = IrBranchImpl(ktEntry.startOffset, ktEntry.endOffset) + + for (ktCondition in ktEntry.conditions) { + val irCondition = + if (irSubject != null) + generateWhenConditionWithSubject(ktCondition, conditionsGenerator, irSubject) + else + generateWhenConditionNoSubject(ktCondition) + irBranch.addCondition(irCondition) + } + + irBranch.result = statementGenerator.generateExpression(ktEntry.expression!!).toExpectedType(resultType) + + irWhen.addBranch(irBranch) + } + + return irWhen + } + + private fun generateWhenConditionNoSubject(ktCondition: KtWhenCondition): IrExpression = + statementGenerator.generateExpression((ktCondition as KtWhenConditionWithExpression).expression!!) + .toExpectedType(context.builtIns.booleanType) + + private fun generateWhenConditionWithSubject( + ktCondition: KtWhenCondition, + conditionsGenerator: CallGenerator, + irSubject: IrVariable + ): IrExpression { + return when (ktCondition) { + is KtWhenConditionWithExpression -> + generateEqualsCondition(irSubject, ktCondition) + is KtWhenConditionInRange -> + generateInRangeCondition(conditionsGenerator, ktCondition) + is KtWhenConditionIsPattern -> + generateIsPatternCondition(irSubject, ktCondition) + else -> + throw AssertionError("Unexpected 'when' condition: ${ktCondition.text}") + } + } + + private fun generateIsPatternCondition(irSubject: IrVariable, ktCondition: KtWhenConditionIsPattern): IrExpression { + val isType = getOrFail(BindingContext.TYPE, ktCondition.typeReference) + return IrTypeOperatorExpressionImpl( + ktCondition.startOffset, ktCondition.endOffset, context.builtIns.booleanType, + IrTypeOperator.INSTANCEOF, isType, irSubject.load() + ) + } + + private fun generateInRangeCondition(conditionsGenerator: CallGenerator, ktCondition: KtWhenConditionInRange): IrExpression { + val inResolvedCall = getResolvedCall(ktCondition.operationReference)!! + val inOperator = getIrBinaryOperator(ktCondition.operationReference.getReferencedNameElementType()) + val irInCall = conditionsGenerator.generateCall(ktCondition, inResolvedCall, inOperator) + return when (inOperator) { + IrOperator.IN -> irInCall + IrOperator.NOT_IN -> + IrUnaryOperatorExpressionImpl(ktCondition.startOffset, ktCondition.endOffset, context.builtIns.booleanType, + IrOperator.EXCL, null, irInCall) + else -> throw AssertionError("Expected 'in' or '!in', got $inOperator") + } + } + + private fun generateEqualsCondition(irSubject: IrVariable, ktCondition: KtWhenConditionWithExpression): IrBinaryOperatorExpressionImpl = + IrBinaryOperatorExpressionImpl( + ktCondition.startOffset, ktCondition.endOffset, + context.builtIns.booleanType, IrOperator.EQEQ, null, + irSubject.load(), statementGenerator.generateExpression(ktCondition.expression!!) + ) +} \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt index 1807990acf4..7314bd833b0 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrSlots.kt @@ -27,5 +27,4 @@ const val MODULE_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 \ No newline at end of file +const val BRANCH_RESULT_SLOT = -1 \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrLiteralExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrLiteralExpression.kt index e3a6d6acfe9..4a0ef0efe8c 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrLiteralExpression.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrLiteralExpression.kt @@ -58,6 +58,9 @@ class IrLiteralExpressionImpl ( fun int(startOffset: Int, endOffset: Int, type: KotlinType, value: Int): IrLiteralExpressionImpl = IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Int, value) + + fun nullLiteral(startOffset: Int, endOffset: Int, type: KotlinType): IrLiteralExpressionImpl = + IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Null, null) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrWhenExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrWhenExpression.kt index e481ef5123b..38a9483f519 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrWhenExpression.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrWhenExpression.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.* import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.utils.SmartList import java.util.* interface IrWhenExpression : IrExpression { @@ -31,8 +32,10 @@ interface IrWhenExpression : IrExpression { } interface IrBranch : IrElement { - var condition: IrExpression + val conditions: List var result: IrExpression + + fun addCondition(expression: IrExpression) } class IrWhenExpressionImpl( @@ -44,7 +47,7 @@ class IrWhenExpressionImpl( startOffset: Int, endOffset: Int, type: KotlinType?, - subject: IrVariable + subject: IrVariable? ) : this(startOffset, endOffset, type) { this.subject = subject } @@ -121,19 +124,17 @@ class IrWhenExpressionImpl( 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 + addCondition(condition) } - 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) - } + override val conditions: MutableList = SmartList() + + override fun addCondition(expression: IrExpression) { + expression.assertDetached() + expression.setTreeLocation(this, conditions.size) + conditions.add(expression) + } private var resultImpl: IrExpression? = null override var result: IrExpression @@ -147,17 +148,19 @@ class IrBranchImpl(startOffset: Int, endOffset: Int) : IrElementBase(startOffset override fun getChild(slot: Int): IrElement? = when (slot) { - BRANCH_CONDITION_SLOT -> condition BRANCH_RESULT_SLOT -> result - else -> null + else -> conditions.getOrNull(slot) } override fun replaceChild(slot: Int, newChild: IrElement) { when (slot) { - BRANCH_CONDITION_SLOT -> - condition = newChild.assertCast() BRANCH_RESULT_SLOT -> result = newChild.assertCast() + in conditions.indices -> { + conditions[slot].detach() + conditions[slot] = newChild.assertCast() + newChild.setTreeLocation(this, slot) + } } } @@ -165,7 +168,7 @@ class IrBranchImpl(startOffset: Int, endOffset: Int) : IrElementBase(startOffset visitor.visitBranch(this, data) override fun acceptChildren(visitor: IrElementVisitor, data: D) { - conditionImpl?.accept(visitor, data) + conditions.forEach { it.accept(visitor, data) } resultImpl?.accept(visitor, data) } } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt index 091e26ebe54..ae3f2d8363b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt @@ -77,7 +77,7 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor { subject.accept(this, "\$subject:") } for (branch in expression.branches) { - branch.condition.accept(this, "if") + branch.conditions.forEach { it.accept(this, "if") } branch.result.accept(this, "then") } expression.elseExpression?.accept(this, "else") diff --git a/compiler/testData/ir/irText/destructuring1.txt b/compiler/testData/ir/irText/destructuring1.txt index aa8a84c3f09..c6c51131db5 100644 --- a/compiler/testData/ir/irText/destructuring1.txt +++ b/compiler/testData/ir/irText/destructuring1.txt @@ -3,7 +3,7 @@ IrFunction public fun B.test(): kotlin.Unit BLOCK type= hasResult=false operator=null BLOCK type= hasResult=false operator=SYNTHETIC_BLOCK VAR val tmp0: A - GET_VAR A type=A operator=null + GET_OBJECT A type=A VAR val x: kotlin.Int CALL .component1 type=kotlin.Int operator=COMPONENT_N(index=1) $this: $RECEIVER of: test type=B diff --git a/compiler/testData/ir/irText/values.kt b/compiler/testData/ir/irText/values.kt new file mode 100644 index 00000000000..949b7b1d277 --- /dev/null +++ b/compiler/testData/ir/irText/values.kt @@ -0,0 +1,11 @@ +enum class Enum { A } +object A +val a = 0 +class Z { + companion object +} + +fun test1() = Enum.A +fun test2() = A +fun test3() = a +fun test4() = Z \ No newline at end of file diff --git a/compiler/testData/ir/irText/values.txt b/compiler/testData/ir/irText/values.txt new file mode 100644 index 00000000000..9a1cb660d03 --- /dev/null +++ b/compiler/testData/ir/irText/values.txt @@ -0,0 +1,27 @@ +IrFile /values.kt + DUMMY Enum + DUMMY A + IrProperty public val a: kotlin.Int = 0 getter=null setter=null + IrExpressionBody + LITERAL Int type=kotlin.Int value='0' + DUMMY Z + IrFunction public fun test1(): Enum + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + GET_ENUM_VALUE A type=Enum + IrFunction public fun test2(): A + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + GET_OBJECT A type=A + IrFunction public fun test3(): kotlin.Int + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + GET_PROPERTY .a type=kotlin.Int operator=null + IrFunction public fun test4(): Z.Companion + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + GET_OBJECT Companion type=Z.Companion diff --git a/compiler/testData/ir/irText/when.kt b/compiler/testData/ir/irText/when.kt new file mode 100644 index 00000000000..708c246b507 --- /dev/null +++ b/compiler/testData/ir/irText/when.kt @@ -0,0 +1,10 @@ +object A + +fun test(x: Any?) = + when (x) { + null -> "null" + A -> "A" + is String -> "String" + in setOf() -> "nothingness?" + else -> "something" + } \ No newline at end of file diff --git a/compiler/testData/ir/irText/when.txt b/compiler/testData/ir/irText/when.txt new file mode 100644 index 00000000000..5b89a06c1d8 --- /dev/null +++ b/compiler/testData/ir/irText/when.txt @@ -0,0 +1,26 @@ +IrFile /when.kt + DUMMY A + IrFunction public fun test(/*0*/ x: kotlin.Any?): kotlin.String + IrExpressionBody + BLOCK type= hasResult=false operator=null + RETURN type= + WHEN subject=tmp0_subject type=kotlin.String + $subject:: VAR val tmp0_subject: kotlin.Any? + GET_VAR x type=kotlin.Any? operator=null + if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null + GET_VAR tmp0_subject type=kotlin.Any? operator=null + LITERAL Null type=kotlin.Nothing? value='null' + then: LITERAL String type=kotlin.String value='null' + if: BINARY_OP operator=EQEQ type=kotlin.Boolean related=null + GET_VAR tmp0_subject type=kotlin.Any? operator=null + GET_OBJECT A type=A + then: LITERAL String type=kotlin.String value='A' + if: TYPE_OP operator=INSTANCEOF typeOperand=kotlin.String + GET_VAR tmp0_subject type=kotlin.Any? operator=null + then: LITERAL String type=kotlin.String value='String' + if: CALL .contains type=kotlin.Boolean operator=IN + $receiver: CALL .setOf type=kotlin.collections.Set operator=null + element: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Any + GET_VAR tmp0_subject type=kotlin.Any? operator=null + then: LITERAL String type=kotlin.String value='nothingness?' + else: LITERAL String type=kotlin.String value='something' diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 1fde8ead47e..65bcbdc96bf 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -214,4 +214,16 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/typeOperators.kt"); doTest(fileName); } + + @TestMetadata("values.kt") + public void testValues() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/values.kt"); + doTest(fileName); + } + + @TestMetadata("when.kt") + public void testWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/when.kt"); + doTest(fileName); + } }