Don't introduce additional variables for simple array assignment.
This commit is contained in:
committed by
Dmitry Petrov
parent
abb106c885
commit
54e6bbd007
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
|
||||
fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): IntermediateValue? =
|
||||
fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): Value? =
|
||||
receiver?.let { generateReceiver(ktDefaultElement, receiver) }
|
||||
|
||||
fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: ReceiverValue): IntermediateValue {
|
||||
fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: ReceiverValue): Value {
|
||||
if (receiver is TransientReceiver) {
|
||||
return TransientReceiverValue(ktDefaultElement.text, receiver.type)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.CallBuilder
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.getValueArgumentsInParameterOrder
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.isValueArgumentReorderingRequired
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.Value
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -121,7 +121,7 @@ class CallGenerator(
|
||||
valueArgumentsToValueParameters[valueArgument] = valueParameter
|
||||
}
|
||||
|
||||
val irArgumentValues = HashMap<ValueParameterDescriptor, IntermediateValue>()
|
||||
val irArgumentValues = HashMap<ValueParameterDescriptor, Value>()
|
||||
|
||||
for (valueArgument in valueArgumentsInEvaluationOrder) {
|
||||
val valueParameter = valueArgumentsToValueParameters[valueArgument]!!
|
||||
|
||||
+1
-5
@@ -302,11 +302,7 @@ class OperatorExpressionGenerator(
|
||||
val ktLeft = expression.left!!
|
||||
val irRhs = statementGenerator.generateExpression(expression.right!!)
|
||||
val irAssignmentReceiver = generateAssignmentReceiver(ktLeft, IrOperator.EQ)
|
||||
|
||||
return if (irAssignmentReceiver is IntermediateReference)
|
||||
irAssignmentReceiver.store(irRhs)
|
||||
else
|
||||
irAssignmentReceiver.assign { irLValue -> irLValue.store(irRhs) }
|
||||
return irAssignmentReceiver.assign(irRhs)
|
||||
}
|
||||
|
||||
private fun generateAssignmentReceiver(ktLeft: KtExpression, irOperator: IrOperator): AssignmentReceiver {
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.IntermediateValue
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.Value
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.createRematerializableOrTemporary
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -84,7 +84,7 @@ class StatementGenerator(
|
||||
return irBlock
|
||||
}
|
||||
|
||||
fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrBlockImpl, containerValue: IntermediateValue) {
|
||||
fun declareComponentVariablesInBlock(multiDeclaration: KtDestructuringDeclaration, irBlock: IrBlockImpl, containerValue: Value) {
|
||||
val callGenerator = CallGenerator(this)
|
||||
for ((index, ktEntry) in multiDeclaration.entries.withIndex()) {
|
||||
val componentResolvedCall = getOrFail(BindingContext.COMPONENT_RESOLVED_CALL, ktEntry)
|
||||
|
||||
+12
-2
@@ -35,7 +35,7 @@ class ArrayAccessAssignmentReceiver(
|
||||
indexedSetCall?.let { it.descriptor.valueParameters.last().type } ?:
|
||||
throw AssertionError("Array access should have either indexed-get call or indexed-set call")
|
||||
|
||||
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression {
|
||||
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression {
|
||||
val hasResult = operator.isAssignmentOperatorWithResult()
|
||||
val resultType = if (hasResult) type else callGenerator.context.builtIns.unitType
|
||||
val irBlock = IrBlockImpl(startOffset, endOffset, resultType, hasResult, operator)
|
||||
@@ -54,7 +54,17 @@ class ArrayAccessAssignmentReceiver(
|
||||
return irBlock
|
||||
}
|
||||
|
||||
private fun CallBuilder.fillArrayAndIndexArguments(arrayValue: IntermediateValue, indexValues: List<IntermediateValue>) {
|
||||
override fun assign(value: IrExpression): IrExpression {
|
||||
if (indexedSetCall == null) throw AssertionError("Array access without indexed-get call")
|
||||
indexedSetCall.setExplicitReceiverValue(OnceExpressionValue(irArray))
|
||||
irIndices.forEachIndexed { i, irIndex ->
|
||||
indexedSetCall.irValueArgumentsByIndex[i] = irIndex
|
||||
}
|
||||
indexedSetCall.lastArgument = value
|
||||
return callGenerator.generateCall(startOffset, endOffset, indexedSetCall, IrOperator.EQ)
|
||||
}
|
||||
|
||||
private fun CallBuilder.fillArrayAndIndexArguments(arrayValue: Value, indexValues: List<Value>) {
|
||||
setExplicitReceiverValue(arrayValue)
|
||||
indexValues.forEachIndexed { i, irIndexValue ->
|
||||
irValueArgumentsByIndex[i] = irIndexValue.load()
|
||||
|
||||
@@ -41,6 +41,12 @@ class CallBuilder(val original: ResolvedCall<*>) {
|
||||
val CallBuilder.argumentsCount: Int get() =
|
||||
irValueArgumentsByIndex.size
|
||||
|
||||
var CallBuilder.lastArgument: IrExpression?
|
||||
get() = irValueArgumentsByIndex.last()
|
||||
set(value) {
|
||||
irValueArgumentsByIndex[argumentsCount - 1] = value
|
||||
}
|
||||
|
||||
fun CallBuilder.getValueArgumentsInParameterOrder(): List<IrExpression?> =
|
||||
descriptor.valueParameters.map { irValueArgumentsByIndex[it.index] }
|
||||
|
||||
@@ -65,10 +71,10 @@ val CallBuilder.explicitReceiverParameter: ReceiverParameterDescriptor? get() =
|
||||
val CallBuilder.explicitReceiverType: KotlinType? get() =
|
||||
explicitReceiverParameter?.type
|
||||
|
||||
fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: IntermediateValue) {
|
||||
fun CallBuilder.setExplicitReceiverValue(explicitReceiverValue: Value) {
|
||||
val previousCallReceiver = callReceiver
|
||||
callReceiver = object : CallReceiver {
|
||||
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
|
||||
override fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression {
|
||||
return previousCallReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val newDispatchReceiverValue = if (hasExtensionReceiver) dispatchReceiverValue else explicitReceiverValue
|
||||
val newExtensionReceiverValue = if (hasExtensionReceiver) explicitReceiverValue else null
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ class LValueWithGetterAndSetterCalls(
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val operator: IrOperator? = null
|
||||
) : IntermediateReference {
|
||||
) : LValue {
|
||||
private val descriptor: CallableDescriptor =
|
||||
getterCall?.descriptor ?: setterCall?.descriptor ?:
|
||||
throw AssertionError("Call-based LValue should have either a getter or a setter call")
|
||||
|
||||
@@ -29,7 +29,7 @@ class OnceCallValue(
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val operator: IrOperator? = null
|
||||
): IntermediateValue {
|
||||
): Value {
|
||||
private var instantiated = false
|
||||
|
||||
override fun load(): IrExpression {
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.psi2ir.generators.CallGenerator
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class OnceExpressionValue(val irExpression: IrExpression) : IntermediateValue {
|
||||
class OnceExpressionValue(val irExpression: IrExpression) : Value {
|
||||
init {
|
||||
irExpression.assertDetached()
|
||||
}
|
||||
|
||||
+4
-4
@@ -21,14 +21,14 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi2ir.generators.Scope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class RematerializableValue(val irExpression: IrExpressionWithCopy) : IntermediateValue {
|
||||
class RematerializableValue(val irExpression: IrExpressionWithCopy) : Value {
|
||||
override val type: KotlinType?
|
||||
get() = irExpression.type
|
||||
|
||||
override fun load(): IrExpression = irExpression.copy()
|
||||
}
|
||||
|
||||
fun createRematerializableValue(irExpression: IrExpression): IntermediateValue? =
|
||||
fun createRematerializableValue(irExpression: IrExpression): Value? =
|
||||
(irExpression as? IrExpressionWithCopy)?.let { RematerializableValue(it) }
|
||||
|
||||
inline fun createRematerializableOrTemporary(
|
||||
@@ -36,7 +36,7 @@ inline fun createRematerializableOrTemporary(
|
||||
irExpression: IrExpression,
|
||||
nameHint: String? = null,
|
||||
addVariable: (IrVariable) -> Unit
|
||||
): IntermediateValue {
|
||||
): Value {
|
||||
val rematerializable = createRematerializableValue(irExpression)
|
||||
if (rematerializable != null) {
|
||||
return rematerializable
|
||||
@@ -47,7 +47,7 @@ inline fun createRematerializableOrTemporary(
|
||||
return VariableLValue(temporaryVariable)
|
||||
}
|
||||
|
||||
fun createRematerializableOrTemporary(scope: Scope, irExpression: IrExpression, block: IrBlockImpl, nameHint: String? = null): IntermediateValue =
|
||||
fun createRematerializableOrTemporary(scope: Scope, irExpression: IrExpression, block: IrBlockImpl, nameHint: String? = null): Value =
|
||||
createRematerializableOrTemporary(scope, irExpression, nameHint) {
|
||||
block.addStatement(it)
|
||||
}
|
||||
+4
-4
@@ -31,14 +31,14 @@ class SafeCallReceiver(
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
val explicitReceiver: IrExpression,
|
||||
val implicitDispatchReceiverValue: IntermediateValue?
|
||||
val implicitDispatchReceiverValue: Value?
|
||||
) : CallReceiver {
|
||||
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
|
||||
override fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression {
|
||||
val irTmp = generator.scope.createTemporaryVariable(explicitReceiver, "safe_receiver")
|
||||
val safeReceiverValue = VariableLValue(irTmp)
|
||||
|
||||
val dispatchReceiverValue: IntermediateValue
|
||||
val extensionReceiverValue: IntermediateValue?
|
||||
val dispatchReceiverValue: Value
|
||||
val extensionReceiverValue: Value?
|
||||
if (implicitDispatchReceiverValue != null) {
|
||||
dispatchReceiverValue = implicitDispatchReceiverValue
|
||||
extensionReceiverValue = safeReceiverValue
|
||||
|
||||
+3
-3
@@ -19,10 +19,10 @@ package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
|
||||
class SimpleCallReceiver(
|
||||
val dispatchReceiverValue: IntermediateValue?,
|
||||
val extensionReceiverValue: IntermediateValue?
|
||||
val dispatchReceiverValue: Value?,
|
||||
val extensionReceiverValue: Value?
|
||||
) : CallReceiver {
|
||||
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression {
|
||||
override fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression {
|
||||
return withDispatchAndExtensionReceivers(dispatchReceiverValue, extensionReceiverValue)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ class SimplePropertyLValue(
|
||||
val irOperator: IrOperator?,
|
||||
val descriptor: PropertyDescriptor,
|
||||
val callReceiver: CallReceiver
|
||||
) : IntermediateReference, AssignmentReceiver {
|
||||
) : LValue, AssignmentReceiver {
|
||||
override val type: KotlinType?
|
||||
get() = descriptor.type
|
||||
|
||||
@@ -54,7 +54,7 @@ class SimplePropertyLValue(
|
||||
}
|
||||
}
|
||||
|
||||
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression {
|
||||
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression {
|
||||
return callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val variablesForReceivers = SmartList<IrVariable>()
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class TransientReceiverValue(val description: String, override val type: KotlinType?): IntermediateValue {
|
||||
class TransientReceiverValue(val description: String, override val type: KotlinType?): Value {
|
||||
override fun load(): IrExpression {
|
||||
throw AssertionError("Transient receiver should not be instantiated: $description")
|
||||
}
|
||||
|
||||
@@ -19,19 +19,20 @@ package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
interface IntermediateValue {
|
||||
interface Value {
|
||||
fun load(): IrExpression
|
||||
val type: KotlinType?
|
||||
}
|
||||
|
||||
interface IntermediateReference : IntermediateValue {
|
||||
interface LValue : Value {
|
||||
fun store(irExpression: IrExpression): IrExpression
|
||||
}
|
||||
|
||||
interface AssignmentReceiver {
|
||||
fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression
|
||||
fun assign(withLValue: (LValue) -> IrExpression): IrExpression
|
||||
fun assign(value: IrExpression): IrExpression = assign { it.store(value) }
|
||||
}
|
||||
|
||||
interface CallReceiver {
|
||||
fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression
|
||||
fun call(withDispatchAndExtensionReceivers: (Value?, Value?) -> IrExpression): IrExpression
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ class VariableLValue(
|
||||
val endOffset: Int,
|
||||
val descriptor: VariableDescriptor,
|
||||
val irOperator: IrOperator? = null
|
||||
) : IntermediateReference, AssignmentReceiver {
|
||||
) : LValue, AssignmentReceiver {
|
||||
constructor(irVariable: IrVariable, irOperator: IrOperator? = null) :
|
||||
this(irVariable.startOffset, irVariable.endOffset, irVariable.descriptor, irOperator)
|
||||
|
||||
@@ -41,6 +41,6 @@ class VariableLValue(
|
||||
override fun store(irExpression: IrExpression): IrExpression =
|
||||
IrSetVariableImpl(startOffset, endOffset, descriptor, irExpression, irOperator)
|
||||
|
||||
override fun assign(withLValue: (IntermediateReference) -> IrExpression): IrExpression =
|
||||
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
|
||||
withLValue(this)
|
||||
}
|
||||
+10
-16
@@ -6,11 +6,10 @@ IrFile /arrayAssignment.kt
|
||||
CALL .intArrayOf type=kotlin.IntArray operator=null
|
||||
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
|
||||
DUMMY vararg type=kotlin.Int
|
||||
BLOCK type=kotlin.Unit hasResult=false operator=EQ
|
||||
CALL .set type=kotlin.Unit operator=EQ
|
||||
$this: GET_VAR x type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='1'
|
||||
value: CONST Int type=kotlin.Int value='0'
|
||||
CALL .set type=kotlin.Unit operator=EQ
|
||||
$this: GET_VAR x type=kotlin.IntArray operator=null
|
||||
index: CONST Int type=kotlin.Int value='1'
|
||||
value: CONST Int type=kotlin.Int value='0'
|
||||
IrFunction public fun foo(): kotlin.Int
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
@@ -19,14 +18,9 @@ IrFile /arrayAssignment.kt
|
||||
IrFunction public fun test2(): kotlin.Unit
|
||||
IrExpressionBody
|
||||
BLOCK type=<no-type> hasResult=false operator=null
|
||||
BLOCK type=kotlin.Unit hasResult=false operator=EQ
|
||||
VAR val tmp0_array: kotlin.IntArray
|
||||
CALL .intArrayOf type=kotlin.IntArray operator=null
|
||||
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
|
||||
DUMMY vararg type=kotlin.Int
|
||||
VAR val tmp1_index0: kotlin.Int
|
||||
CALL .foo type=kotlin.Int operator=null
|
||||
CALL .set type=kotlin.Unit operator=EQ
|
||||
$this: GET_VAR tmp0_array type=kotlin.IntArray operator=null
|
||||
index: GET_VAR tmp1_index0 type=kotlin.Int operator=null
|
||||
value: CONST Int type=kotlin.Int value='1'
|
||||
CALL .set type=kotlin.Unit operator=EQ
|
||||
$this: CALL .intArrayOf type=kotlin.IntArray operator=null
|
||||
elements: TYPE_OP operator=IMPLICIT_CAST typeOperand=kotlin.IntArray
|
||||
DUMMY vararg type=kotlin.Int
|
||||
index: CALL .foo type=kotlin.Int operator=null
|
||||
value: CONST Int type=kotlin.Int value='1'
|
||||
|
||||
Reference in New Issue
Block a user