Simplify IrElement hierarchy.

IrDeclaration can be now hosted under IrExpression (as IrStatement).
This commit is contained in:
Dmitry Petrov
2016-08-15 11:40:42 +03:00
committed by Dmitry Petrov
parent 55eb79febf
commit 37cce98d19
47 changed files with 786 additions and 806 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.assertCast
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
@@ -29,7 +30,7 @@ import java.util.*
class IrCallGenerator(
override val context: IrGeneratorContext,
val irExpressionGenerator: IrExpressionGenerator
val irStatementGenerator: IrStatementGenerator
) : IrGenerator {
fun generateCall(
ktExpression: KtExpression,
@@ -92,7 +93,7 @@ class IrCallGenerator(
for (index in valueArguments!!.indices) {
val valueArgument = valueArguments[index]
val irArgument = generateValueArgument(valueArgument) ?: continue
irCall.putValueArgument(index, irArgument)
irCall.putArgument(index, irArgument)
}
}
}
@@ -105,17 +106,16 @@ class IrCallGenerator(
resultType: KotlinType
): IrExpression {
val valueArgumentsInEvaluationOrder = resolvedCall.valueArguments.values
val hasResult = isUsedAsExpression(ktExpression)
val irBlock = IrBlockExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, resultType, hasResult)
val irBlock = IrBlockExpressionImpl(ktExpression.startOffset, ktExpression.endOffset, resultType,
hasResult = isUsedAsExpression(ktExpression),
isDesugared = true)
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)
irTemporaryDeclaration.childDeclaration = irTemporary
irBlock.addChildExpression(irTemporaryDeclaration)
val irTemporary = irStatementGenerator.declarationFactory.createTemporaryVariable(irArgument)
irBlock.addStatement(irTemporary)
temporaryVariablesForValueArguments[valueArgument] = Pair(irTemporary.descriptor, irArgument)
}
@@ -124,16 +124,16 @@ class IrCallGenerator(
val (temporaryDescriptor, irArgument) = temporaryVariablesForValueArguments[valueArgument]!!
val irGetTemporary = IrGetVariableExpressionImpl(irArgument.startOffset, irArgument.endOffset,
irArgument.type, temporaryDescriptor)
irCall.putValueArgument(index, irGetTemporary)
irCall.putArgument(index, irGetTemporary)
}
irBlock.addChildExpression(irCall)
irBlock.addStatement(irCall)
return irBlock
}
// TODO smart casts on implicit receivers
private fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? =
fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? =
when (receiver) {
is ImplicitClassReceiver ->
IrThisExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type, receiver.classDescriptor)
@@ -142,7 +142,7 @@ class IrCallGenerator(
IrThisExpressionImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor)
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
is ExpressionReceiver ->
irExpressionGenerator.generateExpression(receiver.expression)
irStatementGenerator.generateStatement(receiver.expression).assertCast()
is ClassValueReceiver ->
IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
receiver.classQualifier.descriptor)
@@ -155,12 +155,12 @@ class IrCallGenerator(
TODO("Receiver: ${receiver.javaClass.simpleName}")
}
private fun generateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? {
fun generateValueArgument(valueArgument: ResolvedValueArgument): IrExpression? {
when (valueArgument) {
is DefaultValueArgument ->
return null
is ExpressionValueArgument ->
return irExpressionGenerator.generateExpression(valueArgument.valueArgument!!.getArgumentExpression()!!)
return irStatementGenerator.generateStatement(valueArgument.valueArgument!!.getArgumentExpression()!!).assertCast()
is VarargValueArgument ->
TODO("vararg")
else ->
@@ -70,20 +70,22 @@ class IrLocalDeclarationsFactory(val scopeOwner: DeclarationDescriptor) : IrDecl
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(ktElement: KtElement, type: KotlinType): IrVariable =
IrVariableImpl(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
?: throw AssertionError("No type for $irExpression"))
).apply { initializerExpression = irExpression }
fun createTemporaryVariable(irExpression: IrExpression): IrVariable =
IrVariableImpl(irExpression.startOffset, irExpression.endOffset,
IrDeclarationOriginKind.IR_TEMPORARY_VARIABLE,
createDescriptorForTemporaryVariable(
irExpression.type
?: throw AssertionError("No type for $irExpression")
)
).apply { initializer = irExpression }
fun createLocalVariable(ktElement: KtElement, descriptor: VariableDescriptor): IrLocalVariable =
IrLocalVariableImpl(ktElement.startOffset, ktElement.endOffset,
IrDeclarationOriginKind.DEFINED,
descriptor)
fun createLocalVariable(ktElement: KtElement, descriptor: VariableDescriptor): IrVariable =
IrVariableImpl(ktElement.startOffset, ktElement.endOffset,
IrDeclarationOriginKind.DEFINED,
descriptor)
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
import org.jetbrains.kotlin.ir.assertCast
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrExpressionBodyImpl
@@ -33,11 +34,9 @@ interface IrDeclarationGenerator : IrGenerator
abstract class IrDeclarationGeneratorBase(
override val context: IrGeneratorContext,
val container: IrDeclarationOwnerN,
val declarationFactory: IrDeclarationFactoryBase
) : IrDeclarationGenerator {
private fun <D : IrMemberDeclaration> D.register(): D =
apply { container.addChildDeclaration(this) }
protected abstract fun <D : IrDeclaration> D.register(): D
fun generateAnnotationEntries(annotationEntries: List<KtAnnotationEntry>) {
// TODO create IrAnnotation's for each KtAnnotationEntry
@@ -50,10 +49,10 @@ abstract class IrDeclarationGeneratorBase(
generateFunctionDeclaration(ktDeclaration)
is KtProperty ->
generatePropertyDeclaration(ktDeclaration)
is KtClassOrObject ->
TODO("classOrObject")
is KtTypeAlias ->
TODO("typealias")
is KtClassOrObject -> {}
// TODO("classOrObject")
is KtTypeAlias -> {}
// TODO("typealias")
}
}
@@ -90,6 +89,6 @@ abstract class IrDeclarationGeneratorBase(
fun generateExpressionBody(scopeOwner: DeclarationDescriptor, ktBody: KtExpression): IrBody =
IrExpressionBodyImpl(ktBody.startOffset, ktBody.endOffset).apply {
argument = IrExpressionGenerator(context, IrLocalDeclarationsFactory(scopeOwner)).generateExpression(ktBody)
expression = IrStatementGenerator(context, IrLocalDeclarationsFactory(scopeOwner)).generateStatement(ktBody).assertCast()
}
}
@@ -16,17 +16,20 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
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,
private val irFile: IrFile,
context: IrGeneratorContext,
irFile: IrFile,
parent: IrModuleGenerator,
declarationFactory: IrDeclarationFactory
) : IrDeclarationGeneratorBase(context, irFile, declarationFactory) {
) : IrDeclarationGeneratorBase(context, declarationFactory) {
override fun <D : IrDeclaration> D.register(): D =
apply { irFile.addDeclaration(this) }
fun generateFileContent() {
generateAnnotationEntries(ktFile.annotationEntries)
@@ -37,6 +37,9 @@ fun IrGenerator.getTypeOrFail(key: KtExpression): KotlinType =
fun <K, V : Any> IrGenerator.get(slice: ReadOnlySlice<K, V>, key: K): V? =
context.bindingContext[slice, key]
fun <K, V : Any> IrGenerator.getOrFail(slice: ReadOnlySlice<K, V>, key: K): V =
context.bindingContext[slice, key] ?: throw RuntimeException("No $slice for $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))
@@ -22,14 +22,14 @@ import org.jetbrains.kotlin.resolve.BindingContext
class IrModuleGenerator(override val context: IrGeneratorContext) : IrDeclarationGenerator {
fun generateModuleContent() {
for (ktFile in context.inputFiles) {
val packageFragmentDescriptor = getOrFail(BindingContext.FILE_TO_PACKAGE_FRAGMENT, ktFile) { "no package fragment for file" }
val packageFragmentDescriptor = getOrFail(BindingContext.FILE_TO_PACKAGE_FRAGMENT, ktFile)
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)
val generator = IrFileGenerator(ktFile, irFile, context, irFileElementFactory)
generator.generateFileContent()
}
}
@@ -20,6 +20,8 @@ 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.IrStatement
import org.jetbrains.kotlin.ir.assertCast
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
@@ -31,55 +33,59 @@ import org.jetbrains.kotlin.resolve.constants.IntValue
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
class IrExpressionGenerator(
class IrStatementGenerator(
override val context: IrGeneratorContext,
val declarationFactory: IrLocalDeclarationsFactory
) : KtVisitor<IrExpression, Nothing?>(), IrGenerator {
) : KtVisitor<IrStatement, Nothing?>(), IrGenerator {
private val irCallGenerator = IrCallGenerator(context, this)
fun generateExpression(ktExpression: KtExpression) = ktExpression.generate()
fun generateStatement(ktExpression: KtExpression) = ktExpression.generate()
private fun KtElement.generate(): IrExpression =
private fun KtElement.generate(): IrStatement =
deparenthesize()
.accept(this@IrExpressionGenerator, null)
.accept(this@IrStatementGenerator, null)
.applySmartCastIfNeeded(this)
private fun IrExpression.applySmartCastIfNeeded(ktElement: KtElement): IrExpression {
if (ktElement is KtExpression) {
private fun KtElement.generateExpression(): IrExpression =
generate().assertCast()
private fun IrStatement.applySmartCastIfNeeded(ktElement: KtElement): IrStatement {
if (this is IrExpression && 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@applySmartCastIfNeeded }
IrTypeOperator.SMART_AS, this@applySmartCastIfNeeded, smartCastType
)
}
}
return this
}
override fun visitExpression(expression: KtExpression, data: Nothing?): IrExpression =
IrDummyExpression(expression.startOffset, expression.endOffset, getTypeOrFail(expression), expression.javaClass.simpleName)
override fun visitExpression(expression: KtExpression, data: Nothing?): IrStatement =
IrDummyExpression(expression.startOffset, expression.endOffset, getType(expression), expression.javaClass.simpleName)
override fun visitProperty(property: KtProperty, data: Nothing?): IrExpression {
override fun visitProperty(property: KtProperty, data: Nothing?): IrStatement {
if (property.delegateExpression != null) TODO("Local delegated property")
val variableDescriptor = getOrFail(BindingContext.VARIABLE, property) { "No descriptor for local variable ${property.name}" }
val variableDescriptor = getOrFail(BindingContext.VARIABLE, property)
val irLocalVariable = declarationFactory.createLocalVariable(property, variableDescriptor)
irLocalVariable.initializerExpression = property.initializer?.generate()
irLocalVariable.initializer = property.initializer?.generateExpression()
return IrLocalVariableDeclarationExpressionImpl(property.startOffset, property.endOffset, irLocalVariable)
return irLocalVariable
}
override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrExpression {
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), false)
expression.statements.forEach { irBlock.addChildExpression(it.generate()) }
override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrStatement {
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, getType(expression),
hasResult = isUsedAsExpression(expression), isDesugared = false)
expression.statements.forEach { irBlock.addStatement(it.generate()) }
return irBlock
}
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrExpression =
IrReturnExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression))
.apply { this.argument = expression.returnedExpression?.generate() }
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrStatement =
IrReturnExpressionImpl(expression.startOffset, expression.endOffset, getType(expression),
expression.returnedExpression?.generateExpression())
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression {
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
@@ -97,17 +103,17 @@ class IrExpressionGenerator(
}
}
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Nothing?): IrExpression {
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Nothing?): IrStatement {
if (expression.entries.size == 1 && expression.entries[0] is KtLiteralStringTemplateEntry) {
return expression.entries[0].generate()
}
val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression))
expression.entries.forEach { irStringTemplate.addChildExpression(it.generate()) }
val irStringTemplate = IrStringConcatenationExpressionImpl(expression.startOffset, expression.endOffset, getType(expression))
expression.entries.forEach { irStringTemplate.addArgument(it.generateExpression()) }
return irStringTemplate
}
override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?): IrExpression =
override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?): IrStatement =
IrLiteralExpressionImpl.string(entry.startOffset, entry.endOffset, context.builtIns.stringType, entry.text)
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Nothing?): IrExpression {
@@ -122,25 +128,25 @@ class IrExpressionGenerator(
return when (descriptor) {
is ClassDescriptor ->
if (DescriptorUtils.isObject(descriptor))
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), descriptor)
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), descriptor)
else if (DescriptorUtils.isEnumEntry(descriptor))
IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), descriptor)
IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), descriptor)
else
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression),
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, getType(expression),
descriptor.companionObjectDescriptor ?: error("Class value without companion object: $descriptor"))
is PropertyDescriptor -> {
irCallGenerator.generateCall(expression, resolvedCall)
}
is VariableDescriptor ->
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), descriptor)
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), descriptor)
else ->
IrDummyExpression(expression.startOffset, expression.endOffset, getTypeOrFail(expression),
IrDummyExpression(expression.startOffset, expression.endOffset, getType(expression),
expression.getReferencedName() +
": ${descriptor?.name} ${descriptor?.javaClass?.simpleName}")
}
}
override fun visitCallExpression(expression: KtCallExpression, data: Nothing?): IrExpression {
override fun visitCallExpression(expression: KtCallExpression, data: Nothing?): IrStatement {
val resolvedCall = getResolvedCall(expression) ?: TODO("No resolved call for call expression")
if (resolvedCall is VariableAsFunctionResolvedCall) {
@@ -150,20 +156,20 @@ class IrExpressionGenerator(
return irCallGenerator.generateCall(expression, resolvedCall)
}
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Nothing?): IrExpression =
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Nothing?): IrStatement =
expression.selectorExpression!!.accept(this, data)
override fun visitSafeQualifiedExpression(expression: KtSafeQualifiedExpression, data: Nothing?): IrExpression =
override fun visitSafeQualifiedExpression(expression: KtSafeQualifiedExpression, data: Nothing?): IrStatement =
expression.selectorExpression!!.accept(this, data)
override fun visitThisExpression(expression: KtThisExpression, data: Nothing?): IrExpression {
val referenceTarget = getOrFail(BindingContext.REFERENCE_TARGET, expression.instanceReference) { "No reference target for this" }
return when (referenceTarget) {
is ClassDescriptor ->
IrThisExpressionImpl(expression.startOffset, expression.endOffset, getTypeOrFail(expression), referenceTarget)
IrThisExpressionImpl(expression.startOffset, expression.endOffset, getType(expression), referenceTarget)
is CallableDescriptor ->
IrGetExtensionReceiverExpressionImpl(
expression.startOffset, expression.endOffset, getTypeOrFail(expression),
expression.startOffset, expression.endOffset, getType(expression),
referenceTarget.extensionReceiverParameter!!
)
else ->
@@ -21,10 +21,47 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrElement {
val startOffset: Int
val endOffset: Int
val parent: IrElement?
val slot: Int
fun setTreeLocation(newParent: IrElement?, newSlot: Int)
fun getChild(slot: Int): IrElement?
fun replaceChild(slot: Int, newChild: IrElement)
fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R
fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D): Unit
}
abstract class IrElementBase(override val startOffset: Int, override val endOffset: Int) : IrElement
interface IrStatement : IrElement
abstract class IrElementBase(override val startOffset: Int, override val endOffset: Int) : IrElement {
override var parent: IrElement? = null
override var slot: Int = DETACHED_SLOT
override fun setTreeLocation(newParent: IrElement?, newSlot: Int) {
parent = newParent
slot = newSlot
}
}
fun IrElement?.detach() {
this?.setTreeLocation(null, DETACHED_SLOT)
}
fun IrElement.replaceWith(otherElement: IrElement) {
parent?.replaceChild(slot, otherElement)
}
fun IrElement.assertChild(child: IrElement) {
assert(getChild(child.slot) == child) { "$this: Invalid child: $child" }
}
fun IrElement.assertDetached() {
assert(parent == null && slot == DETACHED_SLOT) { "$this: should be detached" }
}
fun IrElement.throwNoSuchSlot(slot: Int): Nothing =
throw AssertionError("$this: no such slot $slot")
inline fun <reified T : IrElement> IrElement.assertCast(): T =
if (this is T) this else throw AssertionError("Expected ${T::class.simpleName}: $this")
@@ -16,10 +16,13 @@
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
const val ARGUMENT1_INDEX = 1
const val DISPATCH_RECEIVER_INDEX = -1
const val EXTENSION_RECEIVER_INDEX = -2
const val CHILD_DECLARATION_SLOT = 0
const val DETACHED_SLOT = Int.MIN_VALUE
const val CHILD_EXPRESSION_SLOT = 0
const val ARGUMENT0_SLOT = 0
const val ARGUMENT1_SLOT = 1
const val DISPATCH_RECEIVER_SLOT = -1
const val EXTENSION_RECEIVER_SLOT = -2
const val FUNCTION_BODY_SLOT = 0
const val MODULE_SLOT = 0
const val INITIALIZER_SLOT = 0
@@ -17,13 +17,21 @@
package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import java.util.*
interface IrClassElement : IrElement
interface IrClass : IrDeclaration {
override val declarationKind: IrDeclarationKind
get() = IrDeclarationKind.CLASS
interface IrClass : IrCompoundDeclaration, IrMemberDeclaration {
override val descriptor: ClassDescriptor
override val declarationKind: IrDeclarationKind
get() = IrDeclarationKind.MODULE
val children: List<IrClassElement>
fun addChild(child: IrClassElement)
}
class IrClassImpl(
@@ -31,7 +39,30 @@ class IrClassImpl(
endOffset: Int,
originKind: IrDeclarationOriginKind,
override val descriptor: ClassDescriptor
) : IrCompoundMemberDeclarationBase(startOffset, endOffset, originKind), IrClass {
) : IrDeclarationBase(startOffset, endOffset, originKind), IrClass {
override val children: MutableList<IrClassElement> = ArrayList()
override fun addChild(child: IrClassElement) {
child.assertDetached()
child.setTreeLocation(this, children.size)
children.add(child)
}
override fun getChild(slot: Int): IrElement? =
children.getOrNull(slot)
override fun replaceChild(slot: Int, newChild: IrElement) {
newChild.assertDetached()
children.getOrNull(slot)?.detach() ?: throwNoSuchSlot(slot)
children[slot] = newChild.assertCast()
newChild.setTreeLocation(this, slot)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitClass(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
children.forEach { it.accept(visitor, data) }
}
}
@@ -1,152 +0,0 @@
/*
* 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.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 {
fun getChildDeclaration(index: Int): IrMemberDeclaration?
fun replaceChildDeclaration(oldChild: IrMemberDeclaration, newChild: IrMemberDeclaration)
}
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, IrDeclarationOwnerN
interface IrMemberDeclaration : IrDeclaration {
override var parent: IrDeclarationOwner?
fun setTreeLocation(parent: IrDeclarationOwner?, index: Int)
}
abstract class IrDeclarationOwnerNBase(
startOffset: Int,
endOffset: Int
) : IrElementBase(startOffset, endOffset), IrDeclarationOwnerN {
protected val childDeclarations: MutableList<IrMemberDeclaration> = ArrayList()
override val childrenCount: Int
get() = childDeclarations.size
override fun getChildDeclaration(index: Int): IrMemberDeclaration? =
childDeclarations.getOrNull(index)
override fun addChildDeclaration(child: IrMemberDeclaration) {
child.setTreeLocation(this, childDeclarations.size)
childDeclarations.add(child)
}
override fun removeChildDeclaration(child: IrMemberDeclaration) {
validateChild(child)
childDeclarations.removeAt(child.indexInParent)
for (i in child.indexInParent..childDeclarations.size - 1) {
childDeclarations[i].setTreeLocation(this, i)
}
child.detach()
}
override fun removeAllChildDeclarations() {
childDeclarations.forEach { it.detach() }
childDeclarations.clear()
}
override fun replaceChildDeclaration(oldChild: IrMemberDeclaration, newChild: IrMemberDeclaration) {
validateChild(oldChild)
childDeclarations[oldChild.indexInParent] = newChild
newChild.setTreeLocation(this, oldChild.indexInParent)
oldChild.detach()
}
override fun <D> acceptChildDeclarations(visitor: IrElementVisitor<Unit, D>, data: D) {
childDeclarations.forEach { it.accept(visitor, data) }
}
}
// TODO synchronization?
abstract class IrCompoundDeclarationBase(
startOffset: Int,
endOffset: Int,
override val originKind: IrDeclarationOriginKind
) : IrDeclarationOwnerNBase(startOffset, endOffset), IrCompoundDeclaration {
override var indexInParent: Int = IrDeclaration.DETACHED_INDEX
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
acceptChildDeclarations(visitor, data)
}
}
abstract class IrCompoundMemberDeclarationBase(
startOffset: Int,
endOffset: Int,
originKind: IrDeclarationOriginKind
) : IrCompoundDeclarationBase(startOffset, endOffset, originKind), IrMemberDeclaration {
private var parentImpl: IrDeclarationOwner? = null
override var parent: IrDeclarationOwner?
get() = parentImpl!!
set(newParent) {
parentImpl = newParent
}
override fun setTreeLocation(parent: IrDeclarationOwner?, index: Int) {
this.parentImpl = parent
this.indexInParent = index
}
}
abstract class IrMemberDeclarationBase(
startOffset: Int,
endOffset: Int,
originKind: IrDeclarationOriginKind
) : IrDeclarationBase(startOffset, endOffset, originKind), IrMemberDeclaration {
private var parentImpl: IrDeclarationOwner? = null
override var parent: IrDeclarationOwner?
get() = parentImpl!!
set(newParent) {
parentImpl = newParent
}
override fun setTreeLocation(parent: IrDeclarationOwner?, index: Int) {
this.parentImpl = parent
this.indexInParent = index
}
}
fun IrMemberDeclaration.detach() {
setTreeLocation(null, IrDeclaration.DETACHED_INDEX)
}
fun IrDeclarationOwner.validateChild(child: IrMemberDeclaration) {
assert(child.parent == this && getChildDeclaration(child.indexInParent) == child) { "Invalid child: $child" }
}
@@ -17,21 +17,13 @@
package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrElementBase
import org.jetbrains.kotlin.ir.IrStatement
interface IrDeclaration : IrElement {
override val parent: IrDeclarationOwner?
val indexInParent: Int
interface IrDeclaration : IrStatement, IrClassElement {
val descriptor: DeclarationDescriptor?
val declarationKind: IrDeclarationKind
val originKind: IrDeclarationOriginKind
companion object {
const val DETACHED_INDEX = Int.MIN_VALUE
}
}
enum class IrDeclarationKind {
@@ -41,7 +33,7 @@ enum class IrDeclarationKind {
PROPERTY_GETTER,
PROPERTY_SETTER,
PROPERTY,
LOCAL_VARIABLE,
VARIABLE,
CLASS
}
@@ -54,6 +46,4 @@ abstract class IrDeclarationBase(
startOffset: Int,
endOffset: Int,
override val originKind: IrDeclarationOriginKind
) : IrElementBase(startOffset, endOffset), IrDeclaration {
override var indexInParent: Int = IrDeclaration.DETACHED_INDEX
}
) : IrElementBase(startOffset, endOffset), IrDeclaration
@@ -17,28 +17,48 @@
package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.ir.SourceLocationManager
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import java.util.*
interface IrFile : IrCompoundDeclaration {
interface IrFile : IrElement {
val name: String
val fileEntry: SourceLocationManager.FileEntry
val module: IrModule
override val descriptor: PackageFragmentDescriptor
val packageFragmentDescriptor: PackageFragmentDescriptor
val declarations: List<IrDeclaration>
override val parent: Nothing? get() = null
override val declarationKind: IrDeclarationKind
get() = IrDeclarationKind.FILE
fun addDeclaration(declaration: IrDeclaration)
}
class IrFileImpl(
override val fileEntry: SourceLocationManager.FileEntry,
override val name: String,
override val descriptor: PackageFragmentDescriptor
) : IrCompoundDeclarationBase(0, fileEntry.maxOffset, IrDeclarationOriginKind.DEFINED), IrFile {
override lateinit var module: IrModule
override val packageFragmentDescriptor: PackageFragmentDescriptor
) : IrElementBase(0, fileEntry.maxOffset), IrFile {
override val declarations: MutableList<IrDeclaration> = ArrayList()
override fun addDeclaration(declaration: IrDeclaration) {
declaration.assertDetached()
declaration.setTreeLocation(this, declarations.size)
declarations.add(declaration)
}
override fun getChild(slot: Int): IrElement? =
declarations.getOrNull(slot)
override fun replaceChild(slot: Int, newChild: IrElement) {
newChild.assertDetached()
declarations.getOrNull(slot)?.detach() ?: throwNoSuchSlot(slot)
declarations[slot] = newChild.assertCast()
newChild.setTreeLocation(this, slot)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitFile(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
declarations.forEach { it.accept(visitor, data) }
}
}
@@ -17,10 +17,11 @@
package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrFunction : IrMemberDeclaration {
interface IrFunction : IrDeclaration {
override val descriptor: FunctionDescriptor
val body: IrBody
@@ -31,8 +32,36 @@ interface IrFunction : IrMemberDeclaration {
abstract class IrFunctionBase(
startOffset: Int,
endOffset: Int,
originKind: IrDeclarationOriginKind
) : IrMemberDeclarationBase(startOffset, endOffset, originKind), IrFunction {
originKind: IrDeclarationOriginKind,
body: IrBody? = null
) : IrDeclarationBase(startOffset, endOffset, originKind), IrFunction {
init {
body?.setTreeLocation(this, FUNCTION_BODY_SLOT)
}
private var bodyImpl: IrBody? = body
override var body: IrBody
get() = bodyImpl!!
set(newValue) {
newValue.assertDetached()
bodyImpl?.detach()
bodyImpl = newValue
newValue.setTreeLocation(this, FUNCTION_BODY_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
FUNCTION_BODY_SLOT -> body
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
FUNCTION_BODY_SLOT -> body = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
body.accept(visitor, data)
}
@@ -43,12 +72,8 @@ class IrFunctionImpl(
endOffset: Int,
originKind: IrDeclarationOriginKind,
override val descriptor: FunctionDescriptor,
override val body: IrBody
) : IrFunctionBase(startOffset, endOffset, originKind) {
init {
body.parent = this
}
body: IrBody
) : IrFunctionBase(startOffset, endOffset, originKind, body) {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitFunction(this, data)
}
@@ -17,41 +17,44 @@
package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import java.util.*
interface IrModule : IrDeclaration {
override val descriptor: ModuleDescriptor
interface IrModule : IrElement {
override val startOffset: Int get() = UNDEFINED_OFFSET
override val endOffset: Int get() = UNDEFINED_OFFSET
override val parent: Nothing? get() = null
override val indexInParent: Int get() = MODULE_INDEX
override val parent: IrElement? get() = null
override val slot: Int get() = MODULE_SLOT
override fun setTreeLocation(newParent: IrElement?, newSlot: Int) {
throw AssertionError("IrModule can't have a parent element")
}
override val declarationKind: IrDeclarationKind
get() = IrDeclarationKind.MODULE
val descriptor: ModuleDescriptor
val files: List<IrFile>
companion object {
const val MODULE_INDEX = -1
}
fun addFile(file: IrFile)
}
class IrModuleImpl(
override val descriptor: ModuleDescriptor
) : IrModule {
override val originKind: IrDeclarationOriginKind
get() = IrDeclarationOriginKind.DEFINED
override val files: MutableList<IrFile> = ArrayList()
fun addFile(file: IrFileImpl) {
override fun addFile(file: IrFile) {
file.assertDetached()
file.setTreeLocation(this, files.size)
files.add(file)
file.module = this
}
override fun getChild(slot: Int): IrElement? =
files.getOrNull(slot)
override fun replaceChild(slot: Int, newChild: IrElement) {
newChild.assertDetached()
files.getOrNull(slot)?.detach() ?: throwNoSuchSlot(slot)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
@@ -17,10 +17,11 @@
package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrProperty : IrMemberDeclaration {
interface IrProperty : IrDeclaration {
override val descriptor: PropertyDescriptor
var getter: IrPropertyGetter?
var setter: IrPropertySetter?
@@ -32,11 +33,11 @@ interface IrProperty : IrMemberDeclaration {
}
interface IrSimpleProperty : IrProperty {
val valueInitializer: IrBody?
var valueInitializer: IrBody?
}
interface IrDelegatedProperty : IrProperty {
val delegateInitializer: IrBody
var delegateInitializer: IrBody
}
// TODO synchronization?
@@ -45,15 +46,17 @@ abstract class IrPropertyBase(
endOffset: Int,
originKind: IrDeclarationOriginKind,
override val descriptor: PropertyDescriptor
) : IrMemberDeclarationBase(startOffset, endOffset, originKind), IrProperty {
) : IrDeclarationBase(startOffset, endOffset, originKind), IrProperty {
override var getter: IrPropertyGetter? = null
set(newGetter) {
newGetter?.run { assert(property == null) { "$newGetter: should not have a property" } }
newGetter?.property = this
field = newGetter
}
override var setter: IrPropertySetter? = null
set(newSetter) {
newSetter?.run { assert(property == null) { "$newSetter: should not have a property" } }
newSetter?.property = this
field = newSetter
}
@@ -69,10 +72,27 @@ class IrSimplePropertyImpl(
endOffset: Int,
originKind: IrDeclarationOriginKind,
descriptor: PropertyDescriptor,
override val valueInitializer: IrBody?
valueInitializer: IrBody? = null
) : IrPropertyBase(startOffset, endOffset, originKind, descriptor), IrSimpleProperty {
init {
valueInitializer?.parent = this
override var valueInitializer: IrBody? = valueInitializer
set(value) {
value?.assertDetached()
field?.detach()
field = value
value?.setTreeLocation(this, INITIALIZER_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
INITIALIZER_SLOT -> valueInitializer
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
INITIALIZER_SLOT -> valueInitializer = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
@@ -88,8 +108,29 @@ class IrDelegatedPropertyImpl(
endOffset: Int,
originKind: IrDeclarationOriginKind,
descriptor: PropertyDescriptor,
override val delegateInitializer: IrBody
delegateInitializer: IrBody
) : IrPropertyBase(startOffset, endOffset, originKind, descriptor), IrDelegatedProperty {
override var delegateInitializer: IrBody = delegateInitializer
set(value) {
value.assertDetached()
field.detach()
field = value
value.setTreeLocation(this, INITIALIZER_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
INITIALIZER_SLOT -> delegateInitializer
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
INITIALIZER_SLOT -> delegateInitializer = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitDelegatedProperty(this, data)
@@ -45,12 +45,8 @@ abstract class IrPropertyAccessorBase(
startOffset: Int,
endOffset: Int,
originKind: IrDeclarationOriginKind,
override val body: IrBody
) : IrFunctionBase(startOffset, endOffset, originKind), IrPropertyAccessor {
init {
body.parent = this
}
body: IrBody
) : IrFunctionBase(startOffset, endOffset, originKind, body), IrPropertyAccessor {
override var property: IrProperty? = null
}
@@ -17,38 +17,44 @@
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.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrLocalVariable : IrMemberDeclaration, IrExpressionOwner {
interface IrVariable : IrDeclaration {
override val descriptor: VariableDescriptor
override val declarationKind: IrDeclarationKind
get() = IrDeclarationKind.LOCAL_VARIABLE
get() = IrDeclarationKind.VARIABLE
var initializerExpression: IrExpression?
var initializer: IrExpression?
}
class IrLocalVariableImpl(
class IrVariableImpl(
startOffset: Int,
endOffset: Int,
originKind: IrDeclarationOriginKind,
override val descriptor: VariableDescriptor
) : IrMemberDeclarationBase(startOffset, endOffset, originKind), IrLocalVariable {
override var initializerExpression: IrExpression? = null
) : IrDeclarationBase(startOffset, endOffset, originKind), IrVariable {
override var initializer: IrExpression? = null
set(value) {
value?.assertDetached()
field?.detach()
field = value
value?.setTreeLocation(this, CHILD_EXPRESSION_INDEX)
value?.setTreeLocation(this, INITIALIZER_SLOT)
}
override fun getChildExpression(index: Int): IrExpression? =
if (index == CHILD_EXPRESSION_INDEX) initializerExpression else null
override fun getChild(slot: Int): IrElement? =
when (slot) {
INITIALIZER_SLOT -> initializer
else -> null
}
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
initializerExpression = newChild
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
INITIALIZER_SLOT -> initializer = newChild.assertCast<IrExpression>()
else -> throwNoSuchSlot(slot)
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
@@ -56,10 +62,6 @@ class IrLocalVariableImpl(
}
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)
initializer?.accept(visitor, data)
}
}
@@ -16,27 +16,51 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.assertCast
import org.jetbrains.kotlin.ir.assertDetached
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
interface IrBlockExpression : IrCompoundExpressionN {
interface IrBlockExpression : IrExpression {
val hasResult: Boolean
}
val isDesugared: Boolean
fun IrBlockExpression.getResultExpression() =
if (hasResult) childExpressions.lastOrNull() else null
val statements: List<IrStatement>
fun addStatement(statement: IrStatement)
}
class IrBlockExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
override val hasResult: Boolean
) : IrCompoundExpressionNBase(startOffset, endOffset, type), IrBlockExpression {
override val hasResult: Boolean,
override val isDesugared: Boolean
) : IrExpressionBase(startOffset, endOffset, type), IrBlockExpression {
override val statements: MutableList<IrStatement> = ArrayList()
override fun addStatement(statement: IrStatement) {
statement.assertDetached()
statement.setTreeLocation(this, statements.size)
statements.add(statement)
}
override fun getChild(slot: Int): IrElement? =
statements.getOrNull(slot)
override fun replaceChild(slot: Int, newChild: IrElement) {
if (0 <= slot && slot < statements.size) {
statements[slot] = newChild.assertCast()
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitBlockExpression(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
childExpressions.forEach { it.accept(visitor, data) }
statements.forEach { it.accept(visitor, data) }
}
}
@@ -16,50 +16,53 @@
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.IrDeclarationOwnerNBase
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrBody : IrElement {
override var parent: IrDeclaration
interface IrBody : IrElement
interface IrExpressionBody : IrBody {
var expression: IrExpression
}
interface IrExpressionBody : IrBody, IrExpressionOwner1
// TODO IrExpressionBodyImpl vs IrCompoundExpression1Impl: extract common base class?
class IrExpressionBodyImpl(
startOffset: Int,
endOffset: Int
) : IrElementBase(startOffset, endOffset), IrExpressionBody {
override lateinit var parent: IrDeclaration
constructor(
startOffset: Int,
endOffset: Int,
expression: IrExpression
) : this(startOffset, endOffset) {
this.expression = expression
}
override var argument: IrExpression? = null
set(newExpression) {
field?.detach()
field = newExpression
newExpression?.setTreeLocation(this, CHILD_EXPRESSION_INDEX)
private var expressionImpl: IrExpression? = null
override var expression: IrExpression
get() = expressionImpl!!
set(newValue) {
newValue.assertDetached()
expressionImpl?.detach()
expressionImpl = newValue
newValue.setTreeLocation(this, CHILD_EXPRESSION_SLOT)
}
override fun getChildExpression(index: Int): IrExpression? =
if (index == CHILD_EXPRESSION_INDEX) argument else null
override fun getChild(slot: Int): IrElement? =
when (slot) {
CHILD_EXPRESSION_SLOT -> expression
else -> null
}
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
argument = newChild
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
CHILD_EXPRESSION_SLOT -> expression = newChild.assertCast()
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitExpressionBody(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) {
argument?.accept(visitor, data)
expression.accept(visitor, data)
}
}
@@ -18,21 +18,18 @@ package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.DISPATCH_RECEIVER_INDEX
import org.jetbrains.kotlin.ir.EXTENSION_RECEIVER_INDEX
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrCallExpression : IrMemberAccessExpression, IrCompoundExpression {
interface IrCallExpression : IrMemberAccessExpression {
val superQualifier: ClassDescriptor?
val operator: IrOperator?
override val descriptor: CallableDescriptor
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 getArgument(index: Int): IrExpression?
fun putArgument(index: Int, valueArgument: IrExpression?)
fun removeArgument(index: Int)
}
class IrCallExpressionImpl(
@@ -42,63 +39,45 @@ class IrCallExpressionImpl(
override val descriptor: CallableDescriptor,
isSafe: Boolean,
override val operator: IrOperator?,
override val superQualifier: ClassDescriptor?
override val superQualifier: ClassDescriptor? = null
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrCallExpression {
private val argumentsByParameterIndex =
kotlin.arrayOfNulls<IrExpression>(descriptor.valueParameters.size)
arrayOfNulls<IrExpression>(descriptor.valueParameters.size)
override fun getValueArgument(index: Int): IrExpression? =
override fun getArgument(index: Int): IrExpression? =
argumentsByParameterIndex[index]
override fun putValueArgument(index: Int, valueArgument: IrExpression?) {
override fun putArgument(index: Int, valueArgument: IrExpression?) {
if (index >= argumentsByParameterIndex.size) throw AssertionError("$this: No such argument slot: $index")
valueArgument?.assertDetached()
argumentsByParameterIndex[index]?.detach()
argumentsByParameterIndex[index] = valueArgument
valueArgument?.setTreeLocation(this, index)
}
override fun removeValueArgument(index: Int) {
override fun removeArgument(index: Int) {
argumentsByParameterIndex[index]?.detach()
argumentsByParameterIndex[index] = null
}
override fun getChildExpression(index: Int): IrExpression? =
when (index) {
DISPATCH_RECEIVER_INDEX ->
dispatchReceiver
EXTENSION_RECEIVER_INDEX ->
extensionReceiver
else ->
argumentsByParameterIndex.getOrNull(index)
}
override fun getChild(slot: Int): IrElement? =
if (0 <= slot)
argumentsByParameterIndex.getOrNull(slot)
else
super.getChild(slot)
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
when (oldChild.index) {
DISPATCH_RECEIVER_INDEX ->
dispatchReceiver = newChild
EXTENSION_RECEIVER_INDEX ->
extensionReceiver = newChild
else ->
putValueArgument(oldChild.index, newChild)
}
}
override fun <D> acceptValueArguments(visitor: IrElementVisitor<Unit, D>, data: D) {
for (valueArgument in argumentsByParameterIndex) {
valueArgument?.let { it.accept(visitor, data) }
}
}
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
dispatchReceiver?.accept(visitor, data)
extensionReceiver?.accept(visitor, data)
acceptValueArguments(visitor, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
acceptChildExpressions(visitor, data)
override fun replaceChild(slot: Int, newChild: IrElement) {
if (0 <= slot)
putArgument(slot, newChild.assertCast())
else
super.replaceChild(slot, newChild)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitCallExpression(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
super.acceptChildren(visitor, data)
argumentsByParameterIndex.forEach { it?.accept(visitor, data) }
}
}
@@ -1,145 +0,0 @@
/*
* 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.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.*
interface IrCompoundExpression : IrExpression, IrExpressionOwner
interface IrCompoundExpression1 : IrCompoundExpression, IrExpressionOwner1
interface IrCompoundExpression2 : IrCompoundExpression, IrExpressionOwner2
interface IrCompoundExpressionN : IrCompoundExpression, IrExpressionOwnerN
abstract class IrCompoundExpressionNBase(
startOffset: Int,
endOffset: Int,
override val type: KotlinType?
) : IrExpressionBase(startOffset, endOffset, type), IrCompoundExpressionN {
override val childExpressions: MutableList<IrExpression> = ArrayList()
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
childExpressions.forEach { it.accept(visitor, data) }
}
override fun addChildExpression(child: IrExpression) {
child.setTreeLocation(this, childExpressions.size)
childExpressions.add(child)
}
override fun getChildExpression(index: Int): IrExpression? =
childExpressions.getOrNull(index)
override fun removeChildExpression(child: IrExpression) {
validateChild(child)
childExpressions.removeAt(child.index)
for (i in child.index ..childExpressions.size - 1) {
childExpressions[i].setTreeLocation(parent, i)
}
child.detach()
}
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
childExpressions[oldChild.index] = newChild
newChild.setTreeLocation(this, oldChild.index)
oldChild.detach()
}
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
childExpressions.forEach { it.accept(visitor, data) }
}
}
// TODO IrExpressionBodyImpl vs IrCompoundExpression1Impl: extract common base class?
abstract class IrCompoundExpression1Base(
startOffset: Int,
endOffset: Int,
override val type: KotlinType?
) : IrExpressionBase(startOffset, endOffset, type), IrCompoundExpression1 {
override var argument: IrExpression? = null
set(newExpression) {
field?.detach()
field = newExpression
newExpression?.setTreeLocation(this, ARGUMENT0_INDEX)
}
override fun getChildExpression(index: Int): IrExpression? =
if (index == ARGUMENT0_INDEX) argument else null
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
argument = newChild
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
acceptChildExpressions(visitor, data)
}
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
argument?.accept(visitor, data)
}
}
abstract class IrCompoundExpression2Base(
startOffset: Int,
endOffset: Int,
override val type: KotlinType?
) : IrExpressionBase(startOffset, endOffset, type), IrCompoundExpression2 {
override var argument0: IrExpression? = null
set(newExpression) {
field?.detach()
field = newExpression
newExpression?.setTreeLocation(this, ARGUMENT0_INDEX)
}
override var argument1: IrExpression? = null
set(newExpression) {
field?.detach()
field = newExpression
newExpression?.setTreeLocation(this, ARGUMENT1_INDEX)
}
override fun getChildExpression(index: Int): IrExpression? =
when (index) {
ARGUMENT0_INDEX -> argument0
ARGUMENT1_INDEX -> argument1
else -> null
}
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
when (oldChild.index) {
ARGUMENT0_INDEX -> argument0 = newChild
ARGUMENT1_INDEX -> argument1 = newChild
}
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
acceptChildExpressions(visitor, data)
}
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
argument0?.accept(visitor, data)
argument1?.accept(visitor, data)
}
}
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.throwNoSuchSlot
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -39,14 +41,31 @@ abstract class IrDeclarationReferenceBase<out D : DeclarationDescriptor>(
endOffset: Int,
type: KotlinType?,
override val descriptor: D
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrDeclarationReference
) : IrExpressionBase(startOffset, endOffset, type), IrDeclarationReference
abstract class IrTerminalDeclarationReferenceBase<out D : DeclarationDescriptor>(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
descriptor: D
) : IrDeclarationReferenceBase<D>(startOffset, endOffset, type, descriptor) {
override fun getChild(slot: Int): IrElement? = null
override fun replaceChild(slot: Int, newChild: IrElement) {
throwNoSuchSlot(slot)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
// No children
}
}
class IrGetObjectValueExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
descriptor: ClassDescriptor
) : IrDeclarationReferenceBase<ClassDescriptor>(startOffset, endOffset, type, descriptor), IrGetObjectValueExpression {
) : IrTerminalDeclarationReferenceBase<ClassDescriptor>(startOffset, endOffset, type, descriptor), IrGetObjectValueExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetObjectValue(this, data)
}
@@ -56,7 +75,7 @@ class IrGetEnumValueExpressionImpl(
endOffset: Int,
type: KotlinType?,
descriptor: ClassDescriptor
) : IrDeclarationReferenceBase<ClassDescriptor>(startOffset, endOffset, type, descriptor), IrGetEnumValueExpression {
) : IrTerminalDeclarationReferenceBase<ClassDescriptor>(startOffset, endOffset, type, descriptor), IrGetEnumValueExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitGetEnumValue(this, data)
}
@@ -24,7 +24,7 @@ class IrDummyExpression(
endOffset: Int,
type: KotlinType?,
val description: String
) : IrExpressionBase(startOffset, endOffset, type) {
) : IrTerminalExpressionBase(startOffset, endOffset, type) {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitDummyExpression(this, data)
@@ -16,48 +16,34 @@
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.IrStatement
import org.jetbrains.kotlin.ir.throwNoSuchSlot
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrExpression : IrElement {
override val parent: IrExpressionOwner?
val index: Int
interface IrExpression : IrStatement {
val type: KotlinType?
fun setTreeLocation(parent: IrExpressionOwner?, index: Int)
}
fun IrExpression.detach() {
setTreeLocation(null, DETACHED_INDEX)
}
fun IrExpressionOwner.validateChild(child: IrExpression) {
assert(child.parent == this && getChildExpression(child.index) == child) { "Inconsistent child: $child" }
}
abstract class IrExpressionBase(
startOffset: Int,
endOffset: Int,
override val type: KotlinType?
) : IrElementBase(startOffset, endOffset), IrExpression {
override var parent: IrExpressionOwner? = null
override var index: Int = DETACHED_INDEX
override fun setTreeLocation(parent: IrExpressionOwner?, index: Int) {
this.parent = parent
this.index = index
}
}
) : IrElementBase(startOffset, endOffset), IrExpression
abstract class IrTerminalExpressionBase(
startOffset: Int,
endOffset: Int,
type: KotlinType?
) : IrExpressionBase(startOffset, endOffset, type) {
override fun getChild(slot: Int): IrElement? = null
override fun replaceChild(slot: Int, newChild: IrElement) {
throwNoSuchSlot(slot)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
// No children
}
@@ -1,41 +0,0 @@
/*
* 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.IrElement
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrExpressionOwner : IrElement {
fun getChildExpression(index: Int): IrExpression?
fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression)
fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D)
}
interface IrExpressionOwner1 : IrExpressionOwner {
var argument: IrExpression?
}
interface IrExpressionOwner2 : IrExpressionOwner {
var argument0: IrExpression?
var argument1: IrExpression?
}
interface IrExpressionOwnerN : IrExpressionOwner {
val childExpressions: List<IrExpression>
fun addChildExpression(child: IrExpression)
fun removeChildExpression(child: IrExpression)
}
@@ -34,7 +34,7 @@ class IrGetVariableExpressionImpl(
endOffset: Int,
type: KotlinType?,
descriptor: VariableDescriptor
) : IrDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, type, descriptor), IrGetVariableExpression {
) : IrTerminalDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, type, descriptor), IrGetVariableExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetVariable(this, data)
}
@@ -43,8 +43,8 @@ class IrGetExtensionReceiverExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
override val descriptor: CallableDescriptor
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrGetExtensionReceiverExpression {
descriptor: CallableDescriptor
) : IrTerminalDeclarationReferenceBase<CallableDescriptor>(startOffset, endOffset, type, descriptor), IrGetExtensionReceiverExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetExtensionReceiver(this, data)
}
@@ -1,70 +0,0 @@
/*
* 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
) : IrLocalDeclarationExpressionBase(startOffset, endOffset, null), IrLocalVariableDeclarationExpression {
constructor(startOffset: Int, endOffset: Int, childDeclaration: IrLocalVariable) : this(startOffset, endOffset) {
this.childDeclaration = childDeclaration
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitLocalVariableDeclarationExpression(this, data)
}
@@ -16,11 +16,11 @@
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.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrMemberAccessExpression : IrDeclarationReference, IrExpressionOwner {
interface IrMemberAccessExpression : IrDeclarationReference {
var dispatchReceiver: IrExpression?
var extensionReceiver: IrExpression?
val isSafe: Boolean
@@ -34,15 +34,37 @@ abstract class IrMemberAccessExpressionBase(
) : IrExpressionBase(startOffset, endOffset, type), IrMemberAccessExpression {
override var dispatchReceiver: IrExpression? = null
set(newReceiver) {
newReceiver?.assertDetached()
field?.detach()
field = newReceiver
newReceiver?.setTreeLocation(this, DISPATCH_RECEIVER_INDEX)
newReceiver?.setTreeLocation(this, DISPATCH_RECEIVER_SLOT)
}
override var extensionReceiver: IrExpression? = null
set(newReceiver) {
newReceiver?.assertDetached()
field?.detach()
field = newReceiver
newReceiver?.setTreeLocation(this, EXTENSION_RECEIVER_INDEX)
newReceiver?.setTreeLocation(this, EXTENSION_RECEIVER_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
DISPATCH_RECEIVER_SLOT -> dispatchReceiver
EXTENSION_RECEIVER_SLOT -> extensionReceiver
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
DISPATCH_RECEIVER_SLOT -> dispatchReceiver = newChild.assertCast()
EXTENSION_RECEIVER_SLOT -> extensionReceiver = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
dispatchReceiver?.accept(visitor, data)
extensionReceiver?.accept(visitor, data)
}
}
@@ -30,7 +30,8 @@ enum class IrOperator {
RANGE,
PLUS, MINUS, MUL, DIV, MOD,
EQ,
PLUSEQ, MINUSEQ, MULEQ, DIVEQ, MODEQ;
PLUSEQ, MINUSEQ, MULEQ, DIVEQ, MODEQ,
DESTRUCTURING;
}
private val CAO_START = IrOperator.PLUSEQ.ordinal
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -25,9 +26,14 @@ interface IrOperatorExpression : IrExpression {
val relatedDescriptor: FunctionDescriptor?
}
interface IrUnaryOperatorExpression : IrOperatorExpression, IrCompoundExpression1
interface IrUnaryOperatorExpression : IrOperatorExpression {
var argument: IrExpression
}
interface IrBinaryOperatorExpression : IrOperatorExpression, IrCompoundExpression2
interface IrBinaryOperatorExpression : IrOperatorExpression {
var argument0: IrExpression
var argument1: IrExpression
}
class IrUnaryOperatorExpressionImpl(
startOffset: Int,
@@ -35,10 +41,48 @@ class IrUnaryOperatorExpressionImpl(
type: KotlinType?,
override val operator: IrOperator,
override val relatedDescriptor: FunctionDescriptor?
) : IrCompoundExpression1Base(startOffset, endOffset, type), IrUnaryOperatorExpression {
) : IrExpressionBase(startOffset, endOffset, type), IrUnaryOperatorExpression {
constructor(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
operator: IrOperator,
relatedDescriptor: FunctionDescriptor?,
argument: IrExpression
) : this(startOffset, endOffset, type, operator, relatedDescriptor) {
this.argument = argument
}
private var argumentImpl: IrExpression? = null
override var argument: IrExpression
get() = argumentImpl!!
set(value) {
value.assertDetached()
argumentImpl?.detach()
argumentImpl = value
value.setTreeLocation(this, ARGUMENT0_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
ARGUMENT0_SLOT -> argument
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
ARGUMENT0_SLOT -> argument = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitUnaryOperator(this, data)
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
argument.accept(visitor, data)
}
}
class IrBinaryOperatorExpressionImpl(
@@ -47,7 +91,60 @@ class IrBinaryOperatorExpressionImpl(
type: KotlinType?,
override val operator: IrOperator,
override val relatedDescriptor: FunctionDescriptor?
) : IrCompoundExpression2Base(startOffset, endOffset, type), IrBinaryOperatorExpression {
) : IrExpressionBase(startOffset, endOffset, type), IrBinaryOperatorExpression {
constructor(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
operator: IrOperator,
relatedDescriptor: FunctionDescriptor?,
argument0: IrExpression,
argument1: IrExpression
) : this(startOffset, endOffset, type, operator, relatedDescriptor) {
this.argument0 = argument0
this.argument1 = argument1
}
private var argument0Impl: IrExpression? = null
override var argument0: IrExpression
get() = argument0Impl!!
set(value) {
value.assertDetached()
argument0Impl?.detach()
argument0Impl = value
value.setTreeLocation(this, ARGUMENT0_SLOT)
}
private var argument1Impl: IrExpression? = null
override var argument1: IrExpression
get() = argument1Impl!!
set(value) {
value.assertDetached()
argument1Impl?.detach()
argument1Impl = value
value.setTreeLocation(this, ARGUMENT1_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
ARGUMENT0_SLOT -> argument0
ARGUMENT1_SLOT -> argument1
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
ARGUMENT0_SLOT -> argument0 = newChild.assertCast()
ARGUMENT1_SLOT -> argument1 = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitBinaryOperator(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
argument0.acceptChildren(visitor, data)
argument1.acceptChildren(visitor, data)
}
}
@@ -17,9 +17,7 @@
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.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -29,7 +27,9 @@ interface IrPropertyAccessExpression : IrMemberAccessExpression {
interface IrGetPropertyExpression : IrPropertyAccessExpression
interface IrSetPropertyExpression : IrPropertyAccessExpression, IrCompoundExpression1
interface IrSetPropertyExpression : IrPropertyAccessExpression {
var value: IrExpression
}
class IrGetPropertyExpressionImpl(
startOffset: Int,
@@ -38,33 +38,8 @@ class IrGetPropertyExpressionImpl(
isSafe: Boolean,
override val descriptor: PropertyDescriptor
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrGetPropertyExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitGetProperty(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) {
dispatchReceiver?.accept(visitor, data)
extensionReceiver?.accept(visitor, data)
}
override fun getChildExpression(index: Int): IrExpression? =
when (index) {
DISPATCH_RECEIVER_INDEX -> dispatchReceiver
EXTENSION_RECEIVER_INDEX -> extensionReceiver
else -> null
}
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
when (oldChild.index) {
DISPATCH_RECEIVER_INDEX -> dispatchReceiver = newChild
EXTENSION_RECEIVER_INDEX -> extensionReceiver = newChild
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetProperty(this, data)
}
class IrSetPropertyExpressionImpl(
@@ -74,11 +49,25 @@ class IrSetPropertyExpressionImpl(
isSafe: Boolean,
override val descriptor: PropertyDescriptor
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrSetPropertyExpression {
override var argument: IrExpression? = null
constructor(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
isSafe: Boolean,
descriptor: PropertyDescriptor,
value: IrExpression
) : this(startOffset, endOffset, type, isSafe, descriptor) {
this.value = value
}
private var valueImpl: IrExpression? = null
override var value: IrExpression
get() = valueImpl!!
set(value) {
field?.detach()
field = value
value?.setTreeLocation(this, ARGUMENT0_INDEX)
value.assertDetached()
valueImpl?.detach()
valueImpl = value
value.setTreeLocation(this, ARGUMENT0_SLOT)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
@@ -86,29 +75,20 @@ class IrSetPropertyExpressionImpl(
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
acceptChildExpressions(visitor, data)
super.acceptChildren(visitor, data)
value.accept(visitor, data)
}
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
dispatchReceiver?.accept(visitor, data)
extensionReceiver?.accept(visitor, data)
argument?.accept(visitor, data)
}
override fun getChildExpression(index: Int): IrExpression? =
when (index) {
DISPATCH_RECEIVER_INDEX -> dispatchReceiver
EXTENSION_RECEIVER_INDEX -> extensionReceiver
ARGUMENT0_INDEX -> argument
else -> null
override fun getChild(slot: Int): IrElement? =
when (slot) {
ARGUMENT0_SLOT -> value
else -> super.getChild(slot)
}
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
when (oldChild.index) {
DISPATCH_RECEIVER_INDEX -> dispatchReceiver = newChild
EXTENSION_RECEIVER_INDEX -> extensionReceiver = newChild
ARGUMENT0_INDEX -> argument = newChild
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
ARGUMENT0_SLOT -> value = newChild.assertCast()
else -> super.replaceChild(slot, newChild)
}
}
}
@@ -16,17 +16,56 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrReturnExpression : IrCompoundExpression1
interface IrReturnExpression : IrExpression {
var value: IrExpression?
}
class IrReturnExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType?
) : IrCompoundExpression1Base(startOffset, endOffset, type), IrReturnExpression {
) : IrExpressionBase(startOffset, endOffset, type), IrReturnExpression {
constructor(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
value: IrExpression?
) : this(startOffset, endOffset, type) {
this.value = value
}
override var value: IrExpression? = null
set(newValue) {
newValue?.assertDetached()
field?.detach()
field = newValue
newValue?.setTreeLocation(this, CHILD_EXPRESSION_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
CHILD_EXPRESSION_SLOT -> value
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
CHILD_EXPRESSION_SLOT -> value = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitReturnExpression(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
value?.accept(visitor, data)
}
}
@@ -16,16 +16,48 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
interface IrStringConcatenationExpression : IrCompoundExpressionN
interface IrStringConcatenationExpression : IrExpression {
val arguments: List<IrExpression>
fun addArgument(argument: IrExpression)
}
class IrStringConcatenationExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType?
) : IrCompoundExpressionNBase(startOffset, endOffset, type), IrStringConcatenationExpression {
) : IrExpressionBase(startOffset, endOffset, type), IrStringConcatenationExpression {
override val arguments: MutableList<IrExpression> = ArrayList()
override fun addArgument(argument: IrExpression) {
argument.assertDetached()
argument.setTreeLocation(this, arguments.size)
arguments.add(argument)
}
override fun getChild(slot: Int): IrElement? =
arguments.getOrNull(slot)
override fun replaceChild(slot: Int, newChild: IrElement) {
newChild.assertDetached()
if (0 <= slot && slot < arguments.size) {
arguments[slot].detach()
arguments[slot] = newChild.assertCast()
newChild.setTreeLocation(this, slot)
}
else {
throwNoSuchSlot(slot)
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitStringTemplate(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
arguments.forEach { it.accept(visitor, data) }
}
}
@@ -30,7 +30,6 @@ class IrThisExpressionImpl(
type: KotlinType?,
override val classDescriptor: ClassDescriptor
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrThisExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitThisExpression(this, data)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitThisExpression(this, data)
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -27,8 +28,9 @@ enum class IrTypeOperator {
NOT_IS;
}
interface IrTypeOperatorExpression : IrExpression, IrCompoundExpression1 {
interface IrTypeOperatorExpression : IrExpression {
val operator: IrTypeOperator
var argument: IrExpression
val typeOperand: KotlinType
}
@@ -38,8 +40,47 @@ class IrTypeOperatorExpressionImpl(
type: KotlinType?,
override val operator: IrTypeOperator,
override val typeOperand: KotlinType
) : IrCompoundExpression1Base(startOffset, endOffset, type), IrTypeOperatorExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitTypeOperatorExpression(this, data)
) : IrExpressionBase(startOffset, endOffset, type), IrTypeOperatorExpression {
constructor(
startOffset: Int,
endOffset: Int,
type: KotlinType?,
operator: IrTypeOperator,
argument: IrExpression,
typeOperand: KotlinType
) : this(startOffset, endOffset, type, operator, typeOperand) {
this.argument = argument
}
private var argumentImpl: IrExpression? = null
override var argument: IrExpression
get() = argumentImpl!!
set(value) {
value.assertDetached()
argumentImpl?.detach()
argumentImpl = value
value.setTreeLocation(this, ARGUMENT0_SLOT)
}
override fun getChild(slot: Int): IrElement? =
when (slot) {
ARGUMENT0_SLOT -> argument
else -> null
}
override fun replaceChild(slot: Int, newChild: IrElement) {
when (slot) {
ARGUMENT0_SLOT -> argument = newChild.assertCast()
else -> throwNoSuchSlot(slot)
}
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitTypeOperatorExpression(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
argument.accept(visitor, data)
}
}
@@ -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.index)?.accept(this, valueParameter.name.asString())
expression.getArgument(valueParameter.index)?.accept(this, valueParameter.name.asString())
}
}
}
@@ -66,7 +66,7 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
expression.dumpLabeledElementWith(data) {
expression.dispatchReceiver?.accept(this, "\$this")
expression.extensionReceiver?.accept(this, "\$receiver")
expression.argument?.accept(this, "\$value")
expression.value.accept(this, "\$value")
}
}
@@ -48,8 +48,8 @@ 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 visitLocalVariable(declaration: IrVariable, data: Nothing?): String =
"VAR ${declaration.descriptor.render()}"
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
"IrExpressionBody"
@@ -60,11 +60,8 @@ 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()}"
"BLOCK type=${expression.renderType()} hasResult=${expression.hasResult} isDesugared=${expression.isDesugared}"
override fun visitReturnExpression(expression: IrReturnExpression, data: Nothing?): String =
"RETURN type=${expression.renderType()}"
@@ -22,19 +22,18 @@ import org.jetbrains.kotlin.ir.expressions.*
interface IrElementVisitor<out R, in D> {
fun visitElement(element: IrElement, data: D): R
fun visitModule(declaration: IrModule, data: D): R = visitElement(declaration, data)
fun visitFile(declaration: IrFile, data: D): R = visitElement(declaration, data)
fun visitDeclaration(declaration: IrDeclaration, data: D): R = visitElement(declaration, data)
fun visitModule(declaration: IrModule, data: D): R = visitDeclaration(declaration, data)
fun visitCompoundDeclaration(declaration: IrCompoundDeclaration, data: D): R = visitDeclaration(declaration, data)
fun visitFile(declaration: IrFile, data: D): R = visitCompoundDeclaration(declaration, data)
fun visitClass(declaration: IrClass, data: D): R = visitCompoundDeclaration(declaration, data)
fun visitClass(declaration: IrClass, data: D): R = visitDeclaration(declaration, data)
fun visitFunction(declaration: IrFunction, data: D): R = visitDeclaration(declaration, data)
fun visitPropertyGetter(declaration: IrPropertyGetter, data: D): R = visitFunction(declaration, data)
fun visitPropertySetter(declaration: IrPropertySetter, data: D): R = visitFunction(declaration, data)
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 visitLocalVariable(declaration: IrVariable, 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)
@@ -46,11 +45,6 @@ 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)
+7 -9
View File
@@ -1,7 +1,7 @@
IrFile /callWithReorderedArguments.kt
IrFunction public fun foo(/*0*/ a: kotlin.Int, /*1*/ b: kotlin.Int): kotlin.Unit
IrExpressionBody
BLOCK type=kotlin.Unit
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
IrFunction public fun noReorder1(): kotlin.Int
IrExpressionBody
LITERAL Int type=kotlin.Int value='1'
@@ -16,17 +16,15 @@ IrFile /callWithReorderedArguments.kt
LITERAL Int type=kotlin.Int value='2'
IrFunction public fun test(): kotlin.Unit
IrExpressionBody
BLOCK type=kotlin.Unit
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
CALL .foo type=kotlin.Unit operator=
a: CALL .noReorder1 type=kotlin.Int operator=
b: CALL .noReorder2 type=kotlin.Int operator=
BLOCK type=kotlin.Unit
LOCAL tmp0
IrLocalVariable val tmp0: kotlin.Int
CALL .reordered1 type=kotlin.Int operator=
LOCAL tmp1
IrLocalVariable val tmp1: kotlin.Int
CALL .reordered2 type=kotlin.Int operator=
BLOCK type=kotlin.Unit hasResult=false isDesugared=true
VAR val tmp0: kotlin.Int
CALL .reordered1 type=kotlin.Int operator=
VAR val tmp1: kotlin.Int
CALL .reordered2 type=kotlin.Int operator=
CALL .foo type=kotlin.Unit operator=
a: GET_VAR tmp1 type=kotlin.Int
b: GET_VAR tmp0 type=kotlin.Int
+10
View File
@@ -0,0 +1,10 @@
object A
object B {
operator fun A.component1() = 1
operator fun A.component2() = 2
}
fun B.test() { // <<< destructuring1.txt
val (x, y) = A
}
+4
View File
@@ -0,0 +1,4 @@
IrFunction public fun B.test(): kotlin.Unit
IrExpressionBody
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
DUMMY KtDestructuringDeclaration type=kotlin.Unit
+3 -4
View File
@@ -17,10 +17,9 @@ IrFile /references.kt
GET_VAR x type=kotlin.String
IrFunction public fun test3(): kotlin.String
IrExpressionBody
BLOCK type=kotlin.Nothing
LOCAL x
IrLocalVariable val x: kotlin.String = "OK"
LITERAL String type=kotlin.String value='OK'
BLOCK type=kotlin.Nothing hasResult=false isDesugared=false
VAR val x: kotlin.String = "OK"
LITERAL String type=kotlin.String value='OK'
RETURN type=kotlin.Nothing
GET_VAR x type=kotlin.String
IrFunction public fun test4(): kotlin.String
+2 -2
View File
@@ -1,6 +1,6 @@
// <<< smoke.txt
fun testFun(): String { return "OK" }
val testSimpleVal = 1 // <<< smoke.testSimpleVal.txt
val testSimpleVal = 1
val testValWithGetter: Int get() = 42
var testSimpleVar = 2
var testVarWithAccessors: Int
@@ -13,4 +13,4 @@ var testVarWithAccessors: Int
// 2 IrPropertyGetter
// 1 IrPropertySetter
// 1 IrProperty public var testSimpleVar
// 1 IrProperty public var testVarWithAccessors
// 1 IrProperty public var testVarWithAccessors
-3
View File
@@ -1,3 +0,0 @@
IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null
IrExpressionBody
LITERAL Int type=kotlin.Int value='1'
+2 -2
View File
@@ -1,7 +1,7 @@
IrFile /smoke.kt
IrFunction public fun testFun(): kotlin.String
IrExpressionBody
BLOCK type=kotlin.Nothing
BLOCK type=kotlin.Nothing hasResult=false isDesugared=false
RETURN type=kotlin.Nothing
LITERAL String type=kotlin.String value='OK'
IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null
@@ -20,4 +20,4 @@ IrFile /smoke.kt
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
BLOCK type=kotlin.Unit hasResult=false isDesugared=false
@@ -53,6 +53,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
doTest(fileName);
}
@TestMetadata("destructuring1.kt")
public void testDestructuring1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/destructuring1.kt");
doTest(fileName);
}
@TestMetadata("dotQualified.kt")
public void testDotQualified() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/dotQualified.kt");