From 4af32b8d3642752a4c2ecbb1a97f6f54440d8491 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Thu, 17 Nov 2022 15:26:15 +0100 Subject: [PATCH] K2 Scripting, IR: non-class based scripts support in IR --- .../jetbrains/kotlin/backend/common/Lower.kt | 4 +- .../js/lower/ScriptRemoveReceiverLowering.kt | 2 +- .../backend/jvm/lower/ScriptLowering.kt | 62 ++++++++++++++++--- .../psi2ir/generators/ScriptGenerator.kt | 6 +- .../kotlin/ir/declarations/IrScript.kt | 8 +-- .../ir/declarations/impl/IrScriptImpl.kt | 4 +- .../ir/util/DeepCopyIrTreeWithSymbols.kt | 2 +- .../jetbrains/kotlin/ir/generator/IrTree.kt | 6 +- 8 files changed, 71 insertions(+), 23 deletions(-) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Lower.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Lower.kt index 5f5e45201cf..4cee3bcf911 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Lower.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Lower.kt @@ -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) } } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ScriptRemoveReceiverLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ScriptRemoveReceiverLowering.kt index 41928691dea..e237b904293 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ScriptRemoveReceiverLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ScriptRemoveReceiverLowering.kt @@ -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 } diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt index 45876d0e067..cf5e732adcf 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt @@ -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().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()!!.also { constructor -> + (irScript.constructor?.patchForClass()?.safeAs() ?: 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) { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt index eff95dee184..311f85a2ea7 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt @@ -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) diff --git a/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/declarations/IrScript.kt b/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/declarations/IrScript.kt index e1d6be1a1f5..cd6861c20b8 100644 --- a/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/declarations/IrScript.kt +++ b/compiler/ir/ir.tree/gen/org/jetbrains/kotlin/ir/declarations/IrScript.kt @@ -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 @@ -53,7 +53,7 @@ abstract class IrScript : IrDeclarationBase(), IrDeclarationWithName, IrDeclarat override fun acceptChildren(visitor: IrElementVisitor, 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 transformChildren(transformer: IrElementTransformer, 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) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrScriptImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrScriptImpl.kt index 97e44c067d9..ed7d8d4222a 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrScriptImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrScriptImpl.kt @@ -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 override lateinit var implicitReceiversParameters: List override lateinit var providedProperties: List diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt index bb65a57b79a..f49f0ffd702 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt @@ -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 diff --git a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/IrTree.kt b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/IrTree.kt index cfe19b456eb..cc7eaf317ed 100644 --- a/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/IrTree.kt +++ b/compiler/ir/ir.tree/tree-generator/src/org/jetbrains/kotlin/ir/generator/IrTree.kt @@ -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