K2 Scripting, IR: non-class based scripts support in IR

This commit is contained in:
Ilya Chernikov
2022-11-17 15:26:15 +01:00
committed by Space Team
parent cc9a7480a2
commit 4af32b8d36
8 changed files with 71 additions and 23 deletions
@@ -192,7 +192,7 @@ private open class BodyLoweringVisitor(
}
override fun visitScript(declaration: IrScript, data: IrDeclaration?) {
declaration.thisReceiver.accept(this, declaration)
declaration.thisReceiver?.accept(this, declaration)
ArrayList(declaration.statements).forEach { it.accept(this, declaration) }
}
}
@@ -308,7 +308,7 @@ interface DeclarationTransformer : FileLoweringPass {
}
declaration.statements.transformSubsetFlat(transformer::transformFlatRestricted)
declaration.thisReceiver.accept(this, null)
declaration.thisReceiver?.accept(this, null)
}
}
}
@@ -45,7 +45,7 @@ class ScriptRemoveReceiverLowering(val context: CommonBackendContext) : FileLowe
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
return if (expression.symbol === script.thisReceiver.symbol) expression.nullConst()
return if (expression.symbol === script.thisReceiver?.symbol) expression.nullConst()
else expression
}
@@ -32,18 +32,22 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.interpreter.toIrConst
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmBackendErrors
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -88,12 +92,16 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
startOffset = 0
endOffset = fileEntry.maxOffset
origin = IrDeclarationOrigin.SCRIPT_CLASS
name = irScript.name
name = irScript.name.let {
if (it.isSpecial) {
NameUtils.getScriptNameForFile(irScript.name.asStringStripSpecialMarkers().removePrefix("script-"))
} else it
}
kind = ClassKind.CLASS
visibility = DescriptorVisibilities.PUBLIC
modality = Modality.FINAL
}.also { irScriptClass ->
irScriptClass.superTypes += irScript.baseClass
irScriptClass.superTypes += (irScript.baseClass ?: context.irBuiltIns.anyNType)
irScriptClass.parent = irFile
irScriptClass.metadata = irScript.metadata
irScript.targetClass = irScriptClass.symbol
@@ -111,8 +119,10 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
override fun visitClass(declaration: IrClass) {
if (declaration is IrClassImpl && !declaration.isInner) {
val closure = annotator.getClassClosure(declaration)
val scriptsReceivers = mutableSetOf(irScript.thisReceiver.type)
irScript.earlierScripts?.forEach { scriptsReceivers.add(it.owner.thisReceiver.type) }
val scriptsReceivers = mutableSetOf<IrType>().also {
it.addIfNotNull(irScript.thisReceiver?.type)
}
irScript.earlierScripts?.forEach { scriptsReceivers.addIfNotNull(it.owner.thisReceiver?.type) }
irScript.implicitReceiversParameters.forEach {
scriptsReceivers.add(it.type)
scriptsReceivers.add(typeRemapper.remapType(it.type))
@@ -208,14 +218,14 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
.transform(lambdaPatcher, ScriptFixLambdasTransformerContext())
}
irScript.constructor?.patchForClass()?.safeAs<IrConstructor>()!!.also { constructor ->
(irScript.constructor?.patchForClass()?.safeAs<IrConstructor>() ?: createConstructor(irScriptClass, irScript)).also { constructor ->
val explicitParamsStartIndex = if (irScript.earlierScriptsParameter == null) 0 else 1
val explicitParameters = constructor.valueParameters.subList(
explicitParamsStartIndex,
irScript.explicitCallParameters.size + explicitParamsStartIndex
)
constructor.body = context.createIrBuilder(constructor.symbol).irBlockBody {
val baseClassCtor = irScript.baseClass.classOrNull?.owner?.constructors?.firstOrNull()
val baseClassCtor = irScript.baseClass?.classOrNull?.owner?.constructors?.firstOrNull()
// TODO: process situation with multiple constructors (should probably be an error)
if (baseClassCtor == null) {
+irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single())
@@ -297,6 +307,32 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
}
}
private fun createConstructor(
irScriptClass: IrClass,
irScript: IrScript
): IrConstructor =
with(IrFunctionBuilder().apply {
isPrimary = true
returnType = irScriptClass.thisReceiver!!.type as IrSimpleType
}) {
irScriptClass.factory.createConstructor(
startOffset, endOffset, origin,
IrConstructorSymbolImpl(),
SpecialNames.INIT,
visibility, returnType,
isInline = isInline, isExternal = isExternal, isPrimary = isPrimary, isExpect = isExpect,
containerSource = containerSource
)
}.also { irConstructor ->
irConstructor.valueParameters = buildList {
addIfNotNull(irScript.earlierScriptsParameter)
addAll(irScript.explicitCallParameters)
addAll(irScript.implicitReceiversParameters)
addAll(irScript.providedPropertiesParameters)
}
irConstructor.parent = irScript
}
private val scriptingJvmPackage by lazy(LazyThreadSafetyMode.PUBLICATION) {
IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment(context.state.module, FqName("kotlin.script.experimental.jvm"))
}
@@ -419,7 +455,19 @@ private class ScriptToClassTransformer(
}
val scriptClassReceiver =
irScript.thisReceiver.transform(this, ScriptToClassTransformerContext(null, null, null, false))
irScript.thisReceiver?.transform(this, ScriptToClassTransformerContext(null, null, null, false)) ?: run {
context.symbolTable.enterScope(irScriptClass)
val thisType = IrSimpleTypeImpl(irScriptClass.symbol, false, emptyList(), emptyList())
context.symbolTable.irFactory.createValueParameter(
irScriptClass.startOffset, irScriptClass.endOffset, IrDeclarationOrigin.INSTANCE_RECEIVER, IrValueParameterSymbolImpl(),
SpecialNames.THIS, UNDEFINED_PARAMETER_INDEX, thisType,
varargElementType = null, isCrossinline = false, isNoinline = false,
isHidden = false, isAssignable = false
).also {
it.parent = irScriptClass
context.symbolTable.leaveScope(irScriptClass)
}
}
private fun IrDeclaration.transformParent() {
if (parent == irScript) {
@@ -86,7 +86,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
it.owner != irScript && it.descriptor !in importedScripts
}
irScript.earlierScripts?.forEach {
context.symbolTable.introduceValueParameter(it.owner.thisReceiver)
context.symbolTable.introduceValueParameter(it.owner.thisReceiver!!)
}
fun createValueParameter(valueParameterDescriptor: ValueParameterDescriptor): IrValueParameter {
@@ -142,7 +142,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
irScript.constructor = with(IrFunctionBuilder().apply {
isPrimary = true
returnType = irScript.thisReceiver.type as IrSimpleType
returnType = irScript.thisReceiver!!.type as IrSimpleType
}) {
irScript.factory.createConstructor(
startOffset, endOffset, origin,
@@ -240,7 +240,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
).apply {
value = irComponentCall
receiver = IrGetValueImpl(
ktEntry.startOffsetSkippingComments, ktEntry.endOffset, irScript.thisReceiver.symbol
ktEntry.startOffsetSkippingComments, ktEntry.endOffset, irScript.thisReceiver!!.symbol
)
}
irBlock.statements.add(irComponentInitializer)
@@ -26,9 +26,9 @@ abstract class IrScript : IrDeclarationBase(), IrDeclarationWithName, IrDeclarat
IrStatementContainer, IrMetadataSourceOwner {
abstract override val symbol: IrScriptSymbol
abstract var thisReceiver: IrValueParameter
abstract var thisReceiver: IrValueParameter?
abstract var baseClass: IrType
abstract var baseClass: IrType?
abstract var explicitCallParameters: List<IrValueParameter>
@@ -53,7 +53,7 @@ abstract class IrScript : IrDeclarationBase(), IrDeclarationWithName, IrDeclarat
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
statements.forEach { it.accept(visitor, data) }
thisReceiver.accept(visitor, data)
thisReceiver?.accept(visitor, data)
explicitCallParameters.forEach { it.accept(visitor, data) }
implicitReceiversParameters.forEach { it.accept(visitor, data) }
providedPropertiesParameters.forEach { it.accept(visitor, data) }
@@ -62,7 +62,7 @@ abstract class IrScript : IrDeclarationBase(), IrDeclarationWithName, IrDeclarat
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
statements.transformInPlace(transformer, data)
thisReceiver = thisReceiver.transform(transformer, data)
thisReceiver = thisReceiver?.transform(transformer, data)
explicitCallParameters = explicitCallParameters.transformIfNeeded(transformer, data)
implicitReceiversParameters = implicitReceiversParameters.transformIfNeeded(transformer,
data)
@@ -43,9 +43,9 @@ class IrScriptImpl(
override var metadata: MetadataSource? = null
override lateinit var thisReceiver: IrValueParameter
override var thisReceiver: IrValueParameter? = null
override var baseClass: IrType? = null
override lateinit var baseClass: IrType
override lateinit var explicitCallParameters: List<IrValueParameter>
override lateinit var implicitReceiversParameters: List<IrValueParameter>
override lateinit var providedProperties: List<IrPropertySymbol>
@@ -130,7 +130,7 @@ open class DeepCopyIrTreeWithSymbols(
declaration.startOffset,
declaration.endOffset
).also { scriptCopy ->
scriptCopy.thisReceiver = declaration.thisReceiver.transform()
scriptCopy.thisReceiver = declaration.thisReceiver?.transform()
declaration.statements.mapTo(scriptCopy.statements) { it.transform() }
scriptCopy.earlierScripts = declaration.earlierScripts
scriptCopy.earlierScriptsParameter = declaration.earlierScriptsParameter
@@ -398,8 +398,8 @@ object IrTree : AbstractTreeBuilder() {
+symbol(scriptSymbolType)
// NOTE: is the result of the FE conversion, because there script interpreted as a class and has receiver
// TODO: consider removing from here and handle appropriately in the lowering
+field("thisReceiver", valueParameter, mutable = true, isChild = true)
+field("baseClass", irTypeType, mutable = true)
+field("thisReceiver", valueParameter, mutable = true, isChild = true, nullable = true) // K1
+field("baseClass", irTypeType, mutable = true, nullable = true) // K1
+listField("explicitCallParameters", valueParameter, mutability = Var, isChild = true)
+listField("implicitReceiversParameters", valueParameter, mutability = Var, isChild = true)
+listField("providedProperties", propertySymbolType, mutability = Var)
@@ -408,7 +408,7 @@ object IrTree : AbstractTreeBuilder() {
+field("earlierScriptsParameter", valueParameter, mutable = true, nullable = true, isChild = true)
+listField("earlierScripts", scriptSymbolType, mutability = Var, nullable = true)
+field("targetClass", classSymbolType, mutable = true, nullable = true)
+field("constructor", constructor, mutable = true, nullable = true)
+field("constructor", constructor, mutable = true, nullable = true) // K1
}
val simpleFunction: ElementConfig by element(Declaration) {
visitorParent = function