When expression.
Fix object & enum references.
This commit is contained in:
committed by
Dmitry Petrov
parent
d6040d8570
commit
b96626fd4c
@@ -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<out CallableDescriptor>,
|
||||
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<out CallableDescriptor>,
|
||||
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<out CallableDescriptor>,
|
||||
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<ResolvedValueArgument, ValueParameterDescriptor>()
|
||||
@@ -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
|
||||
|
||||
@@ -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<out CallableDescriptor>? =
|
||||
key.getResolvedCall(context.bindingContext)
|
||||
|
||||
+38
-27
@@ -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)
|
||||
}
|
||||
|
||||
+115
@@ -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!!)
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
const val BRANCH_RESULT_SLOT = -1
|
||||
@@ -58,6 +58,9 @@ class IrLiteralExpressionImpl<out T> (
|
||||
|
||||
fun int(startOffset: Int, endOffset: Int, type: KotlinType, value: Int): IrLiteralExpressionImpl<Int> =
|
||||
IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Int, value)
|
||||
|
||||
fun nullLiteral(startOffset: Int, endOffset: Int, type: KotlinType): IrLiteralExpressionImpl<Nothing?> =
|
||||
IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.Null, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<IrExpression>
|
||||
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<IrExpression> = SmartList()
|
||||
|
||||
override fun addCondition(expression: IrExpression) {
|
||||
expression.assertDetached()
|
||||
expression.setTreeLocation(this, conditions.size)
|
||||
conditions.add(expression)
|
||||
}
|
||||
|
||||
private var resultImpl: IrExpression? = null
|
||||
override var result: IrExpression
|
||||
@@ -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 <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||
conditionImpl?.accept(visitor, data)
|
||||
conditions.forEach { it.accept(visitor, data) }
|
||||
resultImpl?.accept(visitor, data)
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
|
||||
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")
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ IrFunction public fun B.test(): kotlin.Unit
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
BLOCK type=<no-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
|
||||
|
||||
+11
@@ -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
|
||||
+27
@@ -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=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
GET_ENUM_VALUE A type=Enum
|
||||
IrFunction public fun test2(): A
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
GET_OBJECT A type=A
|
||||
IrFunction public fun test3(): kotlin.Int
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
GET_PROPERTY .a type=kotlin.Int operator=null
|
||||
IrFunction public fun test4(): Z.Companion
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-type>
|
||||
GET_OBJECT Companion type=Z.Companion
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
object A
|
||||
|
||||
fun test(x: Any?) =
|
||||
when (x) {
|
||||
null -> "null"
|
||||
A -> "A"
|
||||
is String -> "String"
|
||||
in setOf<Nothing>() -> "nothingness?"
|
||||
else -> "something"
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
IrFile /when.kt
|
||||
DUMMY A
|
||||
IrFunction public fun test(/*0*/ x: kotlin.Any?): kotlin.String
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
RETURN type=<no-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<kotlin.Nothing> operator=null
|
||||
element: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||
GET_VAR tmp0_subject type=kotlin.Any? operator=null
|
||||
then: LITERAL String type=kotlin.String value='nothingness?'
|
||||
else: LITERAL String type=kotlin.String value='something'
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user