FIR: Rework processing AugmentedArraySetCall
Previously (few commits earlier), it contained two versions of receiver (lhs) generated separately for each desugaring version that looked a bit redundant. Now, at FIR building stage we just don't create desugaring sub-trees, instead they are being built during bodies transformation and that seems to be much convenient there, since we don't need to reverse-engineer get-set-operator version to check if containing calls are successful (as we just built those calls and retain them) Semantically, this changes may only change how data flow works for such statements (see changed compatibilityResolveWithVarargAndOperatorCall.kt) ^KT-50861 Relates
This commit is contained in:
+1
-1
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.fir.lightTree.fir
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.builder.generateTemporaryVariable
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.generateTemporaryVariable
|
||||
import org.jetbrains.kotlin.fir.lightTree.converter.generateDestructuringBlock
|
||||
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier
|
||||
|
||||
|
||||
Vendored
+6
-6
@@ -3,11 +3,11 @@ FILE: safeCallsWithAugmentedAssignment.kt
|
||||
a#?.{ +=($subj$.b#, IntegerLiteral(1)) }
|
||||
a#?.{ $subj$.b# }?.{ +=($subj$.c#, IntegerLiteral(1)) }
|
||||
+=(a#?.{ $subj$.b# }.c#, IntegerLiteral(1))
|
||||
a#?.{ ArraySet:[$subj$.b#.get#(IntegerLiteral(0)).plusAssign#(IntegerLiteral(1))] }
|
||||
a#?.{ $subj$.b# }?.{ ArraySet:[$subj$.c#.get#(IntegerLiteral(0)).plusAssign#(IntegerLiteral(1))] }
|
||||
ArraySet:[a#?.{ $subj$.b# }.c#.get#(IntegerLiteral(0)).plusAssign#(IntegerLiteral(1))]
|
||||
a#?.{ ArraySet:[$subj$.b#.get#(IntegerLiteral(0)).get#(IntegerLiteral(0)).plusAssign#(IntegerLiteral(1))] }
|
||||
a#?.{ $subj$.b# }?.{ ArraySet:[$subj$.c#.get#(IntegerLiteral(0)).get#(IntegerLiteral(0)).plusAssign#(IntegerLiteral(1))] }
|
||||
ArraySet:[a#?.{ $subj$.b# }.c#.get#(IntegerLiteral(0)).get#(IntegerLiteral(0)).plusAssign#(IntegerLiteral(1))]
|
||||
a#?.{ ArraySet:[$subj$.b#.get#(IntegerLiteral(0)) += IntegerLiteral(1)] }
|
||||
a#?.{ $subj$.b# }?.{ ArraySet:[$subj$.c#.get#(IntegerLiteral(0)) += IntegerLiteral(1)] }
|
||||
ArraySet:[a#?.{ $subj$.b# }.c#.get#(IntegerLiteral(0)) += IntegerLiteral(1)]
|
||||
a#?.{ ArraySet:[$subj$.b#.get#(IntegerLiteral(0)).get#(IntegerLiteral(0)) += IntegerLiteral(1)] }
|
||||
a#?.{ $subj$.b# }?.{ ArraySet:[$subj$.c#.get#(IntegerLiteral(0)).get#(IntegerLiteral(0)) += IntegerLiteral(1)] }
|
||||
ArraySet:[a#?.{ $subj$.b# }.c#.get#(IntegerLiteral(0)).get#(IntegerLiteral(0)) += IntegerLiteral(1)]
|
||||
+=(a#?.{ $subj$.b# }.d#(), IntegerLiteral(1))
|
||||
}
|
||||
|
||||
+18
-121
@@ -1024,123 +1024,28 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
rhs: T?,
|
||||
convert: T.() -> FirExpression
|
||||
): FirStatement {
|
||||
require(receiver is FirFunctionCall) {
|
||||
"Array access should be desugared to a function call, but $receiver is found"
|
||||
}
|
||||
|
||||
return buildAugmentedArraySetCall {
|
||||
source = baseSource
|
||||
this.operation = operation
|
||||
assignCall = generateAugmentedCallForAugmentedArraySetCall(receiver, baseSource, operation, rhs, convert)
|
||||
setGetBlock =
|
||||
generateSetGetBlockForAugmentedArraySetCall(receiver, baseSource, arrayAccessSource, operation, rhs, convert)
|
||||
this.annotations += annotations
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateAugmentedCallForAugmentedArraySetCall(
|
||||
receiver: FirExpression, // a.get(x,y)
|
||||
baseSource: KtSourceElement?,
|
||||
operation: FirOperation,
|
||||
rhs: T?,
|
||||
convert: T.() -> FirExpression
|
||||
): FirFunctionCall {
|
||||
/*
|
||||
* Desugarings of a[x, y] += z to
|
||||
* a.get(x, y).plusAssign(z)
|
||||
*/
|
||||
return buildFunctionCall {
|
||||
source = baseSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
name = FirOperationNameConventions.ASSIGNMENTS.getValue(operation)
|
||||
}
|
||||
explicitReceiver = receiver
|
||||
argumentList = buildArgumentList {
|
||||
arguments += rhs?.convert() ?: buildErrorExpression(
|
||||
null,
|
||||
ConeSimpleDiagnostic("No value for array set", DiagnosticKind.Syntax)
|
||||
)
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun generateSetGetBlockForAugmentedArraySetCall(
|
||||
receiver: FirExpression,
|
||||
baseSource: KtSourceElement?,
|
||||
arrayAccessSource: KtSourceElement?,
|
||||
operation: FirOperation,
|
||||
rhs: T?,
|
||||
convert: T.() -> FirExpression
|
||||
): FirBlock {
|
||||
/*
|
||||
* Desugarings of a[x, y] += z to
|
||||
* {
|
||||
* val tmp_a = a
|
||||
* val tmp_x = x
|
||||
* val tmp_y = y
|
||||
* tmp_a.set(tmp_x, tmp_a.get(tmp_x, tmp_y).plus(z))
|
||||
* }
|
||||
*/
|
||||
return buildBlock {
|
||||
val baseCall = receiver as FirFunctionCall
|
||||
|
||||
val arrayVariable = generateTemporaryVariable(
|
||||
baseModuleData,
|
||||
source = null,
|
||||
specialName = "<array>",
|
||||
initializer = baseCall.explicitReceiver ?: buildErrorExpression {
|
||||
source = baseSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
diagnostic = ConeSimpleDiagnostic("No receiver for array access", DiagnosticKind.Syntax)
|
||||
}
|
||||
this.lhsGetCall = receiver
|
||||
this.rhs = rhs?.convert() ?: buildErrorExpression(
|
||||
null,
|
||||
ConeSimpleDiagnostic("No value for array set", DiagnosticKind.Syntax)
|
||||
)
|
||||
statements += arrayVariable
|
||||
val indexVariables = baseCall.arguments.mapIndexed { i, index ->
|
||||
generateTemporaryVariable(baseModuleData, source = null, specialName = "<index_$i>", initializer = index)
|
||||
}
|
||||
statements += indexVariables
|
||||
statements += buildFunctionCall {
|
||||
source = baseSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
explicitReceiver = arrayVariable.toQualifiedAccess()
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
name = OperatorNameConventions.SET
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
argumentList = buildArgumentList {
|
||||
for (indexVariable in indexVariables) {
|
||||
arguments += indexVariable.toQualifiedAccess()
|
||||
}
|
||||
|
||||
val getCall = buildFunctionCall {
|
||||
source = arrayAccessSource?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment)
|
||||
explicitReceiver = arrayVariable.toQualifiedAccess()
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
name = OperatorNameConventions.GET
|
||||
}
|
||||
argumentList = buildArgumentList {
|
||||
for (indexVariable in indexVariables) {
|
||||
arguments += indexVariable.toQualifiedAccess()
|
||||
}
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
}
|
||||
|
||||
val operatorCall = buildFunctionCall {
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
name = FirOperationNameConventions.ASSIGNMENTS_TO_SIMPLE_OPERATOR.getValue(operation)
|
||||
}
|
||||
explicitReceiver = getCall
|
||||
argumentList = buildArgumentList {
|
||||
arguments += rhs?.convert() ?: buildErrorExpression(
|
||||
null,
|
||||
ConeSimpleDiagnostic(
|
||||
"No value for array set",
|
||||
DiagnosticKind.Syntax
|
||||
)
|
||||
)
|
||||
}
|
||||
origin = FirFunctionCallOrigin.Operator
|
||||
}
|
||||
arguments += operatorCall
|
||||
}
|
||||
}
|
||||
// Second copy of rhs is used because we analyze it twice in different contexts
|
||||
// and now they should be different expressions instances to make everything work properly.
|
||||
// But this lead to exponential time already at FIR building stage,
|
||||
// so we hope this hack will be removed with KT-50861
|
||||
this.rhs2 = rhs?.convert() ?: buildErrorExpression(
|
||||
null,
|
||||
ConeSimpleDiagnostic("No value for array set", DiagnosticKind.Syntax)
|
||||
)
|
||||
this.arrayAccessSource = arrayAccessSource
|
||||
this.annotations += annotations
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1262,14 +1167,6 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
initContainingClassAttr(context)
|
||||
}
|
||||
|
||||
private fun FirVariable.toQualifiedAccess(): FirQualifiedAccessExpression = buildPropertyAccessExpression {
|
||||
calleeReference = buildResolvedNamedReference {
|
||||
source = this@toQualifiedAccess.source?.fakeElement(KtFakeSourceElementKind.ReferenceInAtomicQualifiedAccess)
|
||||
name = this@toQualifiedAccess.name
|
||||
resolvedSymbol = this@toQualifiedAccess.symbol
|
||||
}
|
||||
}
|
||||
|
||||
protected inline fun <R> withDefaultSourceElementKind(newDefault: KtSourceElementKind, action: () -> R): R {
|
||||
val currentForced = context.forcedElementSourceKind
|
||||
context.forcedElementSourceKind = newDefault
|
||||
|
||||
-44
@@ -285,50 +285,6 @@ fun generateResolvedAccessExpression(source: KtSourceElement?, variable: FirVari
|
||||
}
|
||||
}
|
||||
|
||||
fun generateTemporaryVariable(
|
||||
moduleData: FirModuleData,
|
||||
source: KtSourceElement?,
|
||||
name: Name,
|
||||
initializer: FirExpression,
|
||||
typeRef: FirTypeRef? = null,
|
||||
extractedAnnotations: Collection<FirAnnotation>? = null,
|
||||
): FirVariable =
|
||||
buildProperty {
|
||||
this.source = source
|
||||
this.moduleData = moduleData
|
||||
origin = FirDeclarationOrigin.Source
|
||||
returnTypeRef = typeRef ?: buildImplicitTypeRef {
|
||||
this.source = source
|
||||
}
|
||||
this.name = name
|
||||
this.initializer = initializer
|
||||
symbol = FirPropertySymbol(name)
|
||||
isVar = false
|
||||
isLocal = true
|
||||
status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL)
|
||||
if (extractedAnnotations != null) {
|
||||
// LT extracts annotations ahead.
|
||||
// PSI extracts annotations on demand. Use a similar util in [PsiConversionUtils]
|
||||
annotations.addAll(extractedAnnotations)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateTemporaryVariable(
|
||||
moduleData: FirModuleData,
|
||||
source: KtSourceElement?,
|
||||
specialName: String,
|
||||
initializer: FirExpression,
|
||||
extractedAnnotations: Collection<FirAnnotation>? = null,
|
||||
): FirVariable =
|
||||
generateTemporaryVariable(
|
||||
moduleData,
|
||||
source,
|
||||
Name.special("<$specialName>"),
|
||||
initializer,
|
||||
null,
|
||||
extractedAnnotations,
|
||||
)
|
||||
|
||||
val FirClassBuilder.ownerRegularOrAnonymousObjectSymbol
|
||||
get() = when (this) {
|
||||
is FirAnonymousObjectBuilder -> symbol
|
||||
|
||||
Reference in New Issue
Block a user