[RAW FIR] Refactor destructuring code

Move destructuring related code into common to reduce
differences between PSI and LT.
This commit is contained in:
Kirill Rakhman
2023-08-22 10:19:12 +02:00
committed by Space Team
parent 8de36c416e
commit 12b3fbd39a
9 changed files with 171 additions and 140 deletions
+3
View File
@@ -371,6 +371,9 @@ val projectsWithEnabledContextReceivers by extra {
":compiler:fir:resolve", ":compiler:fir:resolve",
":compiler:fir:plugin-utils", ":compiler:fir:plugin-utils",
":compiler:fir:fir2ir", ":compiler:fir:fir2ir",
":compiler:fir:raw-fir:raw-fir.common",
":compiler:fir:raw-fir:psi2fir",
":compiler:fir:raw-fir:light-tree2fir",
":kotlin-lombok-compiler-plugin.k1", ":kotlin-lombok-compiler-plugin.k1",
":kotlinx-serialization-compiler-plugin.k2", ":kotlinx-serialization-compiler-plugin.k2",
":plugins:parcelize:parcelize-compiler:parcelize.k2", ":plugins:parcelize:parcelize-compiler:parcelize.k2",
@@ -6,26 +6,10 @@
package org.jetbrains.kotlin.fir.lightTree.converter package org.jetbrains.kotlin.fir.lightTree.converter
import com.intellij.lang.LighterASTNode import com.intellij.lang.LighterASTNode
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.builder.generateResolvedAccessExpression
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.builder.FirCallBuilder import org.jetbrains.kotlin.fir.expressions.builder.FirCallBuilder
import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList
import org.jetbrains.kotlin.fir.expressions.builder.buildBlock
import org.jetbrains.kotlin.fir.expressions.builder.buildComponentCall
import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.FirUserTypeRef import org.jetbrains.kotlin.fir.types.FirUserTypeRef
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
@@ -76,48 +60,4 @@ inline fun isClassLocal(classNode: LighterASTNode, getParent: LighterASTNode.()
return false return false
} }
fun generateDestructuringBlock(
moduleData: FirModuleData,
multiDeclaration: DestructuringDeclaration,
container: FirVariable,
tmpVariable: Boolean
): FirBlock {
return buildBlock {
statements.addDestructuringStatements(moduleData, multiDeclaration, container, tmpVariable)
}
}
internal fun MutableList<FirStatement>.addDestructuringStatements(
moduleData: FirModuleData,
multiDeclaration: DestructuringDeclaration,
container: FirVariable,
tmpVariable: Boolean,
) {
if (tmpVariable) {
this += container
}
val isVar = multiDeclaration.isVar
for ((index, entry) in multiDeclaration.entries.withIndex()) {
if (entry == null) continue
this += buildProperty {
this.moduleData = moduleData
origin = FirDeclarationOrigin.Source
returnTypeRef = entry.returnTypeRef
name = entry.name
initializer = buildComponentCall {
val componentCallSource = entry.source?.fakeElement(KtFakeSourceElementKind.DesugaredComponentFunctionCall)
source = componentCallSource
explicitReceiver = generateResolvedAccessExpression(componentCallSource, container)
componentIndex = index + 1
}
this.isVar = isVar
symbol = FirPropertySymbol(entry.name) // TODO?
source = entry.source
isLocal = true
status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL)
annotations += entry.annotations
}
}
}
val FirUserTypeRef.isUnderscored get() = qualifier.lastOrNull()?.name?.asString() == "_" val FirUserTypeRef.isUnderscored get() = qualifier.lastOrNull()?.name?.asString() == "_"
@@ -1366,7 +1366,7 @@ class LightTreeRawFirDeclarationBuilder(
internal fun convertDestructingDeclaration(destructingDeclaration: LighterASTNode): DestructuringDeclaration { internal fun convertDestructingDeclaration(destructingDeclaration: LighterASTNode): DestructuringDeclaration {
var modifiers = Modifier() var modifiers = Modifier()
var isVar = false var isVar = false
val entries = mutableListOf<FirVariable?>() val entries = mutableListOf<DestructuringEntry>()
val source = destructingDeclaration.toFirSourceElement() val source = destructingDeclaration.toFirSourceElement()
var firExpression: FirExpression? = null var firExpression: FirExpression? = null
destructingDeclaration.forEachChildren { destructingDeclaration.forEachChildren {
@@ -1387,14 +1387,14 @@ class LightTreeRawFirDeclarationBuilder(
ConeSyntaxDiagnostic("Initializer required for destructuring declaration") ConeSyntaxDiagnostic("Initializer required for destructuring declaration")
), ),
source, source,
modifiers modifiers.annotations
) )
} }
/** /**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseMultiDeclarationName * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseMultiDeclarationName
*/ */
private fun convertDestructingDeclarationEntry(entry: LighterASTNode): FirVariable? { private fun convertDestructingDeclarationEntry(entry: LighterASTNode): DestructuringEntry {
var modifiers = Modifier() var modifiers = Modifier()
var identifier: String? = null var identifier: String? = null
var firType: FirTypeRef? = null var firType: FirTypeRef? = null
@@ -1411,18 +1411,13 @@ class LightTreeRawFirDeclarationBuilder(
} else { } else {
identifier.nameAsSafeName() identifier.nameAsSafeName()
} }
return buildProperty {
source = entry.toFirSourceElement() return DestructuringEntry(
moduleData = baseModuleData source = entry.toFirSourceElement(),
origin = FirDeclarationOrigin.Source returnTypeRef = firType ?: implicitType,
returnTypeRef = firType ?: implicitType name = name,
this.name = name annotations = modifiers.annotations,
isVar = false )
symbol = FirPropertySymbol(name)
isLocal = true
status = FirDeclarationStatusImpl(Visibilities.Local, Modality.FINAL)
annotations += modifiers.annotations
}
} }
/** /**
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.expressions.impl.buildSingleExpressionBlock import org.jetbrains.kotlin.fir.expressions.impl.buildSingleExpressionBlock
import org.jetbrains.kotlin.fir.lightTree.fir.ValueParameter import org.jetbrains.kotlin.fir.lightTree.fir.ValueParameter
import org.jetbrains.kotlin.fir.lightTree.fir.WhenEntry import org.jetbrains.kotlin.fir.lightTree.fir.WhenEntry
import org.jetbrains.kotlin.fir.lightTree.fir.addDestructuringStatements
import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference
@@ -178,7 +179,8 @@ class LightTreeRawFirExpressionBuilder(
baseModuleData, baseModuleData,
multiDeclaration, multiDeclaration,
multiParameter, multiParameter,
tmpVariable = false tmpVariable = false,
localEntries = true
) )
multiParameter multiParameter
} else { } else {
@@ -1172,13 +1174,13 @@ class LightTreeRawFirExpressionBuilder(
valueParameter.returnTypeRef valueParameter.returnTypeRef
) )
if (multiDeclaration != null) { if (multiDeclaration != null) {
val destructuringBlock = generateDestructuringBlock( statements.addDestructuringStatements(
baseModuleData, baseModuleData,
multiDeclaration, multiDeclaration,
firLoopParameter, firLoopParameter,
tmpVariable = true tmpVariable = true,
localEntries = true,
) )
statements.addAll(destructuringBlock.statements)
} else { } else {
statements.add(firLoopParameter) statements.add(firLoopParameter)
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -7,28 +7,76 @@ package org.jetbrains.kotlin.fir.lightTree.fir
import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.builder.DestructuringContext
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.builder.addDestructuringStatements
import org.jetbrains.kotlin.fir.declarations.FirVariable import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.builder.buildBlock
import org.jetbrains.kotlin.fir.generateTemporaryVariable import org.jetbrains.kotlin.fir.generateTemporaryVariable
import org.jetbrains.kotlin.fir.lightTree.converter.generateDestructuringBlock import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
data class DestructuringDeclaration( data class DestructuringDeclaration(
val isVar: Boolean, val isVar: Boolean,
val entries: List<FirVariable?>, val entries: List<DestructuringEntry>,
val initializer: FirExpression, val initializer: FirExpression,
val source: KtSourceElement, val source: KtSourceElement,
val modifier: Modifier, val annotations: List<FirAnnotation>,
) { ) {
fun toFirDestructingDeclaration(moduleData: FirModuleData): FirExpression { fun toFirDestructingDeclaration(
moduleData: FirModuleData,
tmpVariable: Boolean = true,
localEntries: Boolean = true,
): FirExpression {
val baseVariable = generateTemporaryVariable( val baseVariable = generateTemporaryVariable(
moduleData, moduleData,
source, source,
SpecialNames.DESTRUCT, SpecialNames.DESTRUCT,
initializer, initializer,
extractedAnnotations = modifier.annotations extractedAnnotations = annotations
) )
return generateDestructuringBlock(moduleData, this, baseVariable, tmpVariable = true) return buildBlock {
statements.addDestructuringStatements(moduleData, this@DestructuringDeclaration, baseVariable, tmpVariable, localEntries)
}
} }
} }
class DestructuringEntry(
val source: KtSourceElement,
val returnTypeRef: FirTypeRef,
val name: Name,
val annotations: List<FirAnnotation>,
) {
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
companion object : DestructuringContext<DestructuringEntry> {
override val DestructuringEntry.returnTypeRef: FirTypeRef get() = returnTypeRef
override val DestructuringEntry.name: Name get() = name
override val DestructuringEntry.source: KtSourceElement get() = source
override fun DestructuringEntry.extractAnnotationsTo(target: FirAnnotationContainerBuilder) {
target.annotations += annotations
}
}
}
fun MutableList<FirStatement>.addDestructuringStatements(
moduleData: FirModuleData,
multiDeclaration: DestructuringDeclaration,
container: FirVariable,
tmpVariable: Boolean,
localEntries: Boolean,
) {
with(DestructuringEntry) {
addDestructuringStatements(
moduleData,
container,
multiDeclaration.entries,
multiDeclaration.isVar,
tmpVariable,
localEntries
)
}
}
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImplWithoutSource
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
internal fun KtWhenCondition.toFirWhenCondition( internal fun KtWhenCondition.toFirWhenCondition(
@@ -120,14 +119,13 @@ internal fun generateTemporaryVariable(
extractAnnotationsTo, extractAnnotationsTo,
) )
context(DestructuringContext<KtDestructuringDeclarationEntry>)
internal fun generateDestructuringBlock( internal fun generateDestructuringBlock(
moduleData: FirModuleData, moduleData: FirModuleData,
multiDeclaration: KtDestructuringDeclaration, multiDeclaration: KtDestructuringDeclaration,
container: FirVariable, container: FirVariable,
tmpVariable: Boolean, tmpVariable: Boolean,
localEntries: Boolean, localEntries: Boolean,
extractAnnotationsTo: KtAnnotated.(FirAnnotationContainerBuilder) -> Unit,
toFirOrImplicitTypeRef: KtTypeReference?.() -> FirTypeRef,
): FirBlock { ): FirBlock {
return buildBlock { return buildBlock {
source = multiDeclaration.toKtPsiSourceElement() source = multiDeclaration.toKtPsiSourceElement()
@@ -136,50 +134,18 @@ internal fun generateDestructuringBlock(
multiDeclaration, multiDeclaration,
container, container,
tmpVariable, tmpVariable,
localEntries, localEntries
extractAnnotationsTo,
toFirOrImplicitTypeRef
) )
} }
} }
context(DestructuringContext<KtDestructuringDeclarationEntry>)
internal fun MutableList<FirStatement>.addDestructuringStatements( internal fun MutableList<FirStatement>.addDestructuringStatements(
moduleData: FirModuleData, moduleData: FirModuleData,
multiDeclaration: KtDestructuringDeclaration, multiDeclaration: KtDestructuringDeclaration,
container: FirVariable, container: FirVariable,
tmpVariable: Boolean, tmpVariable: Boolean,
localEntries: Boolean, localEntries: Boolean,
extractAnnotationsTo: KtAnnotated.(FirAnnotationContainerBuilder) -> Unit,
toFirOrImplicitTypeRef: KtTypeReference?.() -> FirTypeRef,
) { ) {
if (tmpVariable) { addDestructuringStatements(moduleData, container, multiDeclaration.entries, multiDeclaration.isVar, tmpVariable, localEntries)
this += container
}
val isVar = multiDeclaration.isVar
for ((index, entry) in multiDeclaration.entries.withIndex()) {
val name = if (entry.nameIdentifier?.text == "_") {
SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
} else {
entry.nameAsSafeName
}
val entrySource = entry.toKtPsiSourceElement()
this += buildProperty {
source = entrySource
this.moduleData = moduleData
origin = FirDeclarationOrigin.Source
returnTypeRef = entry.typeReference.toFirOrImplicitTypeRef()
this.name = name
initializer = buildComponentCall {
val componentCallSource = entrySource.fakeElement(KtFakeSourceElementKind.DesugaredComponentFunctionCall)
source = componentCallSource
explicitReceiver = generateResolvedAccessExpression(componentCallSource, container)
componentIndex = index + 1
}
this.isVar = isVar
isLocal = localEntries
status = FirDeclarationStatusImpl(if (localEntries) Visibilities.Local else Visibilities.Public, Modality.FINAL)
symbol = FirPropertySymbol(name)
entry.extractAnnotationsTo(this)
}
}
} }
@@ -164,7 +164,26 @@ open class PsiRawFirBuilder(
} }
} }
protected open inner class Visitor : KtVisitor<FirElement, FirElement?>() { protected open inner class Visitor : KtVisitor<FirElement, FirElement?>(), DestructuringContext<KtDestructuringDeclarationEntry> {
override val KtDestructuringDeclarationEntry.returnTypeRef: FirTypeRef
get() = typeReference.toFirOrImplicitType()
@Suppress("ConflictingExtensionProperty")
override val KtDestructuringDeclarationEntry.name: Name
get() = if (nameIdentifier?.text == "_") {
SpecialNames.UNDERSCORE_FOR_UNUSED_VAR
} else {
nameAsSafeName
}
override val KtDestructuringDeclarationEntry.source: KtSourceElement
get() = toKtPsiSourceElement()
override fun KtDestructuringDeclarationEntry.extractAnnotationsTo(target: FirAnnotationContainerBuilder) {
(this as KtAnnotated).extractAnnotationsTo(target)
}
private inline fun <reified R : FirElement> KtElement?.convertSafe(): R? = private inline fun <reified R : FirElement> KtElement?.convertSafe(): R? =
this?.let { convertElement(it, null)} as? R this?.let { convertElement(it, null)} as? R
@@ -1192,10 +1211,7 @@ open class PsiRawFirBuilder(
destructuringContainerVar, destructuringContainerVar,
tmpVariable = false, tmpVariable = false,
localEntries = false, localEntries = false,
extractAnnotationsTo = { extractAnnotationsTo(it) }, ).apply {
) {
toFirOrImplicitType()
}.apply {
statements.forEach { statements.forEach {
(it as FirProperty).destructuringDeclarationContainerVariable = destructuringContainerVar.symbol (it as FirProperty).destructuringDeclarationContainerVariable = destructuringContainerVar.symbol
} }
@@ -1744,8 +1760,7 @@ open class PsiRawFirBuilder(
multiParameter, multiParameter,
tmpVariable = false, tmpVariable = false,
localEntries = true, localEntries = true,
extractAnnotationsTo = { extractAnnotationsTo(it) }, )
) { toFirOrImplicitType() }
multiParameter multiParameter
} else { } else {
val typeRef = valueParameter.typeReference?.convertSafe() ?: FirImplicitTypeRefImplWithoutSource val typeRef = valueParameter.typeReference?.convertSafe() ?: FirImplicitTypeRefImplWithoutSource
@@ -2596,15 +2611,13 @@ open class PsiRawFirBuilder(
typeRef = ktParameter.typeReference.toFirOrImplicitType(), typeRef = ktParameter.typeReference.toFirOrImplicitType(),
) )
if (multiDeclaration != null) { if (multiDeclaration != null) {
val destructuringBlock = generateDestructuringBlock( blockBuilder.statements.addDestructuringStatements(
baseModuleData, baseModuleData,
multiDeclaration = multiDeclaration, multiDeclaration = multiDeclaration,
container = firLoopParameter, container = firLoopParameter,
tmpVariable = true, tmpVariable = true,
localEntries = true, localEntries = true,
extractAnnotationsTo = { extractAnnotationsTo(it) }, )
) { toFirOrImplicitType() }
blockBuilder.statements.addAll(destructuringBlock.statements)
} else { } else {
blockBuilder.statements.add(firLoopParameter) blockBuilder.statements.add(firLoopParameter)
} }
@@ -2968,10 +2981,7 @@ open class PsiRawFirBuilder(
baseVariable, baseVariable,
tmpVariable = true, tmpVariable = true,
localEntries = true, localEntries = true,
extractAnnotationsTo = { extractAnnotationsTo(it) }, )
) {
toFirOrImplicitType()
}
} }
override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, data: FirElement?): FirElement { override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, data: FirElement?): FirElement {
@@ -299,6 +299,18 @@ fun generateResolvedAccessExpression(source: KtSourceElement?, variable: FirVari
} }
} }
fun FirVariable.toComponentCall(
entrySource: KtSourceElement?,
index: Int,
): FirComponentCall {
return buildComponentCall {
val componentCallSource = entrySource?.fakeElement(KtFakeSourceElementKind.DesugaredComponentFunctionCall)
source = componentCallSource
explicitReceiver = generateResolvedAccessExpression(componentCallSource, this@toComponentCall)
componentIndex = index + 1
}
}
val FirClassBuilder.ownerRegularOrAnonymousObjectSymbol val FirClassBuilder.ownerRegularOrAnonymousObjectSymbol
get() = when (this) { get() = when (this) {
is FirAnonymousObjectBuilder -> symbol is FirAnonymousObjectBuilder -> symbol
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.fir.builder
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.name.Name
interface DestructuringContext<T> {
val T.returnTypeRef: FirTypeRef
val T.name: Name
val T.source: KtSourceElement
fun T.extractAnnotationsTo(target: FirAnnotationContainerBuilder)
}
context(DestructuringContext<T>)
fun <T> MutableList<FirStatement>.addDestructuringStatements(
moduleData: FirModuleData,
container: FirVariable,
entries: List<T>,
isVar: Boolean,
tmpVariable: Boolean,
localEntries: Boolean,
) {
if (tmpVariable) {
this += container
}
for ((index, entry) in entries.withIndex()) {
this += buildProperty {
this.moduleData = moduleData
origin = FirDeclarationOrigin.Source
returnTypeRef = entry.returnTypeRef
name = entry.name
initializer = container.toComponentCall(entry.source, index)
this.isVar = isVar
symbol = FirPropertySymbol(entry.name)
source = entry.source
isLocal = localEntries
status = FirDeclarationStatusImpl(if (localEntries) Visibilities.Local else Visibilities.Public, Modality.FINAL)
entry.extractAnnotationsTo(this)
}
}
}