Make state of the default REPL compiler explicit and replaceable

restores proper object hierarchy in case the legacy REPL infrastructure
This commit is contained in:
Ilya Chernikov
2021-08-20 15:11:48 +02:00
committed by TeamCityServer
parent e7c9a46329
commit a45e31720c
9 changed files with 121 additions and 117 deletions
@@ -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 {
@@ -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 {
@@ -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<ReplCodeAnalyzerBase>()
val replEvaluator = BasicJvmReplEvaluator()
val compilationConfiguration = ScriptCompilationConfiguration().with {
updateClasspath(classpathFromClass<NewAnn>())
@@ -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<ResultWithDiagnostics<EvaluatedSnippet>> {
val replCompiler = KJvmReplCompilerBase.create(defaultJvmScriptingHostConfiguration)
val replCompiler = KJvmReplCompilerBase<ReplCodeAnalyzerBase>()
val replEvaluator = BasicJvmReplEvaluator()
val currentEvalConfig = evaluationConfiguration ?: ScriptEvaluationConfiguration()
val snipetsLimited = if (limit == 0) snippets else snippets.take(limit)
@@ -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 {
@@ -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<ReplCodeAnalyzerBase> = 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<ReplCodeAnalyzerBase>(
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
}
@@ -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<AnalyzerT : ReplCodeAnalyzerBase> 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<AnalyzerT : ReplCodeAnalyzerBase>(
protected val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
val initAnalyzer: (SharedScriptCompilationContext, ImplicitsExtensionsResolutionFilter) -> AnalyzerT
val state: JvmReplCompilerState<*> = JvmReplCompilerState({ createCompilationState(it, hostConfiguration) })
) : ReplCompiler<KJvmCompiledScript>, ScriptCompiler {
val state = JvmReplCompilerState({ createReplCompilationState(it, initAnalyzer) })
val history = JvmReplCompilerStageHistory(state)
protected val scriptPriority = AtomicInteger()
private val resolutionFilter = ReplImplicitsExtensionsResolutionFilter()
override var lastCompiledSnippet: LinkedSnippetImpl<KJvmCompiledScript>? = null
protected set
fun createReplCompilationState(
scriptCompilationConfiguration: ScriptCompilationConfiguration,
initAnalyzer: (SharedScriptCompilationContext, ImplicitsExtensionsResolutionFilter) -> AnalyzerT /* = { ReplCodeAnalyzer1(it.environment) } */
): ReplCompilationState<AnalyzerT> {
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<SourceCode>,
configuration: ScriptCompilationConfiguration
): ResultWithDiagnostics<LinkedSnippet<KJvmCompiledScript>> =
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<AnalyzerT>
updateResolutionFilterWithHistory(configuration)
val (context, errorHolder, snippetKtFile) = prepareForAnalyze(
snippet,
@@ -109,7 +94,7 @@ open class KJvmReplCompilerBase<AnalyzerT : ReplCodeAnalyzerBase> 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<AnalyzerT : ReplCodeAnalyzerBase> protected cons
)
}
val snippetNo = scriptPriority.getAndIncrement()
val snippetNo = state.getNextLineNo()
val analysisResult =
compilationState.analyzerEngine.analyzeReplLineWithImportedScripts(
@@ -147,7 +132,7 @@ open class KJvmReplCompilerBase<AnalyzerT : ReplCodeAnalyzerBase> 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<AnalyzerT : ReplCodeAnalyzerBase> 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<AnalyzerT : ReplCodeAnalyzerBase> protected cons
sourceFiles: List<KtFile>
): 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<AnalyzerT : ReplCodeAnalyzerBase> 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<AnalyzerT : ReplCodeAnalyzerBase> 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<AnalyzerT : ReplCodeAnalyzerBase> 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<ReplCodeAnalyzerBase> =
createCompilationState(scriptCompilationConfiguration, hostConfiguration) { context1, resolutionFilter ->
ReplCodeAnalyzerBase(context1.environment, implicitsResolutionFilter = resolutionFilter)
}
fun <AnalyzerT : ReplCodeAnalyzerBase> createCompilationState(
scriptCompilationConfiguration: ScriptCompilationConfiguration,
hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration,
initAnalyzer: (SharedScriptCompilationContext, ImplicitsExtensionsResolutionFilter) -> AnalyzerT
): ReplCompilationState<AnalyzerT> {
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<AnalyzerT : ReplCodeAnalyzerBase>(
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<AnalyzerT : ReplCodeAnalyzerBase>(
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
}
@@ -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<KotlinType> = emptyList(),
classesToSkipAfterFirstTime: Collection<KotlinType> = emptyList()
) : ImplicitsExtensionsResolutionFilter {
private val lock = ReentrantReadWriteLock()
private var classesToSkipNames: Set<String> = emptySet()
private var classesToSkipFirstTimeNames: Set<String> = emptySet()
@@ -29,6 +32,10 @@ class ReplImplicitsExtensionsResolutionFilter : ImplicitsExtensionsResolutionFil
classesToSkipFirstTimeNames = classesToSkipAfterFirstTime.mapTo(hashSetOf()) { it.typeName }
}
init {
update(classesToSkip, classesToSkipAfterFirstTime)
}
override fun getScopesWithInfo(
scopes: Sequence<HierarchicalScope>
): Sequence<ScopeWithImplicitsExtensionsResolutionInfo> {
@@ -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<CompilationT : JvmReplCompilerState.Compilation>(private val state: JvmReplCompilerState<CompilationT>) :
class JvmReplCompilerStageHistory<CompilationT : JvmReplCompilerState.Compilation>(state: JvmReplCompilerState<CompilationT>) :
BasicReplStageHistory<ScriptDescriptor>(state.lock)
class JvmReplCompilerState<CompilationT : JvmReplCompilerState.Compilation>(
@@ -63,9 +60,5 @@ class JvmReplCompilerState<CompilationT : JvmReplCompilerState.Compilation>(
val disposable: Disposable?
val baseScriptCompilationConfiguration: ScriptCompilationConfiguration
val environment: KotlinCoreEnvironment
val analyzerEngine: ReplCodeAnalyzerBase
val implicitsResolutionFilter: ImplicitsExtensionsResolutionFilter
val mangler: JvmDescriptorMangler
val symbolTable: SymbolTable
}
}
@@ -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<IdeLikeReplCodeAnalyzer>(hostConfiguration, { sharedScriptCompilationContext, scopeProcessor ->
IdeLikeReplCodeAnalyzer(sharedScriptCompilationContext.environment, scopeProcessor)
}),
KJvmReplCompilerBase<IdeLikeReplCodeAnalyzer>(
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<AnalyzeWithCursorResult> {
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) {