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:
+24
-4
@@ -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,
|
||||
|
||||
+34
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user