KT-30020 expressions without resolved calls in augmented assignment LHS

Augmented assignment operator (e.g., '+=') can be resolved to simple
function call ('plusAssign'). In that case, augmented assignment LHS
can be an arbitrary expression, and may have no associated ResolvedCall.

For example:
    (a as MutableList<Int>) += 42

Note that it can happen only in case of augmented assignment operator
convention resolution, because all other forms of assignment-like
operator desugaring require some kind of 'store' operation
(property setter, 'set' operator for array element expression, etc),
and should resolve to some combination of calls.

In that case we simply generate LHS on 'load', and throw assertion on
'store'.
This commit is contained in:
Dmitry Petrov
2019-02-22 13:02:24 +03:00
parent 1777849ff3
commit b792f3f12f
5 changed files with 367 additions and 4 deletions
@@ -172,15 +172,17 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
return generateArrayAccessAssignmentReceiver(ktLeft, origin)
}
val resolvedCall = getResolvedCall(ktLeft) ?: TODO("no resolved call for LHS")
val resolvedCall = getResolvedCall(ktLeft)
?: return generateExpressionAssignmentReceiver(ktLeft, origin, isAssignmentStatement)
val descriptor = resolvedCall.resultingDescriptor
val startOffset = ktLeft.startOffsetSkippingComments
val endOffset = ktLeft.endOffset
return when (descriptor) {
is SyntheticFieldDescriptor -> {
val receiverValue =
statementGenerator.generateBackingFieldReceiver(
ktLeft.startOffsetSkippingComments,
ktLeft.endOffset,
startOffset, endOffset,
resolvedCall,
descriptor
)
@@ -191,7 +193,7 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
if (descriptor.isDelegated)
DelegatedLocalPropertyLValue(
context,
ktLeft.startOffsetSkippingComments, ktLeft.endOffset,
startOffset, endOffset,
descriptor.type.toIrType(),
descriptor.getter?.let { context.symbolTable.referenceDeclaredFunction(it) },
descriptor.setter?.let { context.symbolTable.referenceDeclaredFunction(it) },
@@ -208,6 +210,24 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
}
}
private fun generateExpressionAssignmentReceiver(
ktLeft: KtExpression,
origin: IrStatementOrigin,
isAssignmentStatement: Boolean
): AssignmentReceiver {
// This is a somewhat special case when LHS of the augmented assignment operator is an arbitrary expression without resolved call.
// This can happen only in case of compound assignment resolved to '<op>Assign' operator, e.g.,
// (a as MutableList<Any>) += 42
if (!isAssignmentStatement) {
throw AssertionError("Arbitrary assignment receiver found in assignment-like expression: ${ktLeft.parent.text}")
}
return SpecialExpressionAssignmentReceiver(
statementGenerator, ktLeft, origin,
context.bindingContext.getType(ktLeft)?.toIrType() ?: throw AssertionError("No type for expression ${ktLeft.text}")
)
}
private fun createVariableValue(
ktExpression: KtExpression,
descriptor: ValueDescriptor,
@@ -0,0 +1,34 @@
/*
* 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.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi2ir.generators.StatementGenerator
class SpecialExpressionAssignmentReceiver(
private val statementGenerator: StatementGenerator,
private val ktExpression: KtExpression,
private val origin: IrStatementOrigin,
override val type: IrType
) :
LValue,
AssignmentReceiver {
override fun load(): IrExpression =
statementGenerator.generateExpression(ktExpression)
override fun store(irExpression: IrExpression): IrExpression =
throw AssertionError(
"This is an expression assignment receiver for ${ktExpression.text}, " +
"it can be used only in augmented assignment operator convention for '<op>Assign'"
)
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression =
withLValue(this)
}