IrBody is no longer a declaration owner.

Local declarations in expression tree.
Call generator supports argument reordering.
This commit is contained in:
Dmitry Petrov
2016-08-12 19:08:42 +03:00
committed by Dmitry Petrov
parent b1af1af8a4
commit 030111b130
36 changed files with 631 additions and 269 deletions
@@ -0,0 +1,174 @@
/*
* 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
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginKind
import org.jetbrains.kotlin.ir.declarations.IrLocalVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
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.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
class IrCallGenerator(
override val context: IrGeneratorContext,
val irExpressionGenerator: IrExpressionGenerator
) : IrGenerator {
fun generateCall(
ktExpression: KtExpression,
resolvedCall: ResolvedCall<out CallableDescriptor>,
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
): IrExpression {
val descriptor = resolvedCall.resultingDescriptor
return when (descriptor) {
is PropertyDescriptor ->
IrGetPropertyExpressionImpl(
ktExpression.startOffset, ktExpression.endOffset, getTypeOrFail(ktExpression),
resolvedCall.call.isSafeCall(), descriptor
).apply {
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver)
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver)
}
is FunctionDescriptor ->
generateFunctionCall(descriptor, ktExpression, operator, resolvedCall, superQualifier)
else ->
TODO("Unexpected callable descriptor: $descriptor ${descriptor.javaClass.simpleName}")
}
}
private fun ResolvedCall<*>.requiresArgumentReordering(): Boolean {
var lastValueParameterIndex = -1
for (valueArgument in call.valueArguments) {
val argumentMapping = getArgumentMapping(valueArgument)
if (argumentMapping !is ArgumentMatch || argumentMapping.isError()) {
error("Value argument in function call is mapped with error")
}
val argumentIndex = argumentMapping.valueParameter.index
if (argumentIndex < lastValueParameterIndex) return true
lastValueParameterIndex = argumentIndex
}
return false
}
private fun generateFunctionCall(
descriptor: FunctionDescriptor,
ktExpression: KtExpression,
operator: IrOperator?,
resolvedCall: ResolvedCall<out CallableDescriptor>,
superQualifier: ClassDescriptor?
): IrExpression {
val resultType = getTypeOrFail(ktExpression)
val irCall = IrCallExpressionImpl(
ktExpression.startOffset, ktExpression.endOffset, resultType,
descriptor, resolvedCall.call.isSafeCall(), operator, superQualifier
)
irCall.dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver)
irCall.extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver)
return if (resolvedCall.requiresArgumentReordering()) {
generateCallWithArgumentReordering(irCall, ktExpression, resolvedCall, resultType)
}
else {
irCall.apply {
val valueArguments = resolvedCall.valueArgumentsByIndex
for (index in valueArguments!!.indices) {
val valueArgument = valueArguments[index]
val irArgument = generateValueArgument(valueArgument) ?: continue
irCall.putValueArgument(index, irArgument)
}
}
}
}
private fun generateCallWithArgumentReordering(
irCall: IrCallExpression,
ktExpression: KtExpression,
resolvedCall: ResolvedCall<out CallableDescriptor>,
resultType: KotlinType
): IrExpression {
val valueArgumentsInEvaluationOrder = resolvedCall.valueArguments.values
val hasResult = isUsedAsExpression(ktExpression)
val irBlock = IrBlockExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, resultType, hasResult)
val temporaryVariablesForValueArguments = HashMap<ResolvedValueArgument, Pair<VariableDescriptor, IrExpression>>()
for (valueArgument in valueArgumentsInEvaluationOrder) {
val irArgument = generateValueArgument(valueArgument) ?: continue
val irTemporary = irExpressionGenerator.declarationFactory.createTemporaryVariable(irArgument)
val irTemporaryDeclaration = IrLocalVariableDeclarationExpressionImpl(irArgument.startOffset, irArgument.endOffset, irArgument.type)
irTemporaryDeclaration.childDeclaration = irTemporary
irBlock.addChildExpression(irTemporaryDeclaration)
temporaryVariablesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
}
for ((index, valueArgument) in resolvedCall.valueArgumentsByIndex!!.withIndex()) {
val (temporaryDescriptor, irArgument) = temporaryVariablesForValueArguments[valueArgument]!!
val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset,
irArgument.type, temporaryDescriptor)
irCall.putValueArgument(index, irGetTemporary)
}
irBlock.addChildExpression(irCall)
return irBlock
}
private fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? =
when (receiver) {
is ImplicitClassReceiver ->
IrThisExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type, receiver.classDescriptor)
is ThisClassReceiver ->
(receiver as? ExpressionReceiver)?.expression?.let { receiverExpression ->
IrThisExpressionImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor)
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
is ExpressionReceiver ->
irExpressionGenerator.generateExpression(receiver.expression)
is ClassValueReceiver ->
IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
receiver.classQualifier.descriptor)
is ExtensionReceiver ->
IrGetExtensionReceiverExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type,
receiver.declarationDescriptor.extensionReceiverParameter!!)
null ->
null
else ->
TODO("Receiver: ${receiver.javaClass.simpleName}")
}
private fun generateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? {
when (valueArgument) {
is DefaultValueArgument ->
return null
is ExpressionValueArgument ->
return irExpressionGenerator.generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
is VarargValueArgument ->
TODO("vararg")
else ->
TODO("Unexpected valueArgument: ${valueArgument.javaClass.simpleName}")
}
}
}
@@ -18,31 +18,27 @@ package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.types.KotlinType
class IrDeclarationFactory private constructor(
val fileEntry: PsiSourceManager.PsiFileEntry,
val irFileImpl: IrFileImpl,
val containingDeclaration: IrCompoundDeclaration
) {
fun createChild(containingDeclaration: IrCompoundDeclaration) =
IrDeclarationFactory(fileEntry, irFileImpl, containingDeclaration)
private fun <D : IrMemberDeclaration> D.addToContainer(): D =
apply { containingDeclaration.addChildDeclaration(this) }
abstract class IrDeclarationFactoryBase {
fun createFunction(ktFunction: KtFunction, functionDescriptor: FunctionDescriptor, body: IrBody): IrFunction =
IrFunctionImpl(ktFunction.startOffset, ktFunction.endOffset,
IrDeclarationOriginKind.DEFINED, functionDescriptor, body)
.addToContainer()
fun createSimpleProperty(ktProperty: KtProperty, propertyDescriptor: PropertyDescriptor, valueInitializer: IrBody?): IrSimpleProperty =
IrSimplePropertyImpl(ktProperty.startOffset, ktProperty.endOffset,
IrDeclarationOriginKind.DEFINED, propertyDescriptor, valueInitializer)
.addToContainer()
fun createPropertyGetter(
ktPropertyAccessor: KtPropertyAccessor,
@@ -53,7 +49,6 @@ class IrDeclarationFactory private constructor(
IrPropertyGetterImpl(ktPropertyAccessor.startOffset, ktPropertyAccessor.endOffset,
IrDeclarationOriginKind.DEFINED, getterDescriptor, getterBody)
.apply { irProperty.getter = this }
.addToContainer()
fun createPropertySetter(
ktPropertyAccessor: KtPropertyAccessor,
@@ -64,16 +59,30 @@ class IrDeclarationFactory private constructor(
IrPropertySetterImpl(ktPropertyAccessor.startOffset, ktPropertyAccessor.endOffset,
IrDeclarationOriginKind.DEFINED, setterDescriptor, setterBody)
.apply { irProperty.setter = this }
.addToContainer()
}
companion object {
fun create(irModule: IrModuleImpl, sourceManager: PsiSourceManager, ktFile: KtFile, descriptor: PackageFragmentDescriptor): IrDeclarationFactory {
val fileEntry = sourceManager.getOrCreateFileEntry(ktFile)
val fileName = fileEntry.getRecognizableName()
val irFile = IrFileImpl(fileEntry, fileName, descriptor)
sourceManager.putFileEntry(irFile, fileEntry)
irModule.addFile(irFile)
return IrDeclarationFactory(fileEntry, irFile, irFile)
}
}
}
class IrDeclarationFactory() : IrDeclarationFactoryBase()
class IrLocalDeclarationsFactory(val scopeOwner: DeclarationDescriptor) : IrDeclarationFactoryBase() {
private var lastTemporaryIndex = 0
private fun nextTemporaryIndex() = lastTemporaryIndex++
fun createDescriptorForTemporaryVariable(type: KotlinType): IrTemporaryVariableDescriptor =
IrTemporaryVariableDescriptorImpl(scopeOwner, Name.identifier("tmp${nextTemporaryIndex()}"), type)
fun createTemporaryVariable(ktElement: KtElement, type: KotlinType): IrLocalVariable =
IrLocalVariableImpl(ktElement.startOffset, ktElement.endOffset,
IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable(type))
fun createTemporaryVariable(irExpression: IrExpression): IrLocalVariable =
IrLocalVariableImpl(irExpression.startOffset, irExpression.endOffset,
IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable(irExpression.type)
).apply { initializerExpression = irExpression }
fun createLocalVariable(ktElement: KtElement, type: KotlinType, descriptor: VariableDescriptor): IrLocalVariable =
IrLocalVariableImpl(ktElement.startOffset, ktElement.endOffset,
IrDeclarationOriginKind.DEFINED,
descriptor)
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
@@ -29,20 +30,15 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
interface IrDeclarationGenerator : IrGenerator {
val irDeclaration: IrDeclaration
val parent: IrDeclarationGenerator?
}
interface IrDeclarationGenerator : IrGenerator
abstract class IrDeclarationGeneratorBase(
override val context: IrGeneratorContext,
override val irDeclaration: IrDeclaration,
override val parent: IrDeclarationGenerator,
val declarationFactory: IrDeclarationFactory
val container: IrDeclarationOwnerN,
val declarationFactory: IrDeclarationFactoryBase
) : IrDeclarationGenerator {
val irExpressionGenerator = IrExpressionGenerator(context, declarationFactory)
val containingDeclaration: IrCompoundDeclaration get() = declarationFactory.containingDeclaration
private fun <D : IrMemberDeclaration> D.register(): D =
apply { container.addChildDeclaration(this) }
fun generateAnnotationEntries(annotationEntries: List<KtAnnotationEntry>) {
// TODO create IrAnnotation's for each KtAnnotationEntry
@@ -64,26 +60,26 @@ abstract class IrDeclarationGeneratorBase(
fun generateFunctionDeclaration(ktNamedFunction: KtNamedFunction) {
val functionDescriptor = getOrFail(BindingContext.FUNCTION, ktNamedFunction) { "unresolved fun" }
val body = generateExpressionBody(ktNamedFunction.bodyExpression ?: TODO("function without body expression"))
declarationFactory.createFunction(ktNamedFunction, functionDescriptor, body)
val body = generateExpressionBody(functionDescriptor, ktNamedFunction.bodyExpression ?: TODO("function without body expression"))
declarationFactory.createFunction(ktNamedFunction, functionDescriptor, body).register()
}
fun generatePropertyDeclaration(ktProperty: KtProperty) {
val propertyDescriptor = getPropertyDescriptor(ktProperty)
if (ktProperty.hasDelegate()) TODO("handle delegated property")
val initializer = ktProperty.initializer?.let { generateExpressionBody(it) }
val irProperty = declarationFactory.createSimpleProperty(ktProperty, propertyDescriptor, initializer)
val initializer = ktProperty.initializer?.let { generateExpressionBody(propertyDescriptor, it) }
val irProperty = declarationFactory.createSimpleProperty(ktProperty, propertyDescriptor, initializer).register()
ktProperty.getter?.let { ktGetter ->
val accessorDescriptor = getOrFail(BindingContext.PROPERTY_ACCESSOR, ktGetter) { "unresolved getter" }
val getterDescriptor = accessorDescriptor as? PropertyGetterDescriptor ?: TODO("not a getter?")
val getterBody = generateExpressionBody(ktGetter.bodyExpression ?: TODO("default getter"))
declarationFactory.createPropertyGetter(ktGetter, irProperty, getterDescriptor, getterBody)
val getterBody = generateExpressionBody(getterDescriptor, ktGetter.bodyExpression ?: TODO("default getter"))
declarationFactory.createPropertyGetter(ktGetter, irProperty, getterDescriptor, getterBody).register()
}
ktProperty.setter?.let { ktSetter ->
val accessorDescriptor = getOrFail(BindingContext.PROPERTY_ACCESSOR, ktSetter) { "unresolved setter" }
val setterDescriptor = accessorDescriptor as? PropertySetterDescriptor ?: TODO("not a setter?")
val setterBody = generateExpressionBody(ktSetter.bodyExpression ?: TODO("default setter"))
declarationFactory.createPropertySetter(ktSetter, irProperty, setterDescriptor, setterBody)
val setterBody = generateExpressionBody(setterDescriptor, ktSetter.bodyExpression ?: TODO("default setter"))
declarationFactory.createPropertySetter(ktSetter, irProperty, setterDescriptor, setterBody).register()
}
}
@@ -93,19 +89,8 @@ abstract class IrDeclarationGeneratorBase(
return propertyDescriptor
}
fun generateExpressionBody(ktBody: KtExpression): IrBody {
val irExpression = irExpressionGenerator.generateExpression(ktBody)
val startOffset = ktBody.startOffset
val endOffset = ktBody.endOffset
val bodyExpression =
if (ktBody is KtBlockExpression)
irExpression
else
IrReturnExpressionImpl(startOffset, endOffset, irExpression.type)
.apply { returnedExpression = irExpression }
return IrExpressionBodyImpl(startOffset, endOffset, containingDeclaration).apply { argument = bodyExpression }
}
fun generateExpressionBody(scopeOwner: DeclarationDescriptor, ktBody: KtExpression): IrBody =
IrExpressionBodyImpl(ktBody.startOffset, ktBody.endOffset).apply {
argument = IrExpressionGenerator(context, IrLocalDeclarationsFactory(scopeOwner)).generateExpression(ktBody)
}
}
@@ -16,66 +16,64 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
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.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.resolve.constants.IntValue
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.scopes.receivers.*
class IrExpressionGenerator(
override val context: IrGeneratorContext,
val declarationFactory: IrDeclarationFactory
val declarationFactory: IrLocalDeclarationsFactory
) : KtVisitor<IrExpression, Nothing?>(), IrGenerator {
private val irCallGenerator = IrCallGenerator(context, this)
fun generateExpression(ktExpression: KtExpression) = ktExpression.generate()
private fun KtElement.generate(): IrExpression =
deparenthesize()
.accept(this@IrExpressionGenerator, null)
.smartCastIfNeeded(this)
.accept(this@IrExpressionGenerator, null)
.applySmartCastIfNeeded(this)
private fun KtExpression.type() =
getType(this) ?: TODO("no type for expression")
private fun IrExpression.smartCastIfNeeded(ktElement: KtElement): IrExpression {
private fun IrExpression.applySmartCastIfNeeded(ktElement: KtElement): IrExpression {
if (ktElement is KtExpression) {
val smartCastType = get(BindingContext.SMARTCAST, ktElement)
if (smartCastType != null) {
return IrTypeOperatorExpressionImpl(
ktElement.startOffset, ktElement.endOffset, smartCastType,
IrTypeOperator.SMART_AS, smartCastType
).apply { argument = this@smartCastIfNeeded }
).apply { argument = this@applySmartCastIfNeeded }
}
}
return this
}
override fun visitExpression(expression: KtExpression, data: Nothing?): IrExpression =
IrDummyExpression(expression.startOffset, expression.endOffset, expression.type(), expression.javaClass.simpleName)
IrDummyExpression(expression.startOffset, expression.endOffset, getTypeOrFail(expression), expression.javaClass.simpleName)
override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrExpression {
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), false)
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), false)
expression.statements.forEach { irBlock.addChildExpression(it.generate()) }
return irBlock
}
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrExpression =
IrReturnExpressionImpl(expression.startOffset, expression.endOffset, expression.type())
IrReturnExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression))
.apply { this.argument = expression.returnedExpression?.generate() }
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression {
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
?: error("KtConstantExpression was not evaluated: ${expression.text}")
val constantValue = compileTimeConstant.toConstantValue(expression.type())
val constantValue = compileTimeConstant.toConstantValue(getTypeOrFail(expression))
val constantType = constantValue.type
return when (constantValue) {
@@ -93,7 +91,7 @@ class IrExpressionGenerator(
return expression.entries[0].generate()
}
val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, expression.type())
val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression))
expression.entries.forEach { irStringTemplate.addChildExpression(it.generate()) }
return irStringTemplate
}
@@ -108,24 +106,24 @@ class IrExpressionGenerator(
TODO("Unexpected VariableAsFunctionResolvedCall")
}
val descriptor = resolvedCall?.resultingDescriptor ?: get(BindingContext.REFERENCE_TARGET, expression)
val descriptor = resolvedCall?.resultingDescriptor
return when (descriptor) {
is ClassDescriptor ->
if (DescriptorUtils.isObject(descriptor))
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), descriptor)
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), descriptor)
else if (DescriptorUtils.isEnumEntry(descriptor))
IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), descriptor)
IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), descriptor)
else
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, expression.type(),
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression),
descriptor.companionObjectDescriptor ?: error("Class value without companion object: $descriptor"))
is PropertyDescriptor -> {
generateCall(expression, resolvedCall ?: TODO("Property, no resolved call: ${descriptor.name}"), null)
irCallGenerator.generateCall(expression, resolvedCall)
}
is VariableDescriptor ->
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), descriptor)
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), descriptor)
else ->
IrDummyExpression(expression.startOffset, expression.endOffset, expression.type(),
IrDummyExpression(expression.startOffset, expression.endOffset, getTypeOrFail(expression),
expression.getReferencedName() +
": ${descriptor?.name} ${descriptor?.javaClass?.simpleName}")
}
@@ -138,7 +136,7 @@ class IrExpressionGenerator(
TODO("VariableAsFunctionResolvedCall = variable call + invoke call")
}
return generateCall(expression, resolvedCall, null, null)
return irCallGenerator.generateCall(expression, resolvedCall)
}
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Nothing?): IrExpression =
@@ -151,77 +149,16 @@ class IrExpressionGenerator(
val referenceTarget = getOrFail(BindingContext.REFERENCE_TARGET, expression.instanceReference) { "No reference target for this" }
return when (referenceTarget) {
is ClassDescriptor ->
IrThisExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), referenceTarget)
IrThisExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), referenceTarget)
is CallableDescriptor ->
IrGetExtensionReceiverExpressionImpl(expression.startOffset, expression.endOffset, expression.type(),
referenceTarget.extensionReceiverParameter!!)
IrGetExtensionReceiverExpressionImpl(
expression.startOffset, expression.endOffset, getTypeOrFail(expression),
referenceTarget.extensionReceiverParameter!!
)
else ->
error("Expected this or receiver: $referenceTarget")
}
}
private fun generateCall(
ktExpression: KtExpression,
resolvedCall: ResolvedCall<out CallableDescriptor>,
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
): IrExpression {
val descriptor = resolvedCall.resultingDescriptor
return when (descriptor) {
is PropertyDescriptor ->
IrGetPropertyExpressionImpl(
ktExpression.startOffset, ktExpression.endOffset, ktExpression.type(),
resolvedCall.call.isSafeCall(), descriptor
)
else ->
IrCallExpressionImpl(
ktExpression.startOffset, ktExpression.endOffset, ktExpression.type(),
resolvedCall.resultingDescriptor, resolvedCall.call.isSafeCall(), operator, superQualifier
).apply {
val valueParameters = resolvedCall.resultingDescriptor.valueParameters
val valueArguments = resolvedCall.valueArgumentsByIndex ?: TODO("null for value arguments: ${ktExpression.text}")
for (index in valueArguments.indices) {
val valueArgument = valueArguments[index]
val valueParameter = valueParameters[index]
putValueArgument(valueParameter, generateValueArgument(valueParameter, valueArgument))
}
}
}.apply {
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver)
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver)
}
}
private fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? =
when (receiver) {
is ImplicitClassReceiver ->
IrThisExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type, receiver.classDescriptor)
is ThisClassReceiver ->
(receiver as? ExpressionReceiver)?.expression?.let { receiverExpression ->
IrThisExpressionImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor)
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
is ExpressionReceiver ->
receiver.expression.generate()
is ClassValueReceiver ->
IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
receiver.classQualifier.descriptor)
is ExtensionReceiver ->
IrGetExtensionReceiverExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type,
receiver.declarationDescriptor.extensionReceiverParameter!!)
null ->
null
else ->
TODO("Receiver: ${receiver.javaClass.simpleName}")
}
private fun generateValueArgument(valueParameter: ValueParameterDescriptor, valueArgument: ResolvedValueArgument): IrExpression? {
if (valueParameter.varargElementType == null) {
assert(valueArgument.arguments.size == 1) { "Single value argument expected for a non-vararg parameter" }
return valueArgument.arguments.single().getArgumentExpression()!!.generate()
}
else {
TODO("vararg")
}
}
}
@@ -16,16 +16,17 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFileImpl
import org.jetbrains.kotlin.psi.KtFile
class IrFileGenerator(
private val ktFile: KtFile,
context: IrGeneratorContext,
irDeclaration: IrFileImpl,
irFile: IrFile,
parent: IrModuleGenerator,
declarationFactory: IrDeclarationFactory
) : IrDeclarationGeneratorBase(context, irDeclaration, parent, declarationFactory) {
) : IrDeclarationGeneratorBase(context, irFile, declarationFactory) {
fun generateFileContent() {
generateAnnotationEntries(ktFile.annotationEntries)
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
@@ -30,12 +31,18 @@ interface IrGenerator {
fun IrGenerator.getType(key: KtExpression): KotlinType? =
context.bindingContext.getType(key)
fun IrGenerator.getTypeOrFail(key: KtExpression): KotlinType =
getType(key) ?: TODO("No type for expression: ${key.text}")
fun <K, V : Any> IrGenerator.get(slice: ReadOnlySlice<K, V>, key: K): V? =
context.bindingContext[slice, key]
inline fun <K, V : Any> IrGenerator.getOrFail(slice: ReadOnlySlice<K, V>, key: K, message: (K) -> String): V =
context.bindingContext[slice, key] ?: throw RuntimeException(message(key))
fun IrGenerator.isUsedAsExpression(ktExpression: KtExpression) =
get(BindingContext.USED_AS_EXPRESSION, ktExpression) ?: false
inline fun <K, V : Any> IrGenerator.getOrElse(slice: ReadOnlySlice<K, V>, key: K, otherwise: (K) -> V): V =
context.bindingContext[slice, key] ?: otherwise(key)
@@ -16,19 +16,19 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.ir.declarations.IrModule
import org.jetbrains.kotlin.ir.declarations.IrFileImpl
import org.jetbrains.kotlin.resolve.BindingContext
class IrModuleGenerator(override val context: IrGeneratorContext) : IrDeclarationGenerator {
override val irDeclaration: IrModule get() = context.irModule
override val parent: IrDeclarationGenerator? get() = null
fun generateModuleContent() {
for (ktFile in context.inputFiles) {
val packageFragmentDescriptor = getOrFail(BindingContext.FILE_TO_PACKAGE_FRAGMENT, ktFile) { "no package fragment for file" }
val irFileElementFactory = IrDeclarationFactory.create(context.irModule, context.sourceManager, ktFile, packageFragmentDescriptor)
val irFile = irFileElementFactory.irFileImpl
val fileEntry = context.sourceManager.getOrCreateFileEntry(ktFile)
val fileName = fileEntry.getRecognizableName()
val irFile = IrFileImpl(fileEntry, fileName, packageFragmentDescriptor)
context.sourceManager.putFileEntry(irFile, fileEntry)
context.irModule.addFile(irFile)
val irFileElementFactory = IrDeclarationFactory()
val generator = IrFileGenerator(ktFile, context, irFile, this, irFileElementFactory)
generator.generateFileContent()
}
@@ -14,8 +14,9 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.ir.expressions
package org.jetbrains.kotlin.ir
const val CHILD_DECLARATION_INDEX = 0
const val DETACHED_INDEX = Int.MIN_VALUE
const val CHILD_EXPRESSION_INDEX = 0
const val ARGUMENT0_INDEX = 0
@@ -16,36 +16,43 @@
package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.ir.CHILD_DECLARATION_INDEX
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrElementBase
import org.jetbrains.kotlin.ir.DETACHED_INDEX
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import java.util.*
interface IrDeclarationOwner : IrElement {
val childrenCount: Int
fun getChildDeclaration(index: Int): IrMemberDeclaration?
fun addChildDeclaration(child: IrMemberDeclaration)
fun replaceChildDeclaration(oldChild: IrMemberDeclaration, newChild: IrMemberDeclaration)
fun removeAllChildDeclarations()
}
// TODO This can be an expensive operation / prohibited for some children.
interface IrDeclarationOwner1 : IrDeclarationOwner {
val childDeclaration: IrMemberDeclaration
}
interface IrDeclarationOwnerN : IrDeclarationOwner {
val childrenCount: Int
fun addChildDeclaration(child: IrMemberDeclaration)
fun removeChildDeclaration(child: IrMemberDeclaration)
fun removeAllChildDeclarations()
fun <D> acceptChildDeclarations(visitor: IrElementVisitor<Unit, D>, data: D)
}
interface IrCompoundDeclaration : IrDeclaration, IrDeclarationOwner
interface IrCompoundDeclaration : IrDeclaration, IrDeclarationOwnerN
interface IrMemberDeclaration : IrDeclaration {
override val parent: IrDeclarationOwner
override var parent: IrDeclarationOwner?
fun setTreeLocation(parent: IrDeclarationOwner?, index: Int)
}
abstract class IrDeclarationOwnerBase(
abstract class IrDeclarationOwnerNBase(
startOffset: Int,
endOffset: Int
) : IrElementBase(startOffset, endOffset), IrDeclarationOwner {
) : IrElementBase(startOffset, endOffset), IrDeclarationOwnerN {
protected val childDeclarations: MutableList<IrMemberDeclaration> = ArrayList()
override val childrenCount: Int
@@ -90,7 +97,7 @@ abstract class IrCompoundDeclarationBase(
startOffset: Int,
endOffset: Int,
override val originKind: IrDeclarationOriginKind
) : IrDeclarationOwnerBase(startOffset, endOffset), IrCompoundDeclaration {
) : IrDeclarationOwnerNBase(startOffset, endOffset), IrCompoundDeclaration {
override var indexInParent: Int = IrDeclaration.DETACHED_INDEX
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
@@ -105,7 +112,7 @@ abstract class IrCompoundMemberDeclarationBase(
) : IrCompoundDeclarationBase(startOffset, endOffset, originKind), IrMemberDeclaration {
private var parentImpl: IrDeclarationOwner? = null
override var parent: IrDeclarationOwner
override var parent: IrDeclarationOwner?
get() = parentImpl!!
set(newParent) {
parentImpl = newParent
@@ -124,7 +131,7 @@ abstract class IrMemberDeclarationBase(
) : IrDeclarationBase(startOffset, endOffset, originKind), IrMemberDeclaration {
private var parentImpl: IrDeclarationOwner? = null
override var parent: IrDeclarationOwner
override var parent: IrDeclarationOwner?
get() = parentImpl!!
set(newParent) {
parentImpl = newParent
@@ -38,15 +38,16 @@ enum class IrDeclarationKind {
MODULE,
FILE,
FUNCTION,
PROPERTY,
PROPERTY_GETTER,
PROPERTY_SETTER,
PROPERTY,
LOCAL_VARIABLE,
CLASS
}
enum class IrDeclarationOriginKind {
DEFINED,
DEFAULT_PROPERTY_ACCESSOR,
IR_TEMPORARY_VARIABLE,
}
abstract class IrDeclarationBase(
@@ -45,6 +45,10 @@ class IrFunctionImpl(
override val descriptor: FunctionDescriptor,
override val body: IrBody
) : IrFunctionBase(startOffset, endOffset, originKind) {
init {
body.parent = this
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitFunction(this, data)
}
@@ -0,0 +1,65 @@
/*
* 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.declarations
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.CHILD_EXPRESSION_INDEX
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrLocalVariable : IrMemberDeclaration, IrExpressionOwner {
override val descriptor: VariableDescriptor
override val declarationKind: IrDeclarationKind
get() = IrDeclarationKind.LOCAL_VARIABLE
var initializerExpression: IrExpression?
}
class IrLocalVariableImpl(
startOffset: Int,
endOffset: Int,
originKind: IrDeclarationOriginKind,
override val descriptor: VariableDescriptor
) : IrMemberDeclarationBase(startOffset, endOffset, originKind), IrLocalVariable {
override var initializerExpression: IrExpression? = null
set(value) {
field?.detach()
field = value
value?.setTreeLocation(this, CHILD_EXPRESSION_INDEX)
}
override fun getChildExpression(index: Int): IrExpression? =
if (index == CHILD_EXPRESSION_INDEX) initializerExpression else null
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
initializerExpression = newChild
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitLocalVariable(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
acceptChildExpressions(visitor, data)
}
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
initializerExpression?.accept(visitor, data)
}
}
@@ -71,6 +71,10 @@ class IrSimplePropertyImpl(
descriptor: PropertyDescriptor,
override val valueInitializer: IrBody?
) : IrPropertyBase(startOffset, endOffset, originKind, descriptor), IrSimpleProperty {
init {
valueInitializer?.parent = this
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitSimpleProperty(this, data)
@@ -47,6 +47,10 @@ abstract class IrPropertyAccessorBase(
originKind: IrDeclarationOriginKind,
override val body: IrBody
) : IrFunctionBase(startOffset, endOffset, originKind), IrPropertyAccessor {
init {
body.parent = this
}
override var property: IrProperty? = null
}
@@ -0,0 +1,48 @@
/*
* 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.descriptors
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.VariableDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
interface IrTemporaryVariableDescriptor : VariableDescriptor
class IrTemporaryVariableDescriptorImpl(
containingDeclaration: DeclarationDescriptor,
name: Name,
outType: KotlinType
): VariableDescriptorImpl(containingDeclaration, Annotations.EMPTY, name, outType, SourceElement.NO_SOURCE),
IrTemporaryVariableDescriptor
{
override fun getCompileTimeInitializer(): ConstantValue<*>? = null
override fun getVisibility(): Visibility = Visibilities.LOCAL
override fun substitute(substitutor: TypeSubstitutor): VariableDescriptor {
throw UnsupportedOperationException("Temporary variable descriptor shouldn't be substituted (so far): $this")
}
override fun isVar(): Boolean = false
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D): R =
visitor.visitVariableDescriptor(this, data)
}
@@ -16,24 +16,27 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.CHILD_EXPRESSION_INDEX
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrElementBase
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOwner
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOwnerBase
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOwnerNBase
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrBody : IrElement {
override val parent: IrDeclaration
override var parent: IrDeclaration
}
interface IrExpressionBody : IrBody, IrExpressionOwner1, IrDeclarationOwner
interface IrExpressionBody : IrBody, IrExpressionOwner1
// TODO IrExpressionBodyImpl vs IrCompoundExpression1Impl: extract common base class?
class IrExpressionBodyImpl(
startOffset: Int,
endOffset: Int,
override val parent: IrDeclaration
) : IrDeclarationOwnerBase(startOffset, endOffset), IrExpressionBody {
endOffset: Int
) : IrElementBase(startOffset, endOffset), IrExpressionBody {
override lateinit var parent: IrDeclaration
override var argument: IrExpression? = null
set(newExpression) {
field?.detach()
@@ -18,7 +18,8 @@ package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.DISPATCH_RECEIVER_INDEX
import org.jetbrains.kotlin.ir.EXTENSION_RECEIVER_INDEX
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -27,16 +28,13 @@ interface IrCallExpression : IrMemberAccessExpression, IrCompoundExpression {
val operator: IrOperator?
override val descriptor: CallableDescriptor
fun getValueArgument(valueParameterDescriptor: ValueParameterDescriptor): IrExpression?
fun putValueArgument(valueParameterDescriptor: ValueParameterDescriptor, valueArgument: IrExpression?)
fun removeValueArgument(valueParameterDescriptor: ValueParameterDescriptor)
fun getValueArgument(index: Int): IrExpression?
fun putValueArgument(index: Int, valueArgument: IrExpression?)
fun removeValueArgument(index: Int)
fun <D> acceptValueArguments(visitor: IrElementVisitor<Unit, D>, data: D)
}
fun IrCallExpression.getMappedValueArguments(): List<IrExpression?> =
descriptor.valueParameters.mapNotNull { getValueArgument(it) }
class IrCallExpressionImpl(
startOffset: Int,
endOffset: Int,
@@ -49,22 +47,18 @@ class IrCallExpressionImpl(
private val argumentsByParameterIndex =
kotlin.arrayOfNulls<IrExpression>(descriptor.valueParameters.size)
override fun getValueArgument(valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
argumentsByParameterIndex[valueParameterDescriptor.index]
override fun getValueArgument(index: Int): IrExpression? =
argumentsByParameterIndex[index]
override fun putValueArgument(valueParameterDescriptor: ValueParameterDescriptor, valueArgument: IrExpression?) {
putValueArgument(valueParameterDescriptor.index, valueArgument)
}
private fun putValueArgument(index: Int, valueArgument: IrExpression?) {
override fun putValueArgument(index: Int, valueArgument: IrExpression?) {
argumentsByParameterIndex[index]?.detach()
argumentsByParameterIndex[index] = valueArgument
valueArgument?.setTreeLocation(this, index)
}
override fun removeValueArgument(valueParameterDescriptor: ValueParameterDescriptor) {
argumentsByParameterIndex[valueParameterDescriptor.index]?.detach()
argumentsByParameterIndex[valueParameterDescriptor.index] = null
override fun removeValueArgument(index: Int) {
argumentsByParameterIndex[index]?.detach()
argumentsByParameterIndex[index] = null
}
override fun getChildExpression(index: Int): IrExpression? =
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.ARGUMENT0_INDEX
import org.jetbrains.kotlin.ir.ARGUMENT1_INDEX
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.DETACHED_INDEX
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrElementBase
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
@@ -0,0 +1,67 @@
/*
* 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.CHILD_DECLARATION_INDEX
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrLocalDeclarationExpression<out D : IrMemberDeclaration> : IrExpression, IrDeclarationOwner1 {
override val childDeclaration: D
}
interface IrLocalVariableDeclarationExpression : IrLocalDeclarationExpression<IrLocalVariable> {
override var childDeclaration: IrLocalVariable
}
abstract class IrLocalDeclarationExpressionBase(
startOffset: Int,
endOffset: Int,
type: KotlinType
) : IrExpressionBase(startOffset, endOffset, type), IrLocalVariableDeclarationExpression {
private var childDeclarationImpl: IrLocalVariable? = null
override var childDeclaration: IrLocalVariable
get() = childDeclarationImpl!!
set(value) {
childDeclarationImpl?.detach()
childDeclarationImpl = value
value.setTreeLocation(this, CHILD_DECLARATION_INDEX)
}
override fun getChildDeclaration(index: Int): IrMemberDeclaration? =
if (index == CHILD_DECLARATION_INDEX) childDeclaration else null
override fun replaceChildDeclaration(oldChild: IrMemberDeclaration, newChild: IrMemberDeclaration) {
if (newChild !is IrLocalVariable) throw AssertionError("IrLocalVariable expected: $newChild")
validateChild(oldChild)
childDeclaration = newChild
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
childDeclarationImpl?.accept(visitor, data)
}
}
class IrLocalVariableDeclarationExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType
) : IrLocalDeclarationExpressionBase(startOffset, endOffset, type), IrLocalVariableDeclarationExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitLocalVariableDeclarationExpression(this, data)
}
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.DISPATCH_RECEIVER_INDEX
import org.jetbrains.kotlin.ir.EXTENSION_RECEIVER_INDEX
import org.jetbrains.kotlin.types.KotlinType
interface IrMemberAccessExpression : IrDeclarationReference, IrExpressionOwner {
@@ -17,11 +17,12 @@
package org.jetbrains.kotlin.ir.expressions
enum class IrOperator {
INVOKE, INVOKE_EXTENSION,
INVOKE,
PREFIX_INCR, PREFIX_DECR, POSTFIX_INCR, POSTFIX_DECR,
UMINUS,
EXCL,
EXCLEXCL,
ELVIS,
LT, GT, LTEQ, GTEQ,
EQEQ, EQEQEQ, EXCLEQ, EXCLEQEQ,
IN, NOT_IN,
@@ -32,32 +33,36 @@ enum class IrOperator {
PLUSEQ, MINUSEQ, MULEQ, DIVEQ, MODEQ;
}
private val CAO_START = IrOperator.PLUSEQ
private val CAO_END = IrOperator.MODEQ
private val DUAL_START = IrOperator.PLUS
private val DUAL_END = IrOperator.MOD
private val INCR_DECR_START = IrOperator.PREFIX_INCR
private val INCR_DECR_END = IrOperator.POSTFIX_DECR
private val CAO_START = IrOperator.PLUSEQ.ordinal
private val CAO_END = IrOperator.MODEQ.ordinal
private val DUAL_START = IrOperator.PLUS.ordinal
private val DUAL_END = IrOperator.MOD.ordinal
private val INCR_DECR_START = IrOperator.PREFIX_INCR.ordinal
private val INCR_DECR_END = IrOperator.POSTFIX_DECR.ordinal
private val RELATIONAL_START = IrOperator.LT.ordinal
private val RELATIONAL_END = IrOperator.GTEQ.ordinal
fun IrOperator.isIncrementOrDecrement(): Boolean =
this in INCR_DECR_START..INCR_DECR_END
this.ordinal in INCR_DECR_START..INCR_DECR_END
fun IrOperator.isCompoundAssignment(): Boolean =
this in CAO_START .. CAO_END
this.ordinal in CAO_START .. CAO_END
fun IrOperator.isAssignmentOrCompoundAssignment(): Boolean =
this == IrOperator.EQ || isCompoundAssignment()
fun IrOperator.hasCompoundAssignmentDual(): Boolean =
this in DUAL_START .. DUAL_END
this.ordinal in DUAL_START .. DUAL_END
fun IrOperator.toDualOperator(): IrOperator =
when {
isCompoundAssignment() ->
IrOperator.values()[this.ordinal - CAO_START.ordinal + DUAL_START.ordinal]
IrOperator.values()[this.ordinal - CAO_START + DUAL_START]
hasCompoundAssignmentDual() ->
IrOperator.values()[this.ordinal - DUAL_START.ordinal + CAO_START.ordinal]
IrOperator.values()[this.ordinal - DUAL_START + CAO_START]
else ->
throw UnsupportedOperationException("Operator $this is not a compound assignment")
}
fun IrOperator.isRelational(): Boolean =
this.ordinal in RELATIONAL_START .. RELATIONAL_END
@@ -17,6 +17,9 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.ARGUMENT0_INDEX
import org.jetbrains.kotlin.ir.DISPATCH_RECEIVER_INDEX
import org.jetbrains.kotlin.ir.EXTENSION_RECEIVER_INDEX
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -50,7 +50,7 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
expression.dispatchReceiver?.accept(this, "\$this")
expression.extensionReceiver?.accept(this, "\$receiver")
for (valueParameter in expression.descriptor.valueParameters) {
expression.getValueArgument(valueParameter)?.accept(this, valueParameter.name.asString())
expression.getValueArgument(valueParameter.index)?.accept(this, valueParameter.name.asString())
}
}
}
@@ -48,6 +48,9 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitPropertySetter(declaration: IrPropertySetter, data: Nothing?): String =
"IrPropertySetter ${declaration.descriptor.render()} property=${declaration.property?.name()}"
override fun visitLocalVariable(declaration: IrLocalVariable, data: Nothing?): String =
"IrLocalVariable ${declaration.descriptor.render()}"
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
"IrExpressionBody"
@@ -57,6 +60,9 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun <T> visitLiteral(expression: IrLiteralExpression<T>, data: Nothing?): String =
"LITERAL ${expression.kind} type=${expression.renderType()} value='${expression.value}'"
override fun visitLocalVariableDeclarationExpression(expression: IrLocalVariableDeclarationExpression, data: Nothing?): String =
"LOCAL ${expression.childDeclaration.descriptor.name}"
override fun visitBlockExpression(expression: IrBlockExpression, data: Nothing?): String =
"BLOCK type=${expression.renderType()}"
@@ -34,6 +34,7 @@ interface IrElementVisitor<out R, in D> {
fun visitProperty(declaration: IrProperty, data: D): R = visitDeclaration(declaration, data)
fun visitSimpleProperty(declaration: IrSimpleProperty, data: D): R = visitProperty(declaration, data)
fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D): R = visitProperty(declaration, data)
fun visitLocalVariable(declaration: IrLocalVariable, data: D) = visitDeclaration(declaration, data)
fun visitBody(body: IrBody, data: D): R = visitElement(body, data)
fun visitExpressionBody(body: IrExpressionBody, data: D): R = visitBody(body, data)
@@ -45,6 +46,11 @@ interface IrElementVisitor<out R, in D> {
fun visitStringTemplate(expression: IrStringConcatenationExpression, data: D) = visitExpression(expression, data)
fun visitThisExpression(expression: IrThisExpression, data: D) = visitExpression(expression, data)
fun <T : IrMemberDeclaration> visitLocalDeclarationExpression(expression: IrLocalDeclarationExpression<T>, data: D) =
visitExpression(expression, data)
fun visitLocalVariableDeclarationExpression(expression: IrLocalVariableDeclarationExpression, data: D) =
visitLocalDeclarationExpression(expression, data)
fun visitDeclarationReference(expression: IrDeclarationReference, data: D) = visitExpression(expression, data)
fun visitGetObjectValue(expression: IrGetObjectValueExpression, data: D) = visitDeclarationReference(expression, data)
fun visitGetEnumValue(expression: IrGetEnumValueExpression, data: D) = visitDeclarationReference(expression, data)
@@ -65,6 +71,4 @@ interface IrElementVisitor<out R, in D> {
fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data)
}
+1 -2
View File
@@ -1,5 +1,4 @@
IrFile /boxOk.kt
IrFunction public fun box(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
LITERAL String type=kotlin.String value='OK'
LITERAL String type=kotlin.String value='OK'
@@ -0,0 +1,13 @@
// <<< callWithReorderedArguments.txt
fun foo(a: Int, b: Int) {}
fun noReorder1() = 1
fun noReorder2() = 2
fun reordered1() = 1
fun reordered2() = 2
fun test() {
foo(a = noReorder1(), b = noReorder2())
foo(b = reordered1(), a = reordered2())
}
@@ -0,0 +1,32 @@
IrFile /callWithReorderedArguments.kt
IrFunction public fun foo(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Unit
IrExpressionBody
BLOCK type=kotlin.Unit
IrFunction public fun noReorder1(): kotlin.Int
IrExpressionBody
LITERAL Int type=kotlin.Int value='1'
IrFunction public fun noReorder2(): kotlin.Int
IrExpressionBody
LITERAL Int type=kotlin.Int value='2'
IrFunction public fun reordered1(): kotlin.Int
IrExpressionBody
LITERAL Int type=kotlin.Int value='1'
IrFunction public fun reordered2(): kotlin.Int
IrExpressionBody
LITERAL Int type=kotlin.Int value='2'
IrFunction public fun test(): kotlin.Unit
IrExpressionBody
BLOCK type=kotlin.Unit
CALL .foo
a: CALL .noReorder1
b: CALL .noReorder2
BLOCK type=kotlin.Unit
LOCAL tmp0
IrLocalVariable val tmp0: kotlin.Int
CALL .reordered1
LOCAL tmp1
IrLocalVariable val tmp1: kotlin.Int
CALL .reordered2
CALL .foo
a: GET_VAR tmp1
b: GET_VAR tmp0
+12 -17
View File
@@ -1,29 +1,24 @@
IrFile /calls.kt
IrFunction public fun foo(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
GET_VAR x
GET_VAR x
IrFunction public fun bar(/*0*/ x: kotlin.Int): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
CALL .foo
x: GET_VAR x
y: LITERAL Int type=kotlin.Int value='1'
CALL .foo
x: GET_VAR x
y: LITERAL Int type=kotlin.Int value='1'
IrFunction public fun qux(/*0*/ x: kotlin.Int): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
CALL .foo
x: CALL .foo
x: GET_VAR x
y: GET_VAR x
CALL .foo
x: CALL .foo
x: GET_VAR x
y: GET_VAR x
y: GET_VAR x
IrFunction public fun kotlin.Int.ext1(): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
$RECEIVER of: ext1
$RECEIVER of: ext1
IrFunction public fun kotlin.Int.ext2(/*0*/ x: kotlin.Int): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
CALL .foo
x: $RECEIVER of: ext2
y: GET_VAR x
CALL .foo
x: $RECEIVER of: ext2
y: GET_VAR x
+4 -6
View File
@@ -1,11 +1,9 @@
IrFile /dotQualified.kt
IrFunction public fun length(/*0*/ s: kotlin.String): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
GET_PROPERTY .length
$this: GET_VAR s
GET_PROPERTY .length
$this: GET_VAR s
IrFunction public fun lengthN(/*0*/ s: kotlin.String?): kotlin.Int?
IrExpressionBody
RETURN type=kotlin.Int?
GET_PROPERTY ?.length
$this: GET_VAR s
GET_PROPERTY ?.length
$this: GET_VAR s
@@ -2,10 +2,8 @@ IrFile /extensionPropertyGetterCall.kt
IrProperty public val kotlin.String.okext: kotlin.String getter=<get-okext> setter=null
IrPropertyGetter public fun kotlin.String.<get-okext>(): kotlin.String property=okext
IrExpressionBody
RETURN type=kotlin.String
LITERAL String type=kotlin.String value='OK'
LITERAL String type=kotlin.String value='OK'
IrFunction public fun kotlin.String.test5(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
GET_PROPERTY .okext
$receiver: $RECEIVER of: test5
GET_PROPERTY .okext
$receiver: $RECEIVER of: test5
+9 -17
View File
@@ -1,25 +1,20 @@
IrFile /references.kt
IrProperty public val ok: kotlin.String = "OK" getter=null setter=null
IrExpressionBody
RETURN type=kotlin.String
LITERAL String type=kotlin.String value='OK'
LITERAL String type=kotlin.String value='OK'
IrProperty public val ok2: kotlin.String = "OK" getter=null setter=null
IrExpressionBody
RETURN type=kotlin.String
GET_PROPERTY .ok
GET_PROPERTY .ok
IrProperty public val ok3: kotlin.String getter=<get-ok3> setter=null
IrPropertyGetter public fun <get-ok3>(): kotlin.String property=ok3
IrExpressionBody
RETURN type=kotlin.String
LITERAL String type=kotlin.String value='OK'
LITERAL String type=kotlin.String value='OK'
IrFunction public fun test1(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
GET_PROPERTY .ok
GET_PROPERTY .ok
IrFunction public fun test2(/*0*/ x: kotlin.String): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
GET_VAR x
GET_VAR x
IrFunction public fun test3(): kotlin.String
IrExpressionBody
BLOCK type=kotlin.Nothing
@@ -28,15 +23,12 @@ IrFile /references.kt
GET_VAR x
IrFunction public fun test4(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
GET_PROPERTY .ok3
GET_PROPERTY .ok3
IrProperty public val kotlin.String.okext: kotlin.String getter=<get-okext> setter=null
IrPropertyGetter public fun kotlin.String.<get-okext>(): kotlin.String property=okext
IrExpressionBody
RETURN type=kotlin.String
LITERAL String type=kotlin.String value='OK'
LITERAL String type=kotlin.String value='OK'
IrFunction public fun kotlin.String.test5(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
GET_PROPERTY .okext
$receiver: $RECEIVER of: test5
GET_PROPERTY .okext
$receiver: $RECEIVER of: test5
+1 -2
View File
@@ -1,4 +1,3 @@
IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null
IrExpressionBody
RETURN type=kotlin.Int
LITERAL Int type=kotlin.Int value='1'
LITERAL Int type=kotlin.Int value='1'
+4 -8
View File
@@ -6,22 +6,18 @@ IrFile /smoke.kt
LITERAL String type=kotlin.String value='OK'
IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null
IrExpressionBody
RETURN type=kotlin.Int
LITERAL Int type=kotlin.Int value='1'
LITERAL Int type=kotlin.Int value='1'
IrProperty public val testValWithGetter: kotlin.Int getter=<get-testValWithGetter> setter=null
IrPropertyGetter public fun <get-testValWithGetter>(): kotlin.Int property=testValWithGetter
IrExpressionBody
RETURN type=kotlin.Int
LITERAL Int type=kotlin.Int value='42'
LITERAL Int type=kotlin.Int value='42'
IrProperty public var testSimpleVar: kotlin.Int getter=null setter=null
IrExpressionBody
RETURN type=kotlin.Int
LITERAL Int type=kotlin.Int value='2'
LITERAL Int type=kotlin.Int value='2'
IrProperty public var testVarWithAccessors: kotlin.Int getter=<get-testVarWithAccessors> setter=<set-testVarWithAccessors>
IrPropertyGetter public fun <get-testVarWithAccessors>(): kotlin.Int property=testVarWithAccessors
IrExpressionBody
RETURN type=kotlin.Int
LITERAL Int type=kotlin.Int value='42'
LITERAL Int type=kotlin.Int value='42'
IrPropertySetter public fun <set-testVarWithAccessors>(/*0*/ v: kotlin.Int): kotlin.Unit property=testVarWithAccessors
IrExpressionBody
BLOCK type=kotlin.Unit
@@ -41,6 +41,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName);
}
@TestMetadata("callWithReorderedArguments.kt")
public void testCallWithReorderedArguments() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/callWithReorderedArguments.kt");
doTest(fileName);
}
@TestMetadata("calls.kt")
public void testCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/calls.kt");