K2 Scripting: wrap script statements into blocks

(reuse anonymous initializers as block wrappers) so the top-level script
elements are all declarations now. Rename the property accordingly (
together with the previous commit).
It makes script more similar to the class and thus simplify e.g.
control flow analysis and resolve code.
This commit is contained in:
Ilya Chernikov
2023-11-22 16:40:51 +01:00
committed by Space Team
parent c9aee5bf09
commit eeb723eb01
20 changed files with 224 additions and 156 deletions
@@ -518,19 +518,19 @@ class Fir2IrConverter(
addDeclarationToParentIfNeeded(irScript)
declarationStorage.withScope(irScript.symbol) {
irScript.parent = parent
for (scriptStatement in declaration.declarations) {
when (scriptStatement) {
for (scriptDeclaration in declaration.declarations) {
when (scriptDeclaration) {
is FirRegularClass -> {
registerClassAndNestedClasses(scriptStatement, irScript)
processClassAndNestedClassHeaders(scriptStatement)
registerClassAndNestedClasses(scriptDeclaration, irScript)
processClassAndNestedClassHeaders(scriptDeclaration)
}
is FirTypeAlias -> classifierStorage.createAndCacheIrTypeAlias(scriptStatement, irScript)
is FirTypeAlias -> classifierStorage.createAndCacheIrTypeAlias(scriptDeclaration, irScript)
else -> {}
}
}
for (scriptStatement in declaration.declarations) {
if (scriptStatement is FirDeclaration) {
processMemberDeclaration(scriptStatement, containingClass = null, irScript, delegateFieldToPropertyMap = null)
for (scriptDeclaration in declaration.declarations) {
if (scriptDeclaration !is FirAnonymousInitializer) {
processMemberDeclaration(scriptDeclaration, containingClass = null, irScript, delegateFieldToPropertyMap = null)
}
}
}
@@ -255,8 +255,8 @@ class Fir2IrVisitor(
conversionScope.withParent(irScript) {
val destructComposites = mutableMapOf<FirVariableSymbol<*>, IrComposite>()
for (statement in script.declarations) {
val irStatement = if (statement is FirDeclaration) {
when {
if (statement !is FirAnonymousInitializer) {
val irStatement = when {
statement is FirProperty && statement.name == SpecialNames.UNDERSCORE_FOR_UNUSED_VAR -> {
continue
}
@@ -311,10 +311,12 @@ class Fir2IrVisitor(
statement.accept(this@Fir2IrVisitor, null) as? IrDeclaration
}
}
irScript.statements.add(irStatement!!)
} else {
statement.toIrStatement()
statement.body?.statements?.mapNotNull { it.toIrStatement() }?.let {
irScript.statements.addAll(it)
}
}
irScript.statements.add(irStatement!!)
}
}
for (configurator in session.extensionService.fir2IrScriptConfigurators) {
@@ -1276,50 +1276,81 @@ open class PsiRawFirBuilder(
fileName: String,
sourceFile: KtSourceFile?,
setup: FirScriptBuilder.() -> Unit = {},
): FirScript = buildScript {
source = script.toFirSourceElement()
moduleData = baseModuleData
origin = FirDeclarationOrigin.Source
name = Name.special("<script-$fileName>")
symbol = FirScriptSymbol(context.packageFqName.child(name))
withContainerSymbol(symbol) {
for (declaration in script.declarations) {
when (declaration) {
is KtScriptInitializer -> {
declaration.body?.let { declarations.add(it.toFirStatement()) }
}
is KtDestructuringDeclaration -> {
val destructuringContainerVar = generateTemporaryVariable(
baseModuleData,
declaration.toFirSourceElement(),
"destruct",
declaration.initializer.toFirExpression { ConeSyntaxDiagnostic("Initializer required for destructuring declaration") },
origin = FirDeclarationOrigin.Synthetic.ScriptTopLevelDestructuringDeclarationContainer,
extractAnnotationsTo = { extractAnnotationsTo(it) }
).apply {
isDestructuringDeclarationContainerVariable = true
}
declarations.add(destructuringContainerVar)
): FirScript {
val scriptName = Name.special("<script-$fileName>")
val scriptSymbol = FirScriptSymbol(context.packageFqName.child(scriptName))
declarations.addDestructuringVariables(
moduleData,
declaration,
destructuringContainerVar,
tmpVariable = false,
localEntries = false,
) {
(it as FirProperty).destructuringDeclarationContainerVariable = destructuringContainerVar.symbol
return buildScript {
source = script.toFirSourceElement()
moduleData = baseModuleData
origin = FirDeclarationOrigin.Source
name = scriptName
symbol = scriptSymbol
val scriptDeclarationsIter = script.declarations.listIterator()
withContainerSymbol(symbol) {
while (scriptDeclarationsIter.hasNext()) {
val declaration = scriptDeclarationsIter.next()
val isLast = !scriptDeclarationsIter.hasNext()
val declarationSource = declaration.toFirSourceElement()
when (declaration) {
is KtScriptInitializer -> {
val firBlock =
if (isLast) {
// the last one need to be analyzed in script configurator to decide on result property
// therefore no lazy conversion in this case
withForcedLocalContext { declaration.body.toFirBlock() }
} else {
buildOrLazyBlock { withForcedLocalContext { declaration.body.toFirBlock() } }
}
declarations.add(
buildAnonymousInitializer {
moduleData = baseModuleData
origin = FirDeclarationOrigin.Source
source = declarationSource
body = firBlock
declaration.extractAnnotationsTo(this)
}
)
}
is KtDestructuringDeclaration -> {
val destructuringContainerVar = generateTemporaryVariable(
baseModuleData,
declarationSource,
"destruct",
declaration.initializer.toFirExpression { ConeSyntaxDiagnostic("Initializer required for destructuring declaration") },
origin = FirDeclarationOrigin.Synthetic.ScriptTopLevelDestructuringDeclarationContainer,
extractAnnotationsTo = { extractAnnotationsTo(it) }
).apply {
isDestructuringDeclarationContainerVariable = true
}
declarations.add(destructuringContainerVar)
declarations.addDestructuringVariables(
moduleData,
declaration,
destructuringContainerVar,
tmpVariable = false,
localEntries = false,
) {
(it as FirProperty).destructuringDeclarationContainerVariable = destructuringContainerVar.symbol
}
}
else -> {
val firStatement = declaration.toFirStatement()
if (firStatement is FirDeclaration) {
declarations.add(firStatement)
} else {
error("unexpected declaration type in script")
}
}
}
else -> {
declarations.add(declaration.toFirStatement())
}
}
}
setup()
if (sourceFile != null) {
for (configurator in baseSession.extensionService.scriptConfigurators) {
with(configurator) { configure(sourceFile) }
setup()
if (sourceFile != null) {
for (configurator in baseSession.extensionService.scriptConfigurators) {
with(configurator) { configure(sourceFile) }
}
}
}
}
@@ -37,28 +37,43 @@ FILE: script.kts
^build2 Builder#().apply#(action#)
}
build#(<L> = build@fun <implicit>.<anonymous>(): <implicit> <inline=Unknown> {
version# = String(123)
local final? class A : R|kotlin/Any| {
public? [ContainingClassKey=A] constructor(): R|<local>/A| {
super<R|kotlin/Any|>()
}
public? final? fun doo(): R|kotlin/Unit| {
init {
build#(<L> = build@fun <implicit>.<anonymous>(): <implicit> <inline=Unknown> {
version# = String(123)
local final? class A : R|kotlin/Any| {
public? [ContainingClassKey=A] constructor(): R|<local>/A| {
super<R|kotlin/Any|>()
}
public? final? fun doo(): R|kotlin/Unit| {
}
}
execute#()
}
execute#()
)
}
)
+=(version#, IntegerLiteral(123))
init {
+=(version#, IntegerLiteral(123))
}
public? final? val builder: <implicit> = build#(<L> = build@fun <implicit>.<anonymous>(): <implicit> <inline=Unknown> {
version# = String(321)
}
)
public? get(): <implicit>
println#()
builder#.version# = String()
builder#.execute#()
init {
println#()
}
init {
builder#.version# = String()
}
init {
builder#.execute#()
}
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol
import org.jetbrains.kotlin.fir.visitors.FirTransformer
@@ -30,9 +29,9 @@ abstract class FirScript : FirDeclaration(), FirControlFlowGraphOwner {
abstract override val attributes: FirDeclarationAttributes
abstract override val controlFlowGraphReference: FirControlFlowGraphReference?
abstract val name: Name
abstract val declarations: List<FirStatement>
abstract val declarations: List<FirDeclaration>
abstract override val symbol: FirScriptSymbol
abstract val parameters: List<FirVariable>
abstract val parameters: List<FirProperty>
abstract val contextReceivers: List<FirContextReceiver>
abstract val resultPropertyName: Name?
@@ -47,9 +46,13 @@ abstract class FirScript : FirDeclaration(), FirControlFlowGraphOwner {
abstract override fun replaceControlFlowGraphReference(newControlFlowGraphReference: FirControlFlowGraphReference?)
abstract fun replaceDeclarations(newDeclarations: List<FirStatement>)
abstract fun replaceDeclarations(newDeclarations: List<FirDeclaration>)
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirScript
abstract fun <D> transformDeclarations(transformer: FirTransformer<D>, data: D): FirScript
abstract fun <D> transformParameters(transformer: FirTransformer<D>, data: D): FirScript
abstract fun <D> transformContextReceivers(transformer: FirTransformer<D>, data: D): FirScript
}
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirScriptImpl
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol
import org.jetbrains.kotlin.name.Name
@@ -32,9 +31,9 @@ class FirScriptBuilder : FirAnnotationContainerBuilder {
lateinit var origin: FirDeclarationOrigin
var attributes: FirDeclarationAttributes = FirDeclarationAttributes()
lateinit var name: Name
val declarations: MutableList<FirStatement> = mutableListOf()
val declarations: MutableList<FirDeclaration> = mutableListOf()
lateinit var symbol: FirScriptSymbol
val parameters: MutableList<FirVariable> = mutableListOf()
val parameters: MutableList<FirProperty> = mutableListOf()
val contextReceivers: MutableList<FirContextReceiver> = mutableListOf()
var resultPropertyName: Name? = null
@@ -47,7 +46,7 @@ class FirScriptBuilder : FirAnnotationContainerBuilder {
origin,
attributes,
name,
declarations.toMutableOrEmpty(),
declarations,
symbol,
parameters,
contextReceivers.toMutableOrEmpty(),
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.fir.MutableOrEmptyList
import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol
import org.jetbrains.kotlin.fir.visitors.FirTransformer
@@ -33,9 +32,9 @@ internal class FirScriptImpl(
override val origin: FirDeclarationOrigin,
override val attributes: FirDeclarationAttributes,
override val name: Name,
override var declarations: MutableOrEmptyList<FirStatement>,
override val declarations: MutableList<FirDeclaration>,
override val symbol: FirScriptSymbol,
override val parameters: MutableList<FirVariable>,
override val parameters: MutableList<FirProperty>,
override var contextReceivers: MutableOrEmptyList<FirContextReceiver>,
override val resultPropertyName: Name?,
) : FirScript() {
@@ -58,8 +57,8 @@ internal class FirScriptImpl(
transformAnnotations(transformer, data)
controlFlowGraphReference = controlFlowGraphReference?.transform(transformer, data)
transformDeclarations(transformer, data)
parameters.transformInplace(transformer, data)
contextReceivers.transformInplace(transformer, data)
transformParameters(transformer, data)
transformContextReceivers(transformer, data)
return this
}
@@ -73,6 +72,16 @@ internal class FirScriptImpl(
return this
}
override fun <D> transformParameters(transformer: FirTransformer<D>, data: D): FirScriptImpl {
parameters.transformInplace(transformer, data)
return this
}
override fun <D> transformContextReceivers(transformer: FirTransformer<D>, data: D): FirScriptImpl {
contextReceivers.transformInplace(transformer, data)
return this
}
override fun replaceAnnotations(newAnnotations: List<FirAnnotation>) {
annotations = newAnnotations.toMutableOrEmpty()
}
@@ -81,7 +90,8 @@ internal class FirScriptImpl(
controlFlowGraphReference = newControlFlowGraphReference
}
override fun replaceDeclarations(newDeclarations: List<FirStatement>) {
declarations = newDeclarations.toMutableOrEmpty()
override fun replaceDeclarations(newDeclarations: List<FirDeclaration>) {
declarations.clear()
declarations.addAll(newDeclarations)
}
}
@@ -494,10 +494,10 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
script.configure {
+name
+FieldList("declarations", statement, withReplace = true, useMutableOrEmpty = true).withTransform()
+declarations.withTransform().withReplace()
+symbol("FirScriptSymbol")
+fieldList("parameters", variable, withReplace = false)
+fieldList(contextReceiver, useMutableOrEmpty = true)
+fieldList("parameters", property).withTransform()
+fieldList(contextReceiver, useMutableOrEmpty = true).withTransform()
+field("resultPropertyName", nameType, nullable = true)
}