Refactor calls and related expressions

This commit is contained in:
Dmitry Petrov
2016-08-11 17:17:05 +03:00
committed by Dmitry Petrov
parent 3e11f35918
commit 4ccf3c3590
25 changed files with 561 additions and 257 deletions
@@ -106,6 +106,6 @@ abstract class IrDeclarationGeneratorBase(
IrReturnExpressionImpl(startOffset, endOffset, irExpression.type)
.apply { returnedExpression = irExpression }
return IrExpressionBodyImpl(startOffset, endOffset, containingDeclaration).apply { childExpression = bodyExpression }
return IrExpressionBodyImpl(startOffset, endOffset, containingDeclaration).apply { argument = bodyExpression }
}
}
@@ -53,7 +53,7 @@ class IrExpressionGenerator(
return IrTypeOperatorExpressionImpl(
ktElement.startOffset, ktElement.endOffset, smartCastType,
IrTypeOperator.SMART_AS, smartCastType
).apply { childExpression = this@smartCastIfNeeded }
).apply { argument = this@smartCastIfNeeded }
}
}
return this
@@ -70,7 +70,7 @@ class IrExpressionGenerator(
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrExpression =
IrReturnExpressionImpl(expression.startOffset, expression.endOffset, expression.type())
.apply { this.childExpression = expression.returnedExpression?.generate() }
.apply { this.argument = expression.returnedExpression?.generate() }
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression {
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
@@ -112,21 +112,22 @@ class IrExpressionGenerator(
return when (descriptor) {
is ClassDescriptor ->
IrSingletonReferenceImpl(expression.startOffset, expression.endOffset, expression.type(),
descriptor.singletonDescriptor() ?: TODO("Unsupported class as value: ${descriptor.name}"))
if (DescriptorUtils.isObject(descriptor))
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), descriptor)
else if (DescriptorUtils.isEnumEntry(descriptor))
IrGetEnumValueExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), descriptor)
else
IrGetObjectValueExpressionImpl(expression.startOffset, expression.endOffset, expression.type(),
descriptor.companionObjectDescriptor ?: error("Class value without companion object: $descriptor"))
is PropertyDescriptor -> {
generateCall(
expression,
resolvedCall ?: TODO("Property, no resolved call: ${descriptor.name}"),
IrCallableOperator.PROPERTY_GET
)
generateCall(expression, resolvedCall ?: TODO("Property, no resolved call: ${descriptor.name}"), null)
}
is VariableDescriptor ->
IrVariableReferenceImpl(expression.startOffset, expression.endOffset, expression.type(), descriptor)
IrGetVariableExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), descriptor)
else ->
IrDummyExpression(expression.startOffset, expression.endOffset, expression.type(),
expression.getReferencedName() +
": ${descriptor?.name} ${descriptor?.javaClass?.simpleName}")
expression.getReferencedName() +
": ${descriptor?.name} ${descriptor?.javaClass?.simpleName}")
}
}
@@ -150,35 +151,47 @@ 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, expression.type(), referenceTarget)
is CallableDescriptor ->
IrExtensionReceiverReferenceImpl(expression.startOffset, expression.endOffset, expression.type(), referenceTarget)
IrGetExtensionReceiverExpressionImpl(expression.startOffset, expression.endOffset, expression.type(),
referenceTarget.extensionReceiverParameter!!)
else ->
error("Expected this or receiver: $referenceTarget")
error("Expected this or receiver: $referenceTarget")
}
}
private fun generateCall(
ktExpression: KtExpression,
resolvedCall: ResolvedCall<out CallableDescriptor>,
operator: IrCallableOperator?,
operator: IrOperator? = null,
superQualifier: ClassDescriptor? = null
): IrExpression =
IrCallExpressionImpl(
ktExpression.startOffset, ktExpression.endOffset, ktExpression.type(),
resolvedCall.resultingDescriptor, resolvedCall.call.isSafeCall(), operator, superQualifier
).apply {
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver)
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver)
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))
): 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) {
@@ -191,11 +204,11 @@ class IrExpressionGenerator(
is ExpressionReceiver ->
receiver.expression.generate()
is ClassValueReceiver ->
IrSingletonReferenceImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
receiver.classQualifier.descriptor)
IrGetObjectValueExpressionImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
receiver.classQualifier.descriptor)
is ExtensionReceiver ->
IrExtensionReceiverReferenceImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type,
receiver.declarationDescriptor.extensionReceiverParameter!!)
IrGetExtensionReceiverExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type,
receiver.declarationDescriptor.extensionReceiverParameter!!)
null ->
null
else ->
@@ -211,14 +224,4 @@ class IrExpressionGenerator(
TODO("vararg")
}
}
companion object {
fun ClassDescriptor.singletonDescriptor(): ClassDescriptor? =
if (DescriptorUtils.isObject(this) || DescriptorUtils.isEnumEntry(this))
this
else
companionObjectDescriptor
}
}
@@ -14,20 +14,10 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.ir.util
package org.jetbrains.kotlin.ir
import java.util.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
class PairListImpl<T>(val first: T, val second: T) : AbstractList<T>() {
override val size: Int get() = 2
class IrBuiltIns(val builtIns: KotlinBuiltIns) {
override fun get(index: Int): T =
when (index) {
0 -> first
1 -> second
else -> throw IndexOutOfBoundsException(index.toString())
}
}
fun <T> pairList(first: T, second: T): List<T> =
PairListImpl(first, second)
@@ -0,0 +1,24 @@
/*
* 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
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
@@ -34,19 +34,19 @@ class IrExpressionBodyImpl(
endOffset: Int,
override val parent: IrDeclaration
) : IrDeclarationOwnerBase(startOffset, endOffset), IrExpressionBody {
override var childExpression: IrExpression? = null
override var argument: IrExpression? = null
set(newExpression) {
field?.detach()
field = newExpression
newExpression?.setTreeLocation(this, IrExpressionOwner1.EXPRESSION_INDEX)
newExpression?.setTreeLocation(this, CHILD_EXPRESSION_INDEX)
}
override fun getChildExpression(index: Int): IrExpression? =
if (index == IrExpressionOwner1.EXPRESSION_INDEX) childExpression else null
if (index == CHILD_EXPRESSION_INDEX) argument else null
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
childExpression = newChild
argument = newChild
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
@@ -57,6 +57,6 @@ class IrExpressionBodyImpl(
}
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
childExpression?.accept(visitor, data)
argument?.accept(visitor, data)
}
}
@@ -22,13 +22,10 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrCallExpression : IrCompoundExpression {
interface IrCallExpression : IrMemberAccessExpression, IrCompoundExpression {
val superQualifier: ClassDescriptor?
val operator: IrCallableOperator?
val isSafe: Boolean
val callee: CallableDescriptor
var dispatchReceiver: IrExpression?
var extensionReceiver: IrExpression?
val operator: IrOperator?
override val descriptor: CallableDescriptor
fun getValueArgument(valueParameterDescriptor: ValueParameterDescriptor): IrExpression?
fun putValueArgument(valueParameterDescriptor: ValueParameterDescriptor, valueArgument: IrExpression?)
@@ -38,33 +35,19 @@ interface IrCallExpression : IrCompoundExpression {
}
fun IrCallExpression.getMappedValueArguments(): List<IrExpression?> =
callee.valueParameters.mapNotNull { getValueArgument(it) }
descriptor.valueParameters.mapNotNull { getValueArgument(it) }
abstract class IrCallExpressionBase(
class IrCallExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
override final val callee: CallableDescriptor,
override val isSafe: Boolean,
override val operator: IrCallableOperator?,
override val descriptor: CallableDescriptor,
isSafe: Boolean,
override val operator: IrOperator?,
override val superQualifier: ClassDescriptor?
) : IrExpressionBase(startOffset, endOffset, type), IrCallExpression {
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrCallExpression {
private val argumentsByParameterIndex =
kotlin.arrayOfNulls<IrExpression>(callee.valueParameters.size)
override var dispatchReceiver: IrExpression? = null
set(newReceiver) {
field?.detach()
field = newReceiver
newReceiver?.setTreeLocation(this, DISPATCH_RECEIVER_INDEX)
}
override var extensionReceiver: IrExpression? = null
set(newReceiver) {
field?.detach()
field = newReceiver
newReceiver?.setTreeLocation(this, EXTENSION_RECEIVER_INDEX)
}
kotlin.arrayOfNulls<IrExpression>(descriptor.valueParameters.size)
override fun getValueArgument(valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
argumentsByParameterIndex[valueParameterDescriptor.index]
@@ -122,21 +105,6 @@ abstract class IrCallExpressionBase(
acceptChildExpressions(visitor, data)
}
companion object {
const val DISPATCH_RECEIVER_INDEX = -1
const val EXTENSION_RECEIVER_INDEX = -2
}
}
class IrCallExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
callee: CallableDescriptor,
isSafe: Boolean,
operator: IrCallableOperator? = null,
superQualifier: ClassDescriptor? = null
) : IrCallExpressionBase(startOffset, endOffset, type, callee, isSafe, operator, superQualifier), IrCallExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitCallExpression(this, data)
}
}
@@ -1,69 +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
enum class IrCallableOperator {
PROPERTY_GET,
PROPERTY_SET,
INVOKE,
INVOKE_EXTENSION,
PLUSPLUS,
MINUSMINUS,
UMINUS,
EXCL,
LT,
GT,
LTEQ,
GTEQ,
EQEQ,
EQEQEQ,
EXCLEQ,
EXCLEQEQ,
IN,
NOT_IN,
ANDAND,
OROR,
RANGE,
PLUS,
MINUS,
MUL,
DIV,
MOD,
PLUSEQ,
MINUSEQ,
MULEQ,
DIVEQ,
MODEQ;
}
fun IrCallableOperator.isCompoundAssignment(): Boolean =
this >= IrCallableOperator.PLUSEQ && this <= IrCallableOperator.MODEQ
fun IrCallableOperator.hasCompoundAssignmentDual(): Boolean =
this >= IrCallableOperator.PLUS && this <= IrCallableOperator.MOD
fun IrCallableOperator.toDualOperator(): IrCallableOperator =
when {
isCompoundAssignment() ->
IrCallableOperator.values()[this.ordinal - IrCallableOperator.PLUSEQ.ordinal + IrCallableOperator.PLUS.ordinal]
hasCompoundAssignmentDual() ->
IrCallableOperator.values()[this.ordinal - IrCallableOperator.PLUS.ordinal + IrCallableOperator.PLUSEQ.ordinal]
else ->
throw UnsupportedOperationException("Operator $this is not a compound assignment")
}
@@ -24,6 +24,8 @@ interface IrCompoundExpression : IrExpression, IrExpressionOwner
interface IrCompoundExpression1 : IrCompoundExpression, IrExpressionOwner1
interface IrCompoundExpression2 : IrCompoundExpression, IrExpressionOwner2
interface IrCompoundExpressionN : IrCompoundExpression, IrExpressionOwnerN
abstract class IrCompoundExpressionNBase(
@@ -72,19 +74,19 @@ abstract class IrCompoundExpression1Base(
endOffset: Int,
override val type: KotlinType
) : IrExpressionBase(startOffset, endOffset, type), IrCompoundExpression1 {
override var childExpression: IrExpression? = null
override var argument: IrExpression? = null
set(newExpression) {
field?.detach()
field = newExpression
newExpression?.setTreeLocation(this, IrExpressionOwner1.EXPRESSION_INDEX)
newExpression?.setTreeLocation(this, ARGUMENT0_INDEX)
}
override fun getChildExpression(index: Int): IrExpression? =
if (index == IrExpressionOwner1.EXPRESSION_INDEX) childExpression else null
if (index == ARGUMENT0_INDEX) argument else null
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
childExpression = newChild
argument = newChild
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
@@ -92,6 +94,50 @@ abstract class IrCompoundExpression1Base(
}
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
childExpression?.accept(visitor, data)
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)
}
}
@@ -16,7 +16,8 @@
package org.jetbrains.kotlin.ir.expressions
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -25,17 +26,13 @@ interface IrDeclarationReference : IrExpression {
val descriptor: DeclarationDescriptor
}
interface IrVariableReference : IrDeclarationReference {
override val descriptor: VariableDescriptor
}
interface IrSingletonReference : IrDeclarationReference {
interface IrGetSingletonValueExpression : IrDeclarationReference {
override val descriptor: ClassDescriptor
}
interface IrExtensionReceiverReference : IrDeclarationReference {
override val descriptor: CallableDescriptor
}
interface IrGetObjectValueExpression : IrGetSingletonValueExpression
interface IrGetEnumValueExpression : IrGetSingletonValueExpression
abstract class IrDeclarationReferenceBase<out D : DeclarationDescriptor>(
startOffset: Int,
@@ -44,34 +41,23 @@ abstract class IrDeclarationReferenceBase<out D : DeclarationDescriptor>(
override val descriptor: D
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrDeclarationReference
class IrVariableReferenceImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
descriptor: VariableDescriptor
) : IrDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, type, descriptor), IrVariableReference {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitVariableReference(this, data)
}
class IrSingletonReferenceImpl(
class IrGetObjectValueExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
descriptor: ClassDescriptor
) : IrDeclarationReferenceBase<ClassDescriptor>(startOffset, endOffset, type, descriptor), IrSingletonReference {
) : IrDeclarationReferenceBase<ClassDescriptor>(startOffset, endOffset, type, descriptor), IrGetObjectValueExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitSingletonReference(this, data)
visitor.visitGetObjectValue(this, data)
}
class IrExtensionReceiverReferenceImpl(
class IrGetEnumValueExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
override val descriptor: CallableDescriptor
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrExtensionReceiverReference {
descriptor: ClassDescriptor
) : IrDeclarationReferenceBase<ClassDescriptor>(startOffset, endOffset, type, descriptor), IrGetEnumValueExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitExtensionReceiverReference(this, data)
return visitor.visitGetEnumValue(this, data)
}
}
@@ -28,14 +28,10 @@ interface IrExpression : IrElement {
val type: KotlinType
fun setTreeLocation(parent: IrExpressionOwner?, index: Int)
companion object {
const val DETACHED_INDEX = Int.MIN_VALUE
}
}
fun IrExpression.detach() {
setTreeLocation(null, IrExpression.DETACHED_INDEX)
setTreeLocation(null, DETACHED_INDEX)
}
fun IrExpressionOwner.validateChild(child: IrExpression) {
@@ -48,7 +44,7 @@ abstract class IrExpressionBase(
override val type: KotlinType
) : IrElementBase(startOffset, endOffset), IrExpression {
override var parent: IrExpressionOwner? = null
override var index: Int = IrExpression.DETACHED_INDEX
override var index: Int = DETACHED_INDEX
override fun setTreeLocation(parent: IrExpressionOwner?, index: Int) {
this.parent = parent
@@ -26,11 +26,12 @@ interface IrExpressionOwner : IrElement {
}
interface IrExpressionOwner1 : IrExpressionOwner {
var childExpression: IrExpression?
var argument: IrExpression?
}
companion object {
const val EXPRESSION_INDEX = 0
}
interface IrExpressionOwner2 : IrExpressionOwner {
var argument0: IrExpression?
var argument1: IrExpression?
}
interface IrExpressionOwnerN : IrExpressionOwner {
@@ -0,0 +1,50 @@
/*
* 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.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrGetVariableExpression : IrDeclarationReference {
override val descriptor: VariableDescriptor
}
interface IrGetExtensionReceiverExpression : IrDeclarationReference {
override val descriptor: CallableDescriptor
}
class IrGetVariableExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
descriptor: VariableDescriptor
) : IrDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, type, descriptor), IrGetVariableExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetVariable(this, data)
}
class IrGetExtensionReceiverExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
override val descriptor: CallableDescriptor
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrGetExtensionReceiverExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitGetExtensionReceiver(this, data)
}
@@ -0,0 +1,46 @@
/*
* 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.types.KotlinType
interface IrMemberAccessExpression : IrDeclarationReference, IrExpressionOwner {
var dispatchReceiver: IrExpression?
var extensionReceiver: IrExpression?
val isSafe: Boolean
}
abstract class IrMemberAccessExpressionBase(
startOffset: Int,
endOffset: Int,
type: KotlinType,
override val isSafe: Boolean
) : IrExpressionBase(startOffset, endOffset, type), IrMemberAccessExpression {
override var dispatchReceiver: IrExpression? = null
set(newReceiver) {
field?.detach()
field = newReceiver
newReceiver?.setTreeLocation(this, DISPATCH_RECEIVER_INDEX)
}
override var extensionReceiver: IrExpression? = null
set(newReceiver) {
field?.detach()
field = newReceiver
newReceiver?.setTreeLocation(this, EXTENSION_RECEIVER_INDEX)
}
}
@@ -0,0 +1,63 @@
/*
* 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
enum class IrOperator {
INVOKE, INVOKE_EXTENSION,
PREFIX_INCR, PREFIX_DECR, POSTFIX_INCR, POSTFIX_DECR,
UMINUS,
EXCL,
EXCLEXCL,
LT, GT, LTEQ, GTEQ,
EQEQ, EQEQEQ, EXCLEQ, EXCLEQEQ,
IN, NOT_IN,
ANDAND, OROR,
RANGE,
PLUS, MINUS, MUL, DIV, MOD,
EQ,
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
fun IrOperator.isIncrementOrDecrement(): Boolean =
this in INCR_DECR_START..INCR_DECR_END
fun IrOperator.isCompoundAssignment(): Boolean =
this in CAO_START .. CAO_END
fun IrOperator.isAssignmentOrCompoundAssignment(): Boolean =
this == IrOperator.EQ || isCompoundAssignment()
fun IrOperator.hasCompoundAssignmentDual(): Boolean =
this in DUAL_START .. DUAL_END
fun IrOperator.toDualOperator(): IrOperator =
when {
isCompoundAssignment() ->
IrOperator.values()[this.ordinal - CAO_START.ordinal + DUAL_START.ordinal]
hasCompoundAssignmentDual() ->
IrOperator.values()[this.ordinal - DUAL_START.ordinal + CAO_START.ordinal]
else ->
throw UnsupportedOperationException("Operator $this is not a compound assignment")
}
@@ -0,0 +1,53 @@
/*
* 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.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrOperatorExpression : IrExpression {
val operator: IrOperator
val relatedDescriptor: FunctionDescriptor?
}
interface IrUnaryOperatorExpression : IrOperatorExpression, IrCompoundExpression1
interface IrBinaryOperatorExpression : IrOperatorExpression, IrCompoundExpression2
class IrUnaryOperatorExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
override val operator: IrOperator,
override val relatedDescriptor: FunctionDescriptor?
) : IrCompoundExpression1Base(startOffset, endOffset, type), IrUnaryOperatorExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitUnaryOperator(this, data)
}
}
class IrBinaryOperatorExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
override val operator: IrOperator,
override val relatedDescriptor: FunctionDescriptor?
) : IrCompoundExpression2Base(startOffset, endOffset, type), IrBinaryOperatorExpression {
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitBinaryOperator(this, data)
}
@@ -0,0 +1,111 @@
/*
* 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.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
interface IrPropertyAccessExpression : IrMemberAccessExpression {
override val descriptor: PropertyDescriptor
}
interface IrGetPropertyExpression : IrPropertyAccessExpression
interface IrSetPropertyExpression : IrPropertyAccessExpression, IrCompoundExpression1
class IrGetPropertyExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
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
}
}
}
class IrSetPropertyExpressionImpl(
startOffset: Int,
endOffset: Int,
type: KotlinType,
isSafe: Boolean,
override val descriptor: PropertyDescriptor
) : IrMemberAccessExpressionBase(startOffset, endOffset, type, isSafe), IrSetPropertyExpression {
override var argument: IrExpression? = null
set(value) {
field?.detach()
field = value
value?.setTreeLocation(this, ARGUMENT0_INDEX)
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitSetProperty(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)
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 replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
validateChild(oldChild)
when (oldChild.index) {
DISPATCH_RECEIVER_INDEX -> dispatchReceiver = newChild
EXTENSION_RECEIVER_INDEX -> extensionReceiver = newChild
ARGUMENT0_INDEX -> argument = newChild
}
}
}
@@ -23,9 +23,9 @@ import org.jetbrains.kotlin.types.KotlinType
interface IrReturnExpression : IrCompoundExpression1
var IrReturnExpression.returnedExpression: IrExpression?
get() = childExpression
get() = argument
set(newReturnedExpression) {
childExpression = newReturnedExpression
argument = newReturnedExpression
}
class IrReturnExpressionImpl(
@@ -20,10 +20,11 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
enum class IrTypeOperator {
SMART_AS,
AS,
AS_SAFE,
IS;
SMART_AS,
SAFE_AS,
IS,
NOT_IS;
}
interface IrTypeOperatorExpression : IrExpression, IrCompoundExpression1 {
@@ -18,9 +18,10 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceLocationManager
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCallExpression
import org.jetbrains.kotlin.ir.expressions.IrGetPropertyExpression
import org.jetbrains.kotlin.ir.expressions.IrSetPropertyExpression
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.utils.Printer
@@ -48,12 +49,27 @@ class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
expression.dumpLabeledElementWith(data) {
expression.dispatchReceiver?.accept(this, "\$this")
expression.extensionReceiver?.accept(this, "\$receiver")
for (valueParameter in expression.callee.valueParameters) {
for (valueParameter in expression.descriptor.valueParameters) {
expression.getValueArgument(valueParameter)?.accept(this, valueParameter.name.asString())
}
}
}
override fun visitGetProperty(expression: IrGetPropertyExpression, data: String) {
expression.dumpLabeledElementWith(data) {
expression.dispatchReceiver?.accept(this, "\$this")
expression.extensionReceiver?.accept(this, "\$receiver")
}
}
override fun visitSetProperty(expression: IrSetPropertyExpression, data: String) {
expression.dumpLabeledElementWith(data) {
expression.dispatchReceiver?.accept(this, "\$this")
expression.extensionReceiver?.accept(this, "\$receiver")
expression.argument?.accept(this, "\$value")
}
}
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
printer.println(accept(elementRenderer, null).withLabel(label))
indented(body)
@@ -63,20 +63,29 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitReturnExpression(expression: IrReturnExpression, data: Nothing?): String =
"RETURN type=${expression.renderType()}"
override fun visitVariableReference(expression: IrVariableReference, data: Nothing?): String =
"VAR ${expression.descriptor.name}"
override fun visitSingletonReference(expression: IrSingletonReference, data: Nothing?): String =
"SINGLETON ${expression.descriptor.name}"
override fun visitExtensionReceiverReference(expression: IrExtensionReceiverReference, data: Nothing?): String =
override fun visitGetExtensionReceiver(expression: IrGetExtensionReceiverExpression, data: Nothing?): String =
"\$RECEIVER of: ${expression.descriptor.containingDeclaration.name}"
override fun visitThisExpression(expression: IrThisExpression, data: Nothing?): String =
"THIS ${expression.classDescriptor.render()}"
override fun visitCallExpression(expression: IrCallExpression, data: Nothing?): String =
"CALL ${if (expression.isSafe) "?." else "."}${expression.callee.name} ${expression.operator ?: ""}"
"CALL ${if (expression.isSafe) "?." else "."}${expression.descriptor.name} ${expression.operator ?: ""}"
override fun visitGetProperty(expression: IrGetPropertyExpression, data: Nothing?): String =
"GET_PROPERTY ${if (expression.isSafe) "?." else "."}${expression.descriptor.name}"
override fun visitGetVariable(expression: IrGetVariableExpression, data: Nothing?): String =
"GET_VAR ${expression.descriptor.name}"
override fun visitGetObjectValue(expression: IrGetObjectValueExpression, data: Nothing?): String =
"GET_OBJECT ${expression.descriptor.name}"
override fun visitGetEnumValue(expression: IrGetEnumValueExpression, data: Nothing?): String =
"GET_ENUM_VALUE ${expression.descriptor.name}"
override fun visitSetProperty(expression: IrSetPropertyExpression, data: Nothing?): String =
"SET_PROPERTY ${if (expression.isSafe) "?." else "."}${expression.descriptor.name}"
override fun visitDummyExpression(expression: IrDummyExpression, data: Nothing?): String =
"DUMMY ${expression.description}"
@@ -44,17 +44,27 @@ interface IrElementVisitor<out R, in D> {
fun visitBlockExpression(expression: IrBlockExpression, data: D): R = visitExpression(expression, data)
fun visitStringTemplate(expression: IrStringConcatenationExpression, data: D) = visitExpression(expression, data)
fun visitThisExpression(expression: IrThisExpression, data: D) = visitExpression(expression, data)
fun visitDeclarationReference(expression: IrDeclarationReference, data: D) = visitExpression(expression, data)
fun visitVariableReference(expression: IrVariableReference, data: D) = visitDeclarationReference(expression, data)
fun visitSingletonReference(expression: IrSingletonReference, data: D) = visitDeclarationReference(expression, data)
fun visitExtensionReceiverReference(expression: IrExtensionReceiverReference, data: D) = visitDeclarationReference(expression, data)
fun visitGetObjectValue(expression: IrGetObjectValueExpression, data: D) = visitDeclarationReference(expression, data)
fun visitGetEnumValue(expression: IrGetEnumValueExpression, data: D) = visitDeclarationReference(expression, data)
fun visitGetVariable(expression: IrGetVariableExpression, data: D) = visitDeclarationReference(expression, data)
fun visitGetExtensionReceiver(expression: IrGetExtensionReceiverExpression, data: D) = visitDeclarationReference(expression, data)
fun visitMemberAccess(expression: IrMemberAccessExpression, data: D) = visitDeclarationReference(expression, data)
fun visitCallExpression(expression: IrCallExpression, data: D) = visitMemberAccess(expression, data)
fun visitPropertyAccess(expression: IrPropertyAccessExpression, data: D) = visitMemberAccess(expression, data)
fun visitGetProperty(expression: IrGetPropertyExpression, data: D) = visitPropertyAccess(expression, data)
fun visitSetProperty(expression: IrSetPropertyExpression, data: D) = visitPropertyAccess(expression, data)
fun visitCallExpression(expression: IrCallExpression, data: D) = visitExpression(expression, data)
fun visitOperatorExpression(expression: IrOperatorExpression, data: D) = visitExpression(expression, data)
fun visitUnaryOperator(expression: IrUnaryOperatorExpression, data: D) = visitOperatorExpression(expression, data)
fun visitBinaryOperator(expression: IrBinaryOperatorExpression, data: D) = visitOperatorExpression(expression, data)
fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: D) = visitExpression(expression, data)
// NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered
fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data)
}
+8 -8
View File
@@ -2,28 +2,28 @@ IrFile /calls.kt
IrFunction public fun foo(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
VAR x
GET_VAR x
IrFunction public fun bar(/*0*/ x: kotlin.Int): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
CALL .foo
x: VAR x
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: VAR x
y: VAR x
y: VAR x
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: <root>
$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: <root>
y: VAR x
x: $RECEIVER of: ext2
y: GET_VAR x
+4 -4
View File
@@ -2,10 +2,10 @@ IrFile /dotQualified.kt
IrFunction public fun length(/*0*/ s: kotlin.String): kotlin.Int
IrExpressionBody
RETURN type=kotlin.Int
CALL .length PROPERTY_GET
$this: VAR s
GET_PROPERTY .length
$this: GET_VAR s
IrFunction public fun lengthN(/*0*/ s: kotlin.String?): kotlin.Int?
IrExpressionBody
RETURN type=kotlin.Int?
CALL ?.length PROPERTY_GET
$this: VAR s
GET_PROPERTY ?.length
$this: GET_VAR s
@@ -7,5 +7,5 @@ IrFile /extensionPropertyGetterCall.kt
IrFunction public fun kotlin.String.test5(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
CALL .okext PROPERTY_GET
GET_PROPERTY .okext
$receiver: $RECEIVER of: test5
+6 -6
View File
@@ -6,7 +6,7 @@ IrFile /references.kt
IrProperty public val ok2: kotlin.String = "OK" getter=null setter=null
IrExpressionBody
RETURN type=kotlin.String
CALL .ok PROPERTY_GET
GET_PROPERTY .ok
IrProperty public val ok3: kotlin.String getter=<get-ok3> setter=null
IrPropertyGetter public fun <get-ok3>(): kotlin.String property=ok3
IrExpressionBody
@@ -15,21 +15,21 @@ IrFile /references.kt
IrFunction public fun test1(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
CALL .ok PROPERTY_GET
GET_PROPERTY .ok
IrFunction public fun test2(/*0*/ x: kotlin.String): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
VAR x
GET_VAR x
IrFunction public fun test3(): kotlin.String
IrExpressionBody
BLOCK type=kotlin.Nothing
DUMMY KtProperty
RETURN type=kotlin.Nothing
VAR x
GET_VAR x
IrFunction public fun test4(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
CALL .ok3 PROPERTY_GET
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
@@ -38,5 +38,5 @@ IrFile /references.kt
IrFunction public fun kotlin.String.test5(): kotlin.String
IrExpressionBody
RETURN type=kotlin.String
CALL .okext PROPERTY_GET
GET_PROPERTY .okext
$receiver: $RECEIVER of: test5