From a45e31720c75ed857ec46cab3d06d8b330e45f28 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Fri, 20 Aug 2021 15:11:48 +0200 Subject: [PATCH] Make state of the default REPL compiler explicit and replaceable restores proper object hierarchy in case the legacy REPL infrastructure --- .../kotlin/cli/common/repl/ReplApi.kt | 2 +- .../jvmhost/test/LegacyReplTest.kt | 2 +- .../experimental/jvmhost/test/ReplTest.kt | 21 +++- .../jsr223/KotlinJsr223ScriptEngineImpl.kt | 3 +- .../jvmhost/repl/legacyReplCompilation.kt | 59 +++------- .../plugin/impl/KJvmReplCompilerBase.kt | 106 ++++++++++-------- ...ReplImplicitsExtensionsResolutionFilter.kt | 9 +- .../plugin/repl/jvmReplCompilation.kt | 9 +- .../KJvmReplCompilerWithIdeServices.kt | 27 +++-- 9 files changed, 121 insertions(+), 117 deletions(-) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/ReplApi.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/ReplApi.kt index e8030e9db61..c5713ace2d2 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/ReplApi.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/ReplApi.kt @@ -24,7 +24,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.jvm.internal.TypeIntrinsics import kotlin.reflect.KClass -const val REPL_CODE_LINE_FIRST_NO = 1 +const val REPL_CODE_LINE_FIRST_NO = 0 const val REPL_CODE_LINE_FIRST_GEN = 1 data class ReplCodeLine(val no: Int, val generation: Int, val code: String) : Serializable { diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/LegacyReplTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/LegacyReplTest.kt index 1955ef6531b..030fc76450d 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/LegacyReplTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/LegacyReplTest.kt @@ -125,7 +125,7 @@ internal class LegacyTestRepl : Closeable { fun nextCodeLine(code: String): ReplCodeLine = ReplCodeLine(currentLineCounter.getAndIncrement(), 0, code) val replCompiler: JvmReplCompiler by lazy { - JvmReplCompiler(simpleScriptCompilationConfiguration, false) + JvmReplCompiler(simpleScriptCompilationConfiguration) } val compiledEvaluator: ReplEvaluator by lazy { diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ReplTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ReplTest.kt index d3129b45550..c8ec05400d5 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ReplTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ReplTest.kt @@ -8,12 +8,12 @@ package kotlin.script.experimental.jvmhost.test import junit.framework.TestCase import kotlinx.coroutines.runBlocking import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerBase +import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase import org.junit.Assert import org.junit.Test import kotlin.script.experimental.api.* import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvm.BasicJvmReplEvaluator -import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.updateClasspath import kotlin.script.experimental.jvm.util.classpathFromClass import kotlin.script.experimental.jvmhost.createJvmScriptDefinitionFromTemplate @@ -212,7 +212,7 @@ class ReplTest : TestCase() { @Test fun testAddNewAnnotationHandler() { - val replCompiler = KJvmReplCompilerBase.create(defaultJvmScriptingHostConfiguration) + val replCompiler = KJvmReplCompilerBase() val replEvaluator = BasicJvmReplEvaluator() val compilationConfiguration = ScriptCompilationConfiguration().with { updateClasspath(classpathFromClass()) @@ -224,7 +224,10 @@ class ReplTest : TestCase() { replEvaluator.eval(it, evaluationConfiguration) } } - assertTrue("Expecting 1 got $res0", res0 is ResultWithDiagnostics.Success && (res0.value.get().result as ResultValue.Value).value == 1) + assertTrue( + "Expecting 1 got $res0", + res0 is ResultWithDiagnostics.Success && (res0.value.get().result as ResultValue.Value).value == 1 + ) var handlerInvoked = false @@ -239,11 +242,17 @@ class ReplTest : TestCase() { } val res1 = runBlocking { - replCompiler.compile("@file:kotlin.script.experimental.jvmhost.test.NewAnn()\n2".toScriptSource("Line_1.kts"), compilationConfiguration2).onSuccess { + replCompiler.compile( + "@file:kotlin.script.experimental.jvmhost.test.NewAnn()\n2".toScriptSource("Line_1.kts"), + compilationConfiguration2 + ).onSuccess { replEvaluator.eval(it, evaluationConfiguration) } } - assertTrue("Expecting 2 got $res1", res1 is ResultWithDiagnostics.Success && (res1.value.get().result as ResultValue.Value).value == 2) + assertTrue( + "Expecting 2 got $res1", + res1 is ResultWithDiagnostics.Success && (res1.value.get().result as ResultValue.Value).value == 2 + ) assertTrue("Refinement handler on annotation is not invoked", handlerInvoked) } @@ -275,7 +284,7 @@ class ReplTest : TestCase() { evaluationConfiguration: ScriptEvaluationConfiguration? = simpleScriptEvaluationConfiguration, limit: Int = 0 ): Sequence> { - val replCompiler = KJvmReplCompilerBase.create(defaultJvmScriptingHostConfiguration) + val replCompiler = KJvmReplCompilerBase() val replEvaluator = BasicJvmReplEvaluator() val currentEvalConfig = evaluationConfiguration ?: ScriptEvaluationConfiguration() val snipetsLimited = if (limit == 0) snippets else snippets.take(limit) diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jsr223/KotlinJsr223ScriptEngineImpl.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jsr223/KotlinJsr223ScriptEngineImpl.kt index ceeb94bb092..bb0b2c45874 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jsr223/KotlinJsr223ScriptEngineImpl.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/jsr223/KotlinJsr223ScriptEngineImpl.kt @@ -6,7 +6,6 @@ package kotlin.script.experimental.jvmhost.jsr223 import org.jetbrains.kotlin.cli.common.repl.* -import org.jetbrains.kotlin.cli.common.repl.ReplCompilerWithoutCheck import java.util.concurrent.locks.ReentrantReadWriteLock import javax.script.ScriptContext import javax.script.ScriptEngineFactory @@ -63,7 +62,7 @@ class KotlinJsr223ScriptEngineImpl( } override val replCompiler: ReplCompilerWithoutCheck by lazy { - JvmReplCompiler(compilationConfiguration, true) + JvmReplCompiler(compilationConfiguration) } private val localEvaluator by lazy { 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 8659684dd6c..4f10a7f9266 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 @@ -5,18 +5,16 @@ package kotlin.script.experimental.jvmhost.repl -import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.cli.common.repl.* 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 import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.write import kotlin.script.experimental.api.* -import kotlin.script.experimental.impl.internalScriptingRunSuspend import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.host.withDefaultsFrom +import kotlin.script.experimental.impl.internalScriptingRunSuspend import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.util.isIncomplete @@ -25,50 +23,28 @@ import kotlin.script.experimental.jvm.util.isIncomplete */ class JvmReplCompiler( val scriptCompilationConfiguration: ScriptCompilationConfiguration, - val allowReInit: Boolean = true, - val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration, - var replCompiler: KJvmReplCompilerBase = KJvmReplCompilerBase.create( - hostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration) - ) + val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration ) : ReplCompilerWithoutCheck { - private val compilers = mutableListOf(replCompiler) - override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = - if (allowReInit) { - JvmReplCompilerState({ replCompiler.createReplCompilationState(it, replCompiler.initAnalyzer) }, lock) - } else { - replCompiler.state - } + JvmReplCompilerState({ KJvmReplCompilerBase.createCompilationState(it, hostConfiguration) }, lock) - override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult = replCompiler.state.lock.write { + override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult = state.lock.write { val replCompilerState = state.asState(JvmReplCompilerState::class.java) val snippet = codeLine.toSourceCode(scriptCompilationConfiguration) - if (allowReInit) { - replCompiler = compilers.find { historiesEq(it.history, replCompilerState.history) } ?: { - compilers.push( - KJvmReplCompilerBase.create( - hostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration) - ) - ) - compilers.last() - }() - } + val replCompiler = KJvmReplCompilerBase( + hostConfiguration.withDefaultsFrom(defaultJvmScriptingHostConfiguration), + replCompilerState + ) @Suppress("DEPRECATION_ERROR") when (val res = internalScriptingRunSuspend { replCompiler.compile(listOf(snippet), scriptCompilationConfiguration) }) { is ResultWithDiagnostics.Success -> { val lineId = LineId(codeLine.no, 0, snippet.hashCode()) - replCompilerState.apply { - lock.write { - val compilerHistory = history as JvmReplCompilerStageHistory<*> - compilerHistory.push(lineId, replCompiler.history.last().item) - } - } ReplCompileResult.CompiledClasses( lineId, - replCompiler.history.map { it.id }, + replCompiler.state.history.map { it.id }, snippet.name!!, emptyList(), res.value.get().resultField != null, @@ -87,15 +63,6 @@ class JvmReplCompiler( } } } - - companion object { - fun historiesEq(history1: IReplStageHistory<*>, history2: IReplStageHistory<*>) = - history1.count() == history2.count() && - history1.zip(history2).all { - val (it1, it2) = it - it1.item === it2.item - } - } } @@ -105,9 +72,11 @@ internal class SourceCodeFromReplCodeLine( ) : SourceCode { override val text: String get() = codeLine.code override val name: String = - "${compilationConfiguration[ScriptCompilationConfiguration.repl.makeSnippetIdentifier]!!( - compilationConfiguration, ReplSnippetIdImpl(codeLine.no, codeLine.generation, 0) - )}.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}" + "${ + compilationConfiguration[ScriptCompilationConfiguration.repl.makeSnippetIdentifier]!!( + compilationConfiguration, ReplSnippetIdImpl(codeLine.no, codeLine.generation, 0) + ) + }.${compilationConfiguration[ScriptCompilationConfiguration.fileExtension]}" override val locationId: String? = null } 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 a19a9886f92..69c8b43981a 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 @@ -8,7 +8,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.JvmGeneratorExtensionsImpl +import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory +import org.jetbrains.kotlin.backend.jvm.JvmNameProvider +import org.jetbrains.kotlin.backend.jvm.jvmPhases import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback @@ -30,11 +33,12 @@ 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.resolve.jvm.KotlinJavaPsiFacade -import org.jetbrains.kotlin.scripting.compiler.plugin.repl.* +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.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.resolve.skipExtensionsResolutionForImplicits import org.jetbrains.kotlin.scripting.resolve.skipExtensionsResolutionForImplicitsExceptInnermost -import java.util.concurrent.atomic.AtomicInteger import kotlin.script.experimental.api.* import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration @@ -43,49 +47,30 @@ import kotlin.script.experimental.util.LinkedSnippet import kotlin.script.experimental.util.LinkedSnippetImpl import kotlin.script.experimental.util.add -open class KJvmReplCompilerBase protected constructor( +// NOTE: this implementation, as it is used in the REPL infrastructure, may be created for every snippet and provided with the state +// so it should not keep any compilation state outside of the stste field +open class KJvmReplCompilerBase( protected val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration, - val initAnalyzer: (SharedScriptCompilationContext, ImplicitsExtensionsResolutionFilter) -> AnalyzerT + val state: JvmReplCompilerState<*> = JvmReplCompilerState({ createCompilationState(it, hostConfiguration) }) ) : ReplCompiler, ScriptCompiler { - val state = JvmReplCompilerState({ createReplCompilationState(it, initAnalyzer) }) - val history = JvmReplCompilerStageHistory(state) - protected val scriptPriority = AtomicInteger() - private val resolutionFilter = ReplImplicitsExtensionsResolutionFilter() override var lastCompiledSnippet: LinkedSnippetImpl? = null protected set - fun createReplCompilationState( - scriptCompilationConfiguration: ScriptCompilationConfiguration, - initAnalyzer: (SharedScriptCompilationContext, ImplicitsExtensionsResolutionFilter) -> AnalyzerT /* = { ReplCodeAnalyzer1(it.environment) } */ - ): ReplCompilationState { - val context = withMessageCollectorAndDisposable(disposeOnSuccess = false) { messageCollector, disposable -> - createIsolatedCompilationContext( - scriptCompilationConfiguration, - hostConfiguration, - messageCollector, - disposable - ).asSuccess() - }.valueOr { throw IllegalStateException("Unable to initialize repl compiler:\n ${it.reports.joinToString("\n ")}") } - - updateResolutionFilter(scriptCompilationConfiguration) - - return ReplCompilationState(context, initAnalyzer, resolutionFilter) - } - override suspend fun compile( snippets: Iterable, configuration: ScriptCompilationConfiguration ): ResultWithDiagnostics> = snippets.map { snippet -> withMessageCollector(snippet) { messageCollector -> - updateResolutionFilter(configuration) - val initialConfiguration = configuration.refineBeforeParsing(snippet).valueOr { return it } - val compilationState = state.getCompilationState(initialConfiguration) + @Suppress("UNCHECKED_CAST") + val compilationState = state.getCompilationState(initialConfiguration) as ReplCompilationState + + updateResolutionFilterWithHistory(configuration) val (context, errorHolder, snippetKtFile) = prepareForAnalyze( snippet, @@ -109,7 +94,7 @@ open class KJvmReplCompilerBase protected cons if (messageCollector.hasErrors()) return failure(messageCollector) - if (history.isEmpty()) { + if (state.history.isEmpty()) { val updatedConfiguration = ScriptDependenciesProvider.getInstance(context.environment.project) ?.getScriptConfiguration(snippetKtFile)?.configuration ?: context.baseScriptCompilationConfiguration @@ -119,7 +104,7 @@ open class KJvmReplCompilerBase protected cons ) } - val snippetNo = scriptPriority.getAndIncrement() + val snippetNo = state.getNextLineNo() val analysisResult = compilationState.analyzerEngine.analyzeReplLineWithImportedScripts( @@ -147,7 +132,7 @@ open class KJvmReplCompilerBase protected cons generateWithOldBackend(compilationState, snippetKtFile, sourceFiles) } - history.push(LineId(snippetNo, 0, snippet.hashCode()), scriptDescriptor) + state.history.push(LineId(snippetNo, 0, snippet.hashCode()), scriptDescriptor) val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project) makeCompiledScript( @@ -185,7 +170,7 @@ open class KJvmReplCompilerBase protected cons sourceFiles, compilationState.environment.configuration ).build().also { generationState -> - generationState.scriptSpecific.earlierScriptsForReplInterpreter = history.map { it.item } + generationState.scriptSpecific.earlierScriptsForReplInterpreter = state.history.map { it.item } generationState.beforeCompile() } KotlinCodegenFacade.generatePackage(generationState, snippetKtFile.script!!.containingKtFile.packageFqName, sourceFiles) @@ -199,7 +184,7 @@ open class KJvmReplCompilerBase protected cons sourceFiles: List ): GenerationState { val generatorExtensions = object : JvmGeneratorExtensionsImpl(compilationState.environment.configuration) { - override fun getPreviousScripts() = history.map { compilationState.symbolTable.referenceScript(it.item) } + override fun getPreviousScripts() = state.history.map { compilationState.symbolTable.referenceScript(it.item) } } val codegenFactory = JvmIrCodegenFactory( compilationState.environment.configuration, @@ -282,7 +267,7 @@ open class KJvmReplCompilerBase protected cons ).asSuccess() } - protected fun updateResolutionFilter(configuration: ScriptCompilationConfiguration) { + protected fun updateResolutionFilterWithHistory(configuration: ScriptCompilationConfiguration) { val updatedConfiguration = updateConfigurationWithPreviousScripts(configuration) val classesToSkip = @@ -290,9 +275,10 @@ open class KJvmReplCompilerBase protected cons val classesToSkipAfterFirstTime = updatedConfiguration[ScriptCompilationConfiguration.skipExtensionsResolutionForImplicitsExceptInnermost]!! - resolutionFilter.update(classesToSkip, classesToSkipAfterFirstTime) + (state.compilation as ReplCompilationState<*>).implicitsResolutionFilter.update(classesToSkip, classesToSkipAfterFirstTime) } + private fun updateConfigurationWithPreviousScripts( configuration: ScriptCompilationConfiguration ): ScriptCompilationConfiguration { @@ -313,23 +299,51 @@ open class KJvmReplCompilerBase protected cons } companion object { - fun create(hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration) = - KJvmReplCompilerBase(hostConfiguration) { context, resolutionFilter -> - ReplCodeAnalyzerBase(context.environment, implicitsResolutionFilter = resolutionFilter) - } - } + fun createCompilationState( + scriptCompilationConfiguration: ScriptCompilationConfiguration, + hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration + ): ReplCompilationState = + createCompilationState(scriptCompilationConfiguration, hostConfiguration) { context1, resolutionFilter -> + ReplCodeAnalyzerBase(context1.environment, implicitsResolutionFilter = resolutionFilter) + } + + fun createCompilationState( + scriptCompilationConfiguration: ScriptCompilationConfiguration, + hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration, + initAnalyzer: (SharedScriptCompilationContext, ImplicitsExtensionsResolutionFilter) -> AnalyzerT + ): ReplCompilationState { + val context = withMessageCollectorAndDisposable(disposeOnSuccess = false) { messageCollector, disposable -> + createIsolatedCompilationContext( + scriptCompilationConfiguration, + hostConfiguration, + messageCollector, + disposable + ).asSuccess() + }.valueOr { throw IllegalStateException("Unable to initialize repl compiler:\n ${it.reports.joinToString("\n ")}") } + + return ReplCompilationState( + context, + initAnalyzer, + ReplImplicitsExtensionsResolutionFilter( + scriptCompilationConfiguration[ScriptCompilationConfiguration.skipExtensionsResolutionForImplicits].orEmpty(), + scriptCompilationConfiguration[ScriptCompilationConfiguration.skipExtensionsResolutionForImplicitsExceptInnermost].orEmpty() + ) + ) + } + } } class ReplCompilationState( val context: SharedScriptCompilationContext, val analyzerInit: (context: SharedScriptCompilationContext, implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter) -> AnalyzerT, - override val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter + val implicitsResolutionFilter: ReplImplicitsExtensionsResolutionFilter ) : JvmReplCompilerState.Compilation { override val disposable: Disposable? get() = context.disposable override val baseScriptCompilationConfiguration: ScriptCompilationConfiguration get() = context.baseScriptCompilationConfiguration override val environment: KotlinCoreEnvironment get() = context.environment - override val analyzerEngine: AnalyzerT by lazy { + + val analyzerEngine: AnalyzerT by lazy { val analyzer = analyzerInit(context, implicitsResolutionFilter) val psiFacade = KotlinJavaPsiFacade.getInstance(environment.project) psiFacade.setNotFoundPackagesCachingStrategy(ReplNotFoundPackagesCachingStrategy) @@ -344,6 +358,6 @@ class ReplCompilationState( mangler to symbolTable } - override val mangler: JvmDescriptorMangler get() = manglerAndSymbolTable.first - override val symbolTable: SymbolTable get() = manglerAndSymbolTable.second + val mangler: JvmDescriptorMangler get() = manglerAndSymbolTable.first + val symbolTable: SymbolTable get() = manglerAndSymbolTable.second } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/ReplImplicitsExtensionsResolutionFilter.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/ReplImplicitsExtensionsResolutionFilter.kt index ce708855930..d81fa21b62c 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/ReplImplicitsExtensionsResolutionFilter.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/ReplImplicitsExtensionsResolutionFilter.kt @@ -16,7 +16,10 @@ import kotlin.concurrent.read import kotlin.concurrent.write import kotlin.script.experimental.api.KotlinType -class ReplImplicitsExtensionsResolutionFilter : ImplicitsExtensionsResolutionFilter { +class ReplImplicitsExtensionsResolutionFilter( + classesToSkip: Collection = emptyList(), + classesToSkipAfterFirstTime: Collection = emptyList() +) : ImplicitsExtensionsResolutionFilter { private val lock = ReentrantReadWriteLock() private var classesToSkipNames: Set = emptySet() private var classesToSkipFirstTimeNames: Set = emptySet() @@ -29,6 +32,10 @@ class ReplImplicitsExtensionsResolutionFilter : ImplicitsExtensionsResolutionFil classesToSkipFirstTimeNames = classesToSkipAfterFirstTime.mapTo(hashSetOf()) { it.typeName } } + init { + update(classesToSkip, classesToSkipAfterFirstTime) + } + override fun getScopesWithInfo( scopes: Sequence ): Sequence { 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 56c87e1811f..b7869c3d0f7 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 @@ -11,14 +11,11 @@ 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.JvmDescriptorMangler -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.ScriptCompilationConfiguration -class JvmReplCompilerStageHistory(private val state: JvmReplCompilerState) : +class JvmReplCompilerStageHistory(state: JvmReplCompilerState) : BasicReplStageHistory(state.lock) class JvmReplCompilerState( @@ -63,9 +60,5 @@ class JvmReplCompilerState( val disposable: Disposable? val baseScriptCompilationConfiguration: ScriptCompilationConfiguration val environment: KotlinCoreEnvironment - val analyzerEngine: ReplCodeAnalyzerBase - val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter - val mangler: JvmDescriptorMangler - val symbolTable: SymbolTable } } diff --git a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/KJvmReplCompilerWithIdeServices.kt b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/KJvmReplCompilerWithIdeServices.kt index 634e641ca3d..f8ebb750431 100644 --- a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/KJvmReplCompilerWithIdeServices.kt +++ b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/KJvmReplCompilerWithIdeServices.kt @@ -12,16 +12,27 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.scripting.compiler.plugin.impl.* -import org.jetbrains.kotlin.scripting.ide_services.compiler.impl.* +import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerState +import org.jetbrains.kotlin.scripting.ide_services.compiler.impl.IdeLikeReplCodeAnalyzer +import org.jetbrains.kotlin.scripting.ide_services.compiler.impl.KotlinResolutionFacadeForRepl +import org.jetbrains.kotlin.scripting.ide_services.compiler.impl.getKJvmCompletion +import org.jetbrains.kotlin.scripting.ide_services.compiler.impl.prepareCodeForCompletion import kotlin.script.experimental.api.* import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.util.calcAbsolute class KJvmReplCompilerWithIdeServices(hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration) : - KJvmReplCompilerBase(hostConfiguration, { sharedScriptCompilationContext, scopeProcessor -> - IdeLikeReplCodeAnalyzer(sharedScriptCompilationContext.environment, scopeProcessor) - }), + KJvmReplCompilerBase( + hostConfiguration, + JvmReplCompilerState( + { + createCompilationState(it, hostConfiguration) { sharedScriptCompilationContext, scopeProcessor -> + IdeLikeReplCodeAnalyzer(sharedScriptCompilationContext.environment, scopeProcessor) + } + } + ) + ), ReplCompleter, ReplCodeAnalyzer { override suspend fun complete( @@ -96,7 +107,6 @@ class KJvmReplCompilerWithIdeServices(hostConfiguration: ScriptingHostConfigurat cursor: SourceCode.Position? = null, getNewSnippet: (SourceCode, Int) -> SourceCode = { code, _ -> code } ): ResultWithDiagnostics { - updateResolutionFilter(configuration) val initialConfiguration = configuration.refineBeforeParsing(snippet).valueOr { return it @@ -105,7 +115,9 @@ class KJvmReplCompilerWithIdeServices(hostConfiguration: ScriptingHostConfigurat val cursorAbs = cursor?.calcAbsolute(snippet) ?: -1 val newSnippet = if (cursorAbs == -1) snippet else getNewSnippet(snippet, cursorAbs) - val compilationState = state.getCompilationState(initialConfiguration) + val compilationState = state.getCompilationState(initialConfiguration) as ReplCompilationState<*> + + updateResolutionFilterWithHistory(configuration) val (_, errorHolder, snippetKtFile) = prepareForAnalyze( newSnippet, @@ -114,8 +126,9 @@ class KJvmReplCompilerWithIdeServices(hostConfiguration: ScriptingHostConfigurat failOnSyntaxErrors = false ).valueOr { return it } + val analyzerEngine = compilationState.analyzerEngine as IdeLikeReplCodeAnalyzer val analysisResult = - compilationState.analyzerEngine.statelessAnalyzeWithImportedScripts(snippetKtFile, emptyList(), scriptPriority.get() + 1) + analyzerEngine.statelessAnalyzeWithImportedScripts(snippetKtFile, emptyList(), state.getNextLineNo() + 1) AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder) val (_, bindingContext, resolutionFacade, moduleDescriptor, resultProperty) = when (analysisResult) {