psi2ir: dynamic member simple assignment/augmented assignment/++/--
This commit is contained in:
+135
-52
@@ -16,16 +16,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.irBlock
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irTemporary
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicOperatorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.util.referenceFunction
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
|
||||
@@ -35,6 +37,7 @@ import org.jetbrains.kotlin.psi2ir.unwrappedSetMethod
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
@@ -53,35 +56,74 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
val ktLeft = ktExpression.left!!
|
||||
val ktRight = ktExpression.right!!
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, origin)
|
||||
val isDynamicCall = opResolvedCall.resultingDescriptor.isDynamic()
|
||||
|
||||
return irAssignmentReceiver.assign { irLValue ->
|
||||
val opCall = statementGenerator.pregenerateCallReceivers(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(irLValue)
|
||||
opCall.irValueArgumentsByIndex[0] = ktRight.genExpr()
|
||||
val irOpCall = CallGenerator(statementGenerator).generateCall(ktExpression, opCall, origin)
|
||||
|
||||
if (isSimpleAssignment) {
|
||||
// Set( Op( Get(), RHS ) )
|
||||
irLValue.store(irOpCall)
|
||||
if (isDynamicCall) {
|
||||
IrDynamicOperatorExpressionImpl(
|
||||
ktExpression.startOffsetSkippingComments, ktExpression.endOffset,
|
||||
context.irBuiltIns.unitType,
|
||||
getDynamicAugmentedAssignmentOperator(ktExpression.operationToken)
|
||||
).apply {
|
||||
left = irLValue.load()
|
||||
right = ktRight.genExpr()
|
||||
}
|
||||
} else {
|
||||
// Op( Get(), RHS )
|
||||
irOpCall
|
||||
val opCall = statementGenerator.pregenerateCallReceivers(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(irLValue)
|
||||
opCall.irValueArgumentsByIndex[0] = ktRight.genExpr()
|
||||
val irOpCall = CallGenerator(statementGenerator).generateCall(ktExpression, opCall, origin)
|
||||
|
||||
if (isSimpleAssignment) {
|
||||
// Set( Op( Get(), RHS ) )
|
||||
irLValue.store(irOpCall)
|
||||
} else {
|
||||
// Op( Get(), RHS )
|
||||
irOpCall
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDynamicAugmentedAssignmentOperator(operatorToken: IElementType): IrDynamicOperator =
|
||||
when (operatorToken) {
|
||||
KtTokens.PLUSEQ -> IrDynamicOperator.PLUSEQ
|
||||
KtTokens.MINUSEQ -> IrDynamicOperator.MINUSEQ
|
||||
KtTokens.MULTEQ -> IrDynamicOperator.MULEQ
|
||||
KtTokens.DIVEQ -> IrDynamicOperator.DIVEQ
|
||||
KtTokens.PERCEQ -> IrDynamicOperator.MODEQ
|
||||
else -> throw AssertionError("Unexpected operator token: $operatorToken")
|
||||
}
|
||||
|
||||
fun generatePrefixIncrementDecrement(ktExpression: KtPrefixExpression, origin: IrStatementOrigin): IrExpression {
|
||||
val opResolvedCall = getResolvedCall(ktExpression)!!
|
||||
val ktBaseExpression = ktExpression.baseExpression!!
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktBaseExpression, origin)
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktBaseExpression, origin, isAssignmentStatement = false)
|
||||
val isDynamicCall = opResolvedCall.resultingDescriptor.isDynamic()
|
||||
|
||||
return irAssignmentReceiver.assign { irLValue ->
|
||||
irBlock(ktExpression.startOffsetSkippingComments, ktExpression.endOffset, origin, irLValue.type) {
|
||||
val opCall = statementGenerator.pregenerateCall(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(irLValue)
|
||||
val irOpCall = CallGenerator(statementGenerator).generateCall(ktExpression, opCall, origin)
|
||||
+irLValue.store(irOpCall)
|
||||
+irLValue.load()
|
||||
val startOffset = ktExpression.startOffsetSkippingComments
|
||||
val endOffset = ktExpression.endOffset
|
||||
|
||||
if (isDynamicCall) {
|
||||
IrDynamicOperatorExpressionImpl(
|
||||
startOffset, endOffset,
|
||||
irLValue.type,
|
||||
if (ktExpression.operationToken == KtTokens.PLUSPLUS)
|
||||
IrDynamicOperator.PREFIX_INCREMENT
|
||||
else
|
||||
IrDynamicOperator.PREFIX_DECREMENT
|
||||
).apply {
|
||||
receiver = irLValue.load()
|
||||
}
|
||||
} else {
|
||||
irBlock(startOffset, endOffset, origin, irLValue.type) {
|
||||
val opCall = statementGenerator.pregenerateCall(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(irLValue)
|
||||
val irOpCall = CallGenerator(statementGenerator).generateCall(ktExpression, opCall, origin)
|
||||
+irLValue.store(irOpCall)
|
||||
+irLValue.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,23 +131,43 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
fun generatePostfixIncrementDecrement(ktExpression: KtPostfixExpression, origin: IrStatementOrigin): IrExpression {
|
||||
val opResolvedCall = getResolvedCall(ktExpression)!!
|
||||
val ktBaseExpression = ktExpression.baseExpression!!
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktBaseExpression, origin)
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktBaseExpression, origin, isAssignmentStatement = false)
|
||||
val isDynamicCall = opResolvedCall.resultingDescriptor.isDynamic()
|
||||
val startOffset = ktExpression.startOffsetSkippingComments
|
||||
val endOffset = ktExpression.endOffset
|
||||
|
||||
return irAssignmentReceiver.assign { irLValue ->
|
||||
irBlock(ktExpression.startOffsetSkippingComments, ktExpression.endOffset, origin, irLValue.type) {
|
||||
val temporary = irTemporary(irLValue.load())
|
||||
val opCall = statementGenerator.pregenerateCall(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(
|
||||
VariableLValue(context, startOffset, endOffset, temporary.symbol, temporary.type)
|
||||
)
|
||||
val irOpCall = CallGenerator(statementGenerator).generateCall(ktExpression, opCall, origin)
|
||||
+irLValue.store(irOpCall)
|
||||
+irGet(temporary.type, temporary.symbol)
|
||||
if (isDynamicCall) {
|
||||
IrDynamicOperatorExpressionImpl(
|
||||
startOffset, endOffset,
|
||||
irLValue.type,
|
||||
if (ktExpression.operationToken == KtTokens.PLUSPLUS)
|
||||
IrDynamicOperator.POSTFIX_INCREMENT
|
||||
else
|
||||
IrDynamicOperator.POSTFIX_DECREMENT
|
||||
).apply {
|
||||
receiver = irLValue.load()
|
||||
}
|
||||
} else {
|
||||
irBlock(startOffset, endOffset, origin, irLValue.type) {
|
||||
val temporary = irTemporary(irLValue.load())
|
||||
val opCall = statementGenerator.pregenerateCall(opResolvedCall)
|
||||
opCall.setExplicitReceiverValue(
|
||||
VariableLValue(context, startOffset, endOffset, temporary.symbol, temporary.type)
|
||||
)
|
||||
val irOpCall = CallGenerator(statementGenerator).generateCall(ktExpression, opCall, origin)
|
||||
+irLValue.store(irOpCall)
|
||||
+irGet(temporary.type, temporary.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateAssignmentReceiver(ktLeft: KtExpression, origin: IrStatementOrigin): AssignmentReceiver {
|
||||
private fun generateAssignmentReceiver(
|
||||
ktLeft: KtExpression,
|
||||
origin: IrStatementOrigin,
|
||||
isAssignmentStatement: Boolean = true
|
||||
): AssignmentReceiver {
|
||||
if (ktLeft is KtArrayAccessExpression) {
|
||||
return generateArrayAccessAssignmentReceiver(ktLeft, origin)
|
||||
}
|
||||
@@ -116,7 +178,12 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
return when (descriptor) {
|
||||
is SyntheticFieldDescriptor -> {
|
||||
val receiverValue =
|
||||
statementGenerator.generateBackingFieldReceiver(ktLeft.startOffsetSkippingComments, ktLeft.endOffset, resolvedCall, descriptor)
|
||||
statementGenerator.generateBackingFieldReceiver(
|
||||
ktLeft.startOffsetSkippingComments,
|
||||
ktLeft.endOffset,
|
||||
resolvedCall,
|
||||
descriptor
|
||||
)
|
||||
createBackingFieldLValue(ktLeft, descriptor.propertyDescriptor, receiverValue, origin)
|
||||
}
|
||||
is LocalVariableDescriptor ->
|
||||
@@ -133,7 +200,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
else
|
||||
createVariableValue(ktLeft, descriptor, origin)
|
||||
is PropertyDescriptor ->
|
||||
generateAssignmentReceiverForProperty(descriptor, origin, ktLeft, resolvedCall)
|
||||
generateAssignmentReceiverForProperty(descriptor, origin, ktLeft, resolvedCall, isAssignmentStatement)
|
||||
is ValueDescriptor ->
|
||||
createVariableValue(ktLeft, descriptor, origin)
|
||||
else ->
|
||||
@@ -172,29 +239,45 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
descriptor: PropertyDescriptor,
|
||||
origin: IrStatementOrigin,
|
||||
ktLeft: KtExpression,
|
||||
resolvedCall: ResolvedCall<*>
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
isAssignmentStatement: Boolean
|
||||
): AssignmentReceiver =
|
||||
if (isValInitializationInConstructor(descriptor, resolvedCall)) {
|
||||
val thisClass = getThisClass()
|
||||
val thisAsReceiverParameter = thisClass.thisAsReceiverParameter
|
||||
val thisType = thisAsReceiverParameter.type.toIrType()
|
||||
val irThis = IrGetValueImpl(
|
||||
ktLeft.startOffsetSkippingComments, ktLeft.endOffset,
|
||||
thisType,
|
||||
context.symbolTable.referenceValueParameter(thisAsReceiverParameter)
|
||||
)
|
||||
createBackingFieldLValue(ktLeft, descriptor, RematerializableValue(irThis), null)
|
||||
} else {
|
||||
val propertyReceiver = statementGenerator.generateCallReceiver(
|
||||
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
|
||||
isSafe = resolvedCall.call.isSafeCall(),
|
||||
isAssignmentReceiver = true
|
||||
)
|
||||
when {
|
||||
descriptor.isDynamic() ->
|
||||
DynamicMemberLValue(
|
||||
context,
|
||||
ktLeft.startOffsetSkippingComments, ktLeft.endOffset,
|
||||
descriptor.type.toIrType(),
|
||||
descriptor.name.asString(),
|
||||
statementGenerator.generateCallReceiver(
|
||||
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
|
||||
isSafe = resolvedCall.call.isSafeCall(),
|
||||
isAssignmentReceiver = isAssignmentStatement
|
||||
)
|
||||
)
|
||||
isValInitializationInConstructor(descriptor, resolvedCall) -> {
|
||||
val thisClass = getThisClass()
|
||||
val thisAsReceiverParameter = thisClass.thisAsReceiverParameter
|
||||
val thisType = thisAsReceiverParameter.type.toIrType()
|
||||
val irThis = IrGetValueImpl(
|
||||
ktLeft.startOffsetSkippingComments, ktLeft.endOffset,
|
||||
thisType,
|
||||
context.symbolTable.referenceValueParameter(thisAsReceiverParameter)
|
||||
)
|
||||
createBackingFieldLValue(ktLeft, descriptor, RematerializableValue(irThis), null)
|
||||
}
|
||||
else -> {
|
||||
val propertyReceiver = statementGenerator.generateCallReceiver(
|
||||
ktLeft, descriptor, resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver,
|
||||
isSafe = resolvedCall.call.isSafeCall(),
|
||||
isAssignmentReceiver = isAssignmentStatement
|
||||
)
|
||||
|
||||
val superQualifier = getSuperQualifier(resolvedCall)
|
||||
val superQualifier = getSuperQualifier(resolvedCall)
|
||||
|
||||
// TODO property imported from an object
|
||||
createPropertyLValue(ktLeft, descriptor, propertyReceiver, getTypeArguments(resolvedCall), origin, superQualifier)
|
||||
// TODO property imported from an object
|
||||
createPropertyLValue(ktLeft, descriptor, propertyReceiver, getTypeArguments(resolvedCall), origin, superQualifier)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPropertyLValue(
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.ir.builders.IrGeneratorContext
|
||||
import org.jetbrains.kotlin.ir.expressions.IrDynamicOperator
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicMemberExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDynamicOperatorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.left
|
||||
import org.jetbrains.kotlin.ir.expressions.right
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
|
||||
class DynamicMemberLValue(
|
||||
private val context: IrGeneratorContext,
|
||||
private val startOffset: Int,
|
||||
private val endOffset: Int,
|
||||
override val type: IrType,
|
||||
private val memberName: String,
|
||||
private val receiver: CallReceiver
|
||||
) : LValue, AssignmentReceiver {
|
||||
|
||||
override fun load(): IrExpression =
|
||||
receiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val dynamicReceiver = getDynamicReceiver(dispatchReceiverValue, extensionReceiverValue)
|
||||
|
||||
IrDynamicMemberExpressionImpl(
|
||||
startOffset, endOffset,
|
||||
type,
|
||||
memberName,
|
||||
dynamicReceiver
|
||||
)
|
||||
}
|
||||
|
||||
override fun store(irExpression: IrExpression): IrExpression =
|
||||
receiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val dynamicReceiver = getDynamicReceiver(dispatchReceiverValue, extensionReceiverValue)
|
||||
|
||||
IrDynamicOperatorExpressionImpl(
|
||||
startOffset, endOffset,
|
||||
context.irBuiltIns.unitType,
|
||||
IrDynamicOperator.EQ
|
||||
).apply {
|
||||
left = dynamicReceiver
|
||||
right = irExpression
|
||||
}
|
||||
}
|
||||
|
||||
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
|
||||
receiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
withLValue(
|
||||
DynamicMemberLValue(
|
||||
context, startOffset, endOffset, type, memberName,
|
||||
SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getDynamicReceiver(dispatchReceiverValue: IntermediateValue?, extensionReceiverValue: IntermediateValue?): IrExpression {
|
||||
if (dispatchReceiverValue == null) throw AssertionError("Dynamic call $memberName should have a dispatch receiver")
|
||||
if (extensionReceiverValue != null) throw AssertionError("Dynamic call $memberName should have no extension receiver")
|
||||
return dispatchReceiverValue.load()
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -16,15 +16,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.buildStatement
|
||||
import org.jetbrains.kotlin.ir.builders.irIfNull
|
||||
import org.jetbrains.kotlin.ir.builders.irNull
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrIfThenElseImpl
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorWithScope
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
|
||||
|
||||
class SafeCallReceiver(
|
||||
@@ -33,7 +32,7 @@ class SafeCallReceiver(
|
||||
val endOffset: Int,
|
||||
val extensionReceiver: IntermediateValue?,
|
||||
val dispatchReceiver: IntermediateValue?,
|
||||
val isAssignmentReceiver: Boolean
|
||||
val isStatement: Boolean
|
||||
) : CallReceiver {
|
||||
|
||||
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
|
||||
@@ -52,7 +51,7 @@ class SafeCallReceiver(
|
||||
|
||||
val irResult = withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue)
|
||||
|
||||
val resultType = if (isAssignmentReceiver) generator.context.irBuiltIns.unitType else irResult.type.makeNullable()
|
||||
val resultType = if (isStatement) generator.context.irBuiltIns.unitType else irResult.type.makeNullable()
|
||||
|
||||
val irBlock = IrBlockImpl(startOffset, endOffset, resultType, IrStatementOrigin.SAFE_CALL)
|
||||
|
||||
@@ -79,7 +78,7 @@ fun IrExpression.safeCallOnDispatchReceiver(
|
||||
generator, startOffset, endOffset,
|
||||
extensionReceiver = null,
|
||||
dispatchReceiver = OnceExpressionValue(this),
|
||||
isAssignmentReceiver = false
|
||||
isStatement = false
|
||||
).call { dispatchReceiverValue, _ ->
|
||||
ifNotNull(dispatchReceiverValue!!.load())
|
||||
}
|
||||
@@ -24,7 +24,10 @@ var IrDynamicOperatorExpression.left: IrExpression
|
||||
var IrDynamicOperatorExpression.right: IrExpression
|
||||
get() = arguments[0]
|
||||
set(value) {
|
||||
arguments[0] = value
|
||||
if (arguments.isEmpty())
|
||||
arguments.add(value)
|
||||
else
|
||||
arguments[0] = value
|
||||
}
|
||||
|
||||
interface IrDynamicMemberExpression : IrDynamicExpression {
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
class IrDynamicOperatorExpressionImpl(
|
||||
startOffset: Int,
|
||||
@@ -23,7 +24,7 @@ class IrDynamicOperatorExpressionImpl(
|
||||
|
||||
override lateinit var receiver: IrExpression
|
||||
|
||||
override val arguments: MutableList<IrExpression> = ArrayList()
|
||||
override val arguments: MutableList<IrExpression> = SmartList()
|
||||
|
||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||
visitor.visitDynamicOperatorExpression(this, data)
|
||||
|
||||
Reference in New Issue
Block a user