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:
committed by
TeamCityServer
parent
e7c9a46329
commit
a45e31720c
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+15
-6
@@ -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)
|
||||
|
||||
+1
-2
@@ -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 {
|
||||
|
||||
+14
-45
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+60
-46
@@ -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
|
||||
}
|
||||
|
||||
+8
-1
@@ -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> {
|
||||
|
||||
+1
-8
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+20
-7
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user