diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt index 50df78604f4..56c5c02bcf4 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt @@ -48,7 +48,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations -class JvmGeneratorExtensionsImpl(private val generateFacades: Boolean = true) : GeneratorExtensions(), JvmGeneratorExtensions { +open class JvmGeneratorExtensionsImpl(private val generateFacades: Boolean = true) : GeneratorExtensions(), JvmGeneratorExtensions { override val classNameOverride: MutableMap = mutableMapOf() override val samConversion: SamConversion diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt index 4c31dd2e6eb..c07068dabdc 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt @@ -37,17 +37,23 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl +import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions import org.jetbrains.kotlin.psi2ir.generators.generateTypicalIrProviderList import org.jetbrains.kotlin.resolve.CleanableBindingContext -class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory { +open class JvmIrCodegenFactory( + private val phaseConfig: PhaseConfig, + private val externalMangler: JvmManglerDesc? = null, + private val externalSymbolTable: SymbolTable? = null, + private val jvmGeneratorExtensions: JvmGeneratorExtensionsImpl = JvmGeneratorExtensionsImpl() +) : CodegenFactory { data class JvmIrBackendInput( val state: GenerationState, val irModuleFragment: IrModuleFragment, val symbolTable: SymbolTable, val phaseConfig: PhaseConfig, val irProviders: List, - val extensions: JvmGeneratorExtensions, + val extensions: JvmGeneratorExtensionsImpl, val backendExtension: JvmBackendExtension, val notifyCodegenStart: () -> Unit, ) @@ -59,18 +65,22 @@ class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory @JvmOverloads fun convertToIr(state: GenerationState, files: Collection, ignoreErrors: Boolean = false): JvmIrBackendInput { - val extensions = JvmGeneratorExtensionsImpl() - val mangler = JvmManglerDesc(MainFunctionDetector(state.bindingContext, state.languageVersionSettings)) + val (mangler, symbolTable) = + if (externalSymbolTable != null) externalMangler!! to externalSymbolTable + else { + val mangler = JvmManglerDesc(MainFunctionDetector(state.bindingContext, state.languageVersionSettings)) + val symbolTable = SymbolTable(JvmIdSignatureDescriptor(mangler), IrFactoryImpl, JvmNameProvider) + mangler to symbolTable + } val psi2ir = Psi2IrTranslator(state.languageVersionSettings, Psi2IrConfiguration(ignoreErrors)) - val symbolTable = SymbolTable(JvmIdSignatureDescriptor(mangler), IrFactoryImpl, JvmNameProvider) val messageLogger = state.configuration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None - val psi2irContext = psi2ir.createGeneratorContext(state.module, state.bindingContext, symbolTable, extensions) + val psi2irContext = psi2ir.createGeneratorContext(state.module, state.bindingContext, symbolTable, jvmGeneratorExtensions) val pluginExtensions = IrGenerationExtension.getInstances(state.project) val functionFactory = IrFunctionFactory(psi2irContext.irBuiltIns, symbolTable) psi2irContext.irBuiltIns.functionFactory = functionFactory val stubGenerator = - DeclarationStubGeneratorImpl(psi2irContext.moduleDescriptor, symbolTable, state.languageVersionSettings, extensions) + DeclarationStubGeneratorImpl(psi2irContext.moduleDescriptor, symbolTable, state.languageVersionSettings, jvmGeneratorExtensions) val frontEndContext = object : TranslationPluginContext { override val moduleDescriptor: ModuleDescriptor get() = psi2irContext.moduleDescriptor @@ -153,7 +163,7 @@ class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory symbolTable, phaseConfig, irProviders, - extensions, + jvmGeneratorExtensions, JvmBackendExtension.Default, ) {} } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt index 4fe57858f52..eee228e8f2e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* +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.types.* @@ -29,6 +30,7 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.util.OperatorNameConventions internal val scriptsToClassesPhase = makeCustomPhase( name = "ScriptsToClasses", @@ -77,12 +79,13 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) { irScriptClass.superTypes += irScript.baseClass irScriptClass.parent = irFile irScriptClass.metadata = irScript.metadata + irScript.targetClass = irScriptClass.symbol } } private fun finalizeScriptClass(irScriptClass: IrClass, irScript: IrScript, symbolRemapper: ScriptsToClassesSymbolRemapper) { val typeRemapper = SimpleTypeRemapper(symbolRemapper) - val scriptTransformer = ScriptToClassTransformer(irScript, irScriptClass, symbolRemapper, typeRemapper) + val scriptTransformer = ScriptToClassTransformer(irScript, irScriptClass, symbolRemapper, typeRemapper, context) irScriptClass.thisReceiver = irScript.thisReceiver.run { transform(scriptTransformer, null) } @@ -112,6 +115,9 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) { } } + irScript.earlierScriptsParameter?.let { earlierScriptdParameter -> + addConstructorParameter(earlierScriptdParameter, false) + } irScript.explicitCallParameters.forEach { addConstructorParameter(it, false) } irScript.implicitReceiversParameters.forEach { addConstructorParameter(it, false) } irScript.providedProperties.forEach { addConstructorParameter(it.first, false) } @@ -300,7 +306,8 @@ private class ScriptToClassTransformer( val irScript: IrScript, val irScriptClass: IrClass, val symbolRemapper: SymbolRemapper, - val typeRemapper: TypeRemapper + val typeRemapper: TypeRemapper, + val context: JvmBackendContext ) : IrElementTransformerVoid() { private fun IrType.remapType() = typeRemapper.remapType(this) @@ -425,6 +432,74 @@ private class ScriptToClassTransformer( } visitExpression(expression) } + + private fun getAccessCallForEarlierScript(expression: IrDeclarationReference, maybeScriptType: IrType): IrExpression? { + if (irScript.earlierScripts?.isEmpty() != false) return null + val scriptSymbol = maybeScriptType.classifierOrNull ?: return null + val scriptSymbolOwner = scriptSymbol.owner + val earlierScriptIndex = when { + scriptSymbolOwner is IrScript -> + irScript.earlierScripts!!.indexOfFirst { it == scriptSymbol } + (scriptSymbolOwner as? IrClass)?.origin == IrDeclarationOrigin.SCRIPT_CLASS -> { + irScript.earlierScripts!!.indexOfFirst { it.owner.targetClass == scriptSymbol } + } + else -> return null + } + if (earlierScriptIndex >= 0) { + val objArray = context.irBuiltIns.arrayClass + val objArrayGet = objArray.functions.single { it.owner.name == OperatorNameConventions.GET } + val builder = context.createIrBuilder(expression.symbol) + val getPrevScriptObjectExpression = builder.irCall(objArrayGet).apply { + dispatchReceiver = builder.irGet(objArray.defaultType, irScript.earlierScriptsParameter!!.symbol) + putValueArgument(0, earlierScriptIndex.toIrConst(objArrayGet.owner.valueParameters.first().type)) + } + val prevScriptClassType = + when { + scriptSymbolOwner is IrScript -> scriptSymbolOwner.targetClass?.owner + (scriptSymbolOwner as? IrClass)?.origin == IrDeclarationOrigin.SCRIPT_CLASS -> scriptSymbolOwner + else -> null + } + return if (prevScriptClassType == null) getPrevScriptObjectExpression + else builder.irImplicitCast(getPrevScriptObjectExpression, prevScriptClassType.defaultType) + } + return null + } + + override fun visitGetField(expression: IrGetField): IrExpression { + if (irScript.earlierScripts != null) { + val receiver = expression.receiver + if (receiver is IrGetValue && receiver.symbol.owner.name == Name.special("")) { + val newReceiver = getAccessCallForEarlierScript(expression, receiver.type) + if (newReceiver != null) { + val newGetField = + IrGetFieldImpl(expression.startOffset, expression.endOffset, expression.symbol, expression.type, newReceiver) + return super.visitGetField(newGetField) + } + } + } + return super.visitGetField(expression) + } + + override fun visitCall(expression: IrCall): IrExpression { + if (irScript.earlierScripts != null) { + val target = expression.symbol.owner + val receiver: IrValueParameter? = target.dispatchReceiverParameter + if (target.origin == IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR && receiver?.name == Name.special("")) { + val newReceiver = getAccessCallForEarlierScript(expression, receiver.type) + if (newReceiver != null) { + val builder = context.createIrBuilder(expression.symbol) + val newCall = builder.irCall(expression.symbol, target.returnType, origin = expression.origin).also { + it.copyTypeAndValueArgumentsFrom(expression) + it.dispatchReceiver = newReceiver + } + return super.visitCall(newCall) + } + } + } + return super.visitCall(expression) + } + + } private class ScriptsToClassesSymbolRemapper( diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt index 7f2178fadeb..21d6118665b 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorExtensions.kt @@ -41,5 +41,5 @@ open class GeneratorExtensions : StubGeneratorExtensions() { open val shouldPreventDeprecatedIntegerValueTypeLiteralConversion: Boolean get() = false - open fun getPreviousScripts(): List = emptyList() + open fun getPreviousScripts(): List? = null } 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 623617e6a75..ac7d40d1d25 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 @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.psi2ir.generators import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ScriptDescriptor +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.assertCast import org.jetbrains.kotlin.ir.declarations.DescriptorMetadataSource import org.jetbrains.kotlin.ir.declarations.IrDeclaration @@ -18,10 +19,13 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.toArrayOrPrimitiveArrayType import org.jetbrains.kotlin.ir.util.indexOrMinusOne import org.jetbrains.kotlin.ir.util.isCrossinline import org.jetbrains.kotlin.ir.util.isNoinline import org.jetbrains.kotlin.ir.util.varargElementType +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.psi.KtScriptInitializer @@ -39,27 +43,12 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG fun generateScriptDeclaration(ktScript: KtScript): IrDeclaration? { val descriptor = getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktScript) as ScriptDescriptor - val previousScripts = context.extensions.getPreviousScripts() - return context.symbolTable.declareScript(descriptor).buildWithScope { irScript -> irScript.metadata = DescriptorMetadataSource.Class(descriptor) - // A workaround for the JS/REPL backend: - // JS backend doesn't save previously executed snippets anywhere, they should be taken for now from the context.symbolTable.listExistedScripts() - // on the other hand imported scripts are also stored there so to avoid clashes the imported scripts should be filtered out - // NOTE: that JVM IR is not properly tested with REPL, so it might have the same problem - // TODO: design and implement other schema for handling previous snippets val importedScripts = descriptor.implicitReceivers.filterIsInstanceTo(HashSet()) - // TODO: since script could reference instances of previous one their receivers have to be enlisted in its scope - // Remove this code once script is no longer represented by Class - previousScripts.forEach { - if (it.owner != irScript && it.descriptor !in importedScripts) { - context.symbolTable.introduceValueParameter(it.owner.thisReceiver) - } - } - val startOffset = ktScript.pureStartOffset val endOffset = ktScript.pureEndOffset @@ -93,6 +82,24 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG // TODO: implement implicit receiver parameters handlin properly var parametersIndex = 0 + irScript.earlierScripts = context.extensions.getPreviousScripts()?.filter { + // TODO: probably unnecessary filtering + it.owner != irScript && it.descriptor !in importedScripts + } + irScript.earlierScripts?.forEach { + context.symbolTable.introduceValueParameter(it.owner.thisReceiver) + } + irScript.earlierScriptsParameter = irScript.earlierScripts?.takeIf { it.isNotEmpty() }?.let { + val baseType = context.irBuiltIns.anyType + val arrayType = baseType.toArrayOrPrimitiveArrayType(context.irBuiltIns) + context.irFactory.createValueParameter( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.SCRIPT_EARLIER_SCRIPTS, IrValueParameterSymbolImpl(), + Name.special(""), parametersIndex++, + arrayType, null, + false, false, false, false + ).also { it.parent = irScript } + } + irScript.explicitCallParameters = descriptor.explicitConstructorParameters.map { valueParameterDescriptor -> parametersIndex++ valueParameterDescriptor.toIrValueParameter(startOffset, endOffset, IrDeclarationOrigin.SCRIPT_CALL_PARAMETER).also { it.parent = irScript } @@ -111,14 +118,17 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG startOffset, endOffset, IrDeclarationOrigin.SCRIPT_PROVIDED_PROPERTY, parameter, type ) val irProperty = - PropertyGenerator(declarationGenerator).generateSyntheticProperty(ktScript, providedProperty, valueParameter, generateSyntheticAccessors = true) + PropertyGenerator(declarationGenerator).generateSyntheticProperty( + ktScript, + providedProperty, + valueParameter, + generateSyntheticAccessors = true + ) irProperty.origin = IrDeclarationOrigin.SCRIPT_PROVIDED_PROPERTY irScript.statements += irProperty valueParameter to irProperty.symbol } - irScript.earlierScripts = previousScripts - for (d in ktScript.declarations) { when (d) { is KtScriptInitializer -> { @@ -129,7 +139,11 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG if (d == ktScript.declarations.last() && descriptor.resultValue != null) { descriptor.resultValue!!.let { resultDescriptor -> PropertyGenerator(declarationGenerator) - .generateSyntheticPropertyWithInitializer(ktScript, resultDescriptor, generateSyntheticAccessors = true) { + .generateSyntheticPropertyWithInitializer( + ktScript, + resultDescriptor, + generateSyntheticAccessors = true + ) { // TODO: check if this is a correct place to do it it.visibility = DescriptorVisibilities.PUBLIC irExpressionBody diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index 91fa8eb6dbd..e36da63f7c2 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -42,6 +42,7 @@ interface IrDeclarationOrigin { object SCRIPT_CLASS : IrDeclarationOriginImpl("SCRIPT_CLASS") object SCRIPT_STATEMENT : IrDeclarationOriginImpl("SCRIPT_STATEMENT") + object SCRIPT_EARLIER_SCRIPTS : IrDeclarationOriginImpl("SCRIPT_EARLIER_SCRIPTS") object SCRIPT_CALL_PARAMETER : IrDeclarationOriginImpl("SCRIPT_CALL_PARAMETER") object SCRIPT_IMPLICIT_RECEIVER : IrDeclarationOriginImpl("SCRIPT_IMPLICIT_RECEIVER") object SCRIPT_PROVIDED_PROPERTY : IrDeclarationOriginImpl("SCRIPT_PROVIDED_PROPERTY") diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrScript.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrScript.kt index 8729dda5d45..8395cc1e674 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrScript.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrScript.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.ir.declarations import org.jetbrains.kotlin.ir.expressions.IrStatementContainer +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol import org.jetbrains.kotlin.ir.types.IrType @@ -32,5 +33,9 @@ abstract class IrScript : abstract var resultProperty: IrPropertySymbol? + abstract var earlierScriptsParameter: IrValueParameter? + abstract var earlierScripts: List? + + abstract var targetClass: IrClassSymbol? } 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 f1913f11744..dac7d90e292 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 @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol import org.jetbrains.kotlin.ir.types.IrType @@ -52,7 +53,9 @@ class IrScriptImpl( override lateinit var implicitReceiversParameters: List override lateinit var providedProperties: List> override var resultProperty: IrPropertySymbol? = null + override var earlierScriptsParameter: IrValueParameter? = null override var earlierScripts: List? = null + override var targetClass: IrClassSymbol? = null @ObsoleteDescriptorBasedAPI override val descriptor: ScriptDescriptor 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 3e23fbe5d5d..daa081be8b6 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 @@ -118,6 +118,8 @@ open class DeepCopyIrTreeWithSymbols( ).also { scriptCopy -> scriptCopy.thisReceiver = declaration.thisReceiver.transform() declaration.statements.mapTo(scriptCopy.statements) { it.transform() } + scriptCopy.earlierScripts = declaration.earlierScripts + scriptCopy.earlierScriptsParameter = declaration.earlierScriptsParameter scriptCopy.explicitCallParameters = declaration.explicitCallParameters.map { it.transform() } scriptCopy.implicitReceiversParameters = declaration.implicitReceiversParameters.map { it.transform() } scriptCopy.providedProperties = declaration.providedProperties.map { it.first.transform() to it.second } diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/repl/legacyReplCompilation.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/repl/legacyReplCompilation.kt index 3285f29d087..e441e99326a 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/repl/legacyReplCompilation.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/repl/legacyReplCompilation.kt @@ -8,7 +8,6 @@ package kotlin.script.experimental.jvmhost.repl import kotlinx.coroutines.runBlocking import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.cli.common.repl.* -import org.jetbrains.kotlin.cli.common.repl.ReplCompilerWithoutCheck import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerBase import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerStageHistory import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerState @@ -78,7 +77,7 @@ class JvmReplCompiler( ) } else -> { - val message = res.reports.joinToString("\n") { it.message } + val message = res.reports.joinToString("\n") if (res.isIncomplete()) { ReplCompileResult.Incomplete(message) } else { diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt index 530b6d95ecf..d05b4c05167 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt @@ -75,7 +75,7 @@ class LazyScriptDescriptor( resolveSession.trace.record(BindingContext.SCRIPT, scriptInfo.script, this) } - override fun getResultValue(): ReplResultPropertyDescriptor? { + private val _resultValue: () -> ReplResultPropertyDescriptor? = resolveSession.storageManager.createNullableLazyValue { val expression = scriptInfo.script .getChildOfType() ?.getChildrenOfType()?.lastOrNull() @@ -85,7 +85,7 @@ class LazyScriptDescriptor( resolveSession.trace.bindingContext.getType(it) } - return if (type != null && !type.isUnit() && !type.isNothing()) { + if (type != null && !type.isUnit() && !type.isNothing()) { resultFieldName()?.let { ReplResultPropertyDescriptor( it, @@ -98,6 +98,8 @@ class LazyScriptDescriptor( } else null } + override fun getResultValue(): ReplResultPropertyDescriptor? = _resultValue() + fun resultFieldName(): Name? { // TODO: implement robust REPL/script selection val replSnippetId = diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt index b102c2bdd82..10d743c7925 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt @@ -7,6 +7,10 @@ package org.jetbrains.kotlin.scripting.compiler.plugin.impl import com.intellij.openapi.Disposable +import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig +import org.jetbrains.kotlin.backend.jvm.* +import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.MessageCollector @@ -16,13 +20,16 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.codegen.ClassBuilderFactories import org.jetbrains.kotlin.codegen.KotlinCodegenFacade import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.ScriptDescriptor +import org.jetbrains.kotlin.idea.MainFunctionDetector +import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc +import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl +import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.calls.tower.ImplicitsExtensionsResolutionFilter -import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerStageHistory -import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerState -import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase -import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplImplicitsExtensionsResolutionFilter +import org.jetbrains.kotlin.scripting.compiler.plugin.repl.* import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.resolve.skipExtensionsResolutionForImplicits import org.jetbrains.kotlin.scripting.resolve.skipExtensionsResolutionForImplicitsExceptInnermost @@ -112,45 +119,35 @@ open class KJvmReplCompilerBase protected cons ) } - val no = scriptPriority.getAndIncrement() + val snippetNo = scriptPriority.getAndIncrement() val analysisResult = - compilationState.analyzerEngine.analyzeReplLineWithImportedScripts(snippetKtFile, sourceFiles.drop(1), snippet, no) + compilationState.analyzerEngine.analyzeReplLineWithImportedScripts( + snippetKtFile, + sourceFiles.drop(1), + snippet, + snippetNo + ) AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder) val scriptDescriptor = when (analysisResult) { - is ReplCodeAnalyzerBase.ReplLineAnalysisResult.WithErrors -> return failure( - messageCollector - ) + is ReplCodeAnalyzerBase.ReplLineAnalysisResult.WithErrors -> return failure(messageCollector) is ReplCodeAnalyzerBase.ReplLineAnalysisResult.Successful -> { (analysisResult.scriptDescriptor as? ScriptDescriptor) - ?: return failure( - snippet, - messageCollector, - "Unexpected script descriptor type ${analysisResult.scriptDescriptor::class}" - ) + ?: throw AssertionError("Unexpected script descriptor type ${analysisResult.scriptDescriptor::class}") } - else -> return failure( - snippet, - messageCollector, - "Unexpected result ${analysisResult::class.java}" - ) + else -> throw AssertionError("Unexpected result ${analysisResult::class.java}") } - val generationState = GenerationState.Builder( - snippetKtFile.project, - ClassBuilderFactories.BINARIES, - compilationState.analyzerEngine.module, - compilationState.analyzerEngine.trace.bindingContext, - sourceFiles, - compilationState.environment.configuration - ).build().apply { - scriptSpecific.earlierScriptsForReplInterpreter = history.map { it.item } - beforeCompile() - } - KotlinCodegenFacade.generatePackage(generationState, snippetKtFile.script!!.containingKtFile.packageFqName, sourceFiles) + val isIr = context.environment.configuration.getBoolean(JVMConfigurationKeys.IR) - history.push(LineId(no, 0, snippet.hashCode()), scriptDescriptor) + val generationState = if (isIr) { + generateWithBackendIr(compilationState, snippetKtFile, sourceFiles) + } else { + generateWithOldBackend(compilationState, snippetKtFile, sourceFiles) + } + + history.push(LineId(snippetNo, 0, snippet.hashCode()), scriptDescriptor) val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project) val compiledScript = @@ -175,6 +172,55 @@ open class KJvmReplCompilerBase protected cons } }.last() + private fun generateWithOldBackend( + compilationState: ReplCompilationState, + snippetKtFile: KtFile, + sourceFiles: List + ): GenerationState { + val generationState = GenerationState.Builder( + snippetKtFile.project, + ClassBuilderFactories.BINARIES, + compilationState.analyzerEngine.module, + compilationState.analyzerEngine.trace.bindingContext, + sourceFiles, + compilationState.environment.configuration + ).build().also { generationState -> + generationState.scriptSpecific.earlierScriptsForReplInterpreter = history.map { it.item } + generationState.beforeCompile() + } + KotlinCodegenFacade.generatePackage(generationState, snippetKtFile.script!!.containingKtFile.packageFqName, sourceFiles) + + return generationState + } + + private fun generateWithBackendIr( + compilationState: ReplCompilationState, + snippetKtFile: KtFile, + sourceFiles: List + ): GenerationState { + val generatorExtensions = object : JvmGeneratorExtensionsImpl() { + override fun getPreviousScripts() = history.map { compilationState.symbolTable.referenceScript(it.item) } + } + val codegenFactory = JvmIrCodegenFactory( + compilationState.environment.configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jvmPhases), + compilationState.mangler, compilationState.symbolTable, generatorExtensions + ) + val generationState = GenerationState.Builder( + snippetKtFile.project, + ClassBuilderFactories.BINARIES, + compilationState.analyzerEngine.module, + compilationState.analyzerEngine.trace.bindingContext, + sourceFiles, + compilationState.environment.configuration + ) + .codegenFactory(codegenFactory) + .build() + + generationState.codegenFactory.generateModule(generationState, generationState.files) + + return generationState + } + override suspend fun invoke( script: SourceCode, scriptCompilationConfiguration: ScriptCompilationConfiguration @@ -294,4 +340,15 @@ class ReplCompilationState( // ReplCodeAnalyzer1(context.environment) analyzerInit(context, implicitsResolutionFilter) } + + private val manglerAndSymbolTable by lazy { + val mangler = JvmManglerDesc( + MainFunctionDetector(analyzerEngine.trace.bindingContext, environment.configuration.languageVersionSettings) + ) + val symbolTable = SymbolTable(JvmIdSignatureDescriptor(mangler), IrFactoryImpl, JvmNameProvider) + mangler to symbolTable + } + + override val mangler: JvmManglerDesc get() = manglerAndSymbolTable.first + override val symbolTable: SymbolTable get() = manglerAndSymbolTable.second } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/jvmReplCompilation.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/jvmReplCompilation.kt index 0cd01e3e7fc..d792b847a1c 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/jvmReplCompilation.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/jvmReplCompilation.kt @@ -7,13 +7,16 @@ package org.jetbrains.kotlin.scripting.compiler.plugin.repl import com.intellij.openapi.Disposable import com.intellij.openapi.util.Disposer -import org.jetbrains.kotlin.cli.common.repl.* +import org.jetbrains.kotlin.cli.common.repl.BasicReplStageHistory +import org.jetbrains.kotlin.cli.common.repl.IReplStageState import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.descriptors.ScriptDescriptor +import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmManglerDesc +import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.resolve.calls.tower.ImplicitsExtensionsResolutionFilter import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.write -import kotlin.script.experimental.api.* +import kotlin.script.experimental.api.ScriptCompilationConfiguration class JvmReplCompilerStageHistory(private val state: JvmReplCompilerState) : BasicReplStageHistory(state.lock) @@ -62,5 +65,7 @@ class JvmReplCompilerState( val environment: KotlinCoreEnvironment val analyzerEngine: ReplCodeAnalyzerBase val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter + val mangler: JvmManglerDesc + val symbolTable: SymbolTable } }