Extract repl state as a separate object

This commit is contained in:
Ilya Chernikov
2017-02-03 18:14:03 +01:00
parent 3eb5b3e08c
commit f9dedab8c8
15 changed files with 666 additions and 416 deletions
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.cli.jvm.repl
import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.repl.messages.DiagnosticMessageHolder
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.locks.ReentrantReadWriteLock
class ReplCompilerStageHistory(private val state: GenericReplCompilerState) : BasicReplStageHistory<ScriptDescriptor>(state.lock) {
override fun resetTo(id: ILineId): Iterable<ILineId> {
state.generation.incrementAndGet()
val removedCompiledLines = super.resetTo(id)
val removedAnalyzedLines = state.analyzerEngine.resetToLine(id.no)
removedCompiledLines.zip(removedAnalyzedLines).forEach {
if (it.first != LineId(it.second)) {
throw IllegalStateException("History mismatch when resetting lines: ${it.first.no} != ${it.second}")
}
}
return removedCompiledLines
}
}
abstract class GenericReplCheckerState: IReplStageState<ScriptDescriptor> {
// "line" - is the unit of evaluation here, could in fact consists of several character lines
class LineState(
val codeLine: ReplCodeLine,
val psiFile: KtFile,
val errorHolder: DiagnosticMessageHolder)
val generation = AtomicLong(1)
var lastLineState: LineState? = null // for transferring state to the compiler in most typical case
}
class GenericReplCompilerState(environment: KotlinCoreEnvironment, override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : IReplStageState<ScriptDescriptor>, GenericReplCheckerState() {
override val history: IReplStageHistory<ScriptDescriptor> = ReplCompilerStageHistory(this)
val analyzerEngine = ReplCodeAnalyzer(environment)
var lastDependencies: KotlinScriptExternalDependencies? = null
}
@@ -22,8 +22,6 @@ import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import java.io.File
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.locks.ReentrantReadWriteLock
open class GenericRepl protected constructor(
@@ -32,56 +30,22 @@ open class GenericRepl protected constructor(
compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector,
baseClassloader: ClassLoader?,
protected val fallbackScriptArgs: ScriptArgsWithTypes?,
protected val repeatingMode: ReplRepeatingMode = ReplRepeatingMode.NONE,
protected val stateLock: ReentrantReadWriteLock
protected val fallbackScriptArgs: ScriptArgsWithTypes? = null,
protected val repeatingMode: ReplRepeatingMode = ReplRepeatingMode.NONE
) : ReplCompiler, ReplEvaluator, ReplAtomicEvaluator {
constructor (
disposable: Disposable,
scriptDefinition: KotlinScriptDefinition,
compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector,
baseClassloader: ClassLoader?,
fallbackScriptArgs: ScriptArgsWithTypes? = null
) : this(disposable, scriptDefinition, compilerConfiguration, messageCollector, baseClassloader, fallbackScriptArgs, stateLock = ReentrantReadWriteLock())
protected val compiler: ReplCompiler by lazy { GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector, stateLock) }
protected val evaluator: ReplFullEvaluator by lazy { GenericReplCompilingEvaluator(compiler, compilerConfiguration.jvmClasspathRoots, baseClassloader, fallbackScriptArgs, repeatingMode, stateLock) }
protected var codeLineNumber = AtomicInteger(0)
protected val compiler: ReplCompiler by lazy { GenericReplCompiler(disposable, scriptDefinition, compilerConfiguration, messageCollector) }
protected val evaluator: ReplFullEvaluator by lazy { GenericReplCompilingEvaluator(compiler, compilerConfiguration.jvmClasspathRoots, baseClassloader, fallbackScriptArgs, repeatingMode) }
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
return evaluator.resetToLine(lineNumber)
}
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = AggregatedReplStageState(compiler.createState(lock), evaluator.createState(lock), lock)
override fun resetToLine(line: ReplCodeLine): List<ReplCodeLine> {
return evaluator.resetToLine(line)
}
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult = compiler.check(state, codeLine)
override val history: List<ReplCodeLine> get() = evaluator.history
override val compiledHistory: List<ReplCodeLine> get() = compiler.history
override val evaluatedHistory: List<ReplCodeLine> get() = evaluator.history
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult = compiler.compile(state, codeLine)
override val currentClasspath: List<File>
get() = evaluator.currentClasspath
override fun eval(state: IReplStageState<*>, compileResult: ReplCompileResult.CompiledClasses, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult =
evaluator.eval(state, compileResult, scriptArgs, invokeWrapper)
override val lastEvaluatedScripts: List<EvalHistoryType>
get() = evaluator.lastEvaluatedScripts
override fun check(codeLine: ReplCodeLine): ReplCheckResult {
return compiler.check(codeLine)
}
override fun compile(codeLine: ReplCodeLine, verifyHistory: List<ReplCodeLine>?): ReplCompileResult {
return compiler.compile(codeLine, verifyHistory)
}
override fun eval(compileResult: ReplCompileResult.CompiledClasses, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult {
return evaluator.eval(compileResult, scriptArgs, invokeWrapper)
}
override fun compileAndEval(codeLine: ReplCodeLine, scriptArgs: ScriptArgsWithTypes?, verifyHistory: List<ReplCodeLine>?, invokeWrapper: InvokeWrapper?): ReplEvalResult {
return evaluator.compileAndEval(codeLine, scriptArgs, verifyHistory, invokeWrapper)
}
fun nextCodeLine(code: String) = ReplCodeLine(codeLineNumber.incrementAndGet(), code)
override fun compileAndEval(state: IReplStageState<*>, codeLine: ReplCodeLine, scriptArgs: ScriptArgsWithTypes?, invokeWrapper: InvokeWrapper?): ReplEvalResult =
evaluator.compileAndEval(state, codeLine, scriptArgs, invokeWrapper)
}
@@ -26,22 +26,18 @@ import com.intellij.testFramework.LightVirtualFile
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.makeScriptBaseName
import org.jetbrains.kotlin.cli.common.repl.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.repl.messages.DiagnosticMessageHolder
import org.jetbrains.kotlin.cli.jvm.repl.messages.ReplTerminalDiagnosticMessageHolder
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
const val KOTLIN_REPL_JVM_TARGET_PROPERTY = "kotlin.repl.jvm.target"
@@ -50,9 +46,9 @@ open class GenericReplChecker(
disposable: Disposable,
val scriptDefinition: KotlinScriptDefinition,
val compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector,
protected val stateLock: ReentrantReadWriteLock = ReentrantReadWriteLock()
) {
messageCollector: MessageCollector
) : ReplCheckAction {
internal val environment = run {
compilerConfiguration.apply {
add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition)
@@ -70,21 +66,12 @@ open class GenericReplChecker(
private val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl
// "line" - is the unit of evaluation here, could in fact consists of several character lines
internal class LineState(
val codeLine: ReplCodeLine,
val psiFile: KtFile,
val errorHolder: DiagnosticMessageHolder)
internal fun createDiagnosticHolder() = ReplTerminalDiagnosticMessageHolder()
private var _lineState: LineState? = null
internal val lineState: LineState? get() = stateLock.read { _lineState }
fun createDiagnosticHolder() = ReplTerminalDiagnosticMessageHolder()
fun check(codeLine: ReplCodeLine, generation: Long): ReplCheckResult {
stateLock.write {
val scriptFileName = makeScriptBaseName(codeLine, generation)
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult {
state.lock.write {
val checkerState = state.asState<GenericReplCheckerState>()
val scriptFileName = makeScriptBaseName(codeLine, checkerState.generation.get())
val virtualFile =
LightVirtualFile("$scriptFileName${KotlinParserDefinition.STD_SCRIPT_EXT}", KotlinLanguage.INSTANCE, StringUtil.convertLineSeparators(codeLine.code)).apply {
charset = CharsetToolkit.UTF8_CHARSET
@@ -97,7 +84,7 @@ open class GenericReplChecker(
val syntaxErrorReport = AnalyzerWithCompilerReport.reportSyntaxErrors(psiFile, errorHolder)
if (!syntaxErrorReport.isHasErrors) {
_lineState = LineState(codeLine, psiFile, errorHolder)
checkerState.lastLineState = GenericReplCheckerState.LineState(codeLine, psiFile, errorHolder)
}
return when {
@@ -26,115 +26,83 @@ import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.script.KotlinScriptExternalDependencies
import java.io.File
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
// WARNING: not thread safe, assuming external synchronization
open class GenericReplCompiler(disposable: Disposable,
protected val scriptDefinition: KotlinScriptDefinition,
protected val compilerConfiguration: CompilerConfiguration,
messageCollector: MessageCollector,
protected val stateLock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : ReplCompiler {
private val checker = GenericReplChecker(disposable, scriptDefinition, compilerConfiguration, messageCollector, stateLock)
messageCollector: MessageCollector
) : ReplCompiler {
private val analyzerEngine = GenericReplAnalyzer(checker.environment, stateLock)
private val checker = GenericReplChecker(disposable, scriptDefinition, compilerConfiguration, messageCollector)
private var lastDependencies: KotlinScriptExternalDependencies? = null
override fun createState(lock: ReentrantReadWriteLock): IReplStageState<*> = GenericReplCompilerState(checker.environment, lock)
private val descriptorsHistory = ReplHistory<ScriptDescriptor>()
override fun check(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCheckResult = checker.check(state, codeLine)
private val generation = AtomicLong(1)
override fun compile(state: IReplStageState<*>, codeLine: ReplCodeLine): ReplCompileResult {
state.lock.write {
val compilerState = state.asState<GenericReplCompilerState>()
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
return stateLock.write {
generation.incrementAndGet()
val removedCompiledLines = descriptorsHistory.resetToLine(lineNumber)
val removedAnalyzedLines = analyzerEngine.resetToLine(lineNumber)
removedCompiledLines.zip(removedAnalyzedLines).forEach {
if (it.first.first != it.second) {
throw IllegalStateException("History mismatch when resetting lines")
}
}
removedCompiledLines
}.map { it.first }
}
override val history: List<ReplCodeLine> get() = stateLock.read { descriptorsHistory.copySources() }
override fun check(codeLine: ReplCodeLine): ReplCheckResult = stateLock.read {
return checker.check(codeLine, generation.get())
}
override fun compile(codeLine: ReplCodeLine, verifyHistory: List<ReplCodeLine>?): ReplCompileResult {
stateLock.write {
val firstMismatch = descriptorsHistory.firstMismatchingHistory(verifyHistory)
if (firstMismatch != null) {
return@compile ReplCompileResult.HistoryMismatch(descriptorsHistory.copySources(), firstMismatch)
}
val currentGeneration = generation.get()
val currentGeneration = compilerState.generation.get()
val (psiFile, errorHolder) = run {
if (checker.lineState == null || checker.lineState!!.codeLine != codeLine) {
val res = checker.check(codeLine, currentGeneration)
if (compilerState.lastLineState == null || compilerState.lastLineState!!.codeLine != codeLine) {
val res = checker.check(state, codeLine)
when (res) {
is ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete(descriptorsHistory.copySources())
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(descriptorsHistory.copySources(), res.message, res.location)
is ReplCheckResult.Incomplete -> return@compile ReplCompileResult.Incomplete()
is ReplCheckResult.Error -> return@compile ReplCompileResult.Error(res.message, res.location)
is ReplCheckResult.Ok -> {} // continue
}
}
Pair(checker.lineState!!.psiFile, checker.lineState!!.errorHolder)
Pair(compilerState.lastLineState!!.psiFile, compilerState.lastLineState!!.errorHolder)
}
val newDependencies = scriptDefinition.getDependenciesFor(psiFile, checker.environment.project, lastDependencies)
val newDependencies = scriptDefinition.getDependenciesFor(psiFile, checker.environment.project, compilerState.lastDependencies)
var classpathAddendum: List<File>? = null
if (lastDependencies != newDependencies) {
lastDependencies = newDependencies
if (compilerState.lastDependencies != newDependencies) {
compilerState.lastDependencies = newDependencies
classpathAddendum = newDependencies?.let { checker.environment.updateClasspath(it.classpath.map(::JvmClasspathRoot)) }
}
val analysisResult = analyzerEngine.analyzeReplLine(psiFile, codeLine)
val analysisResult = compilerState.analyzerEngine.analyzeReplLine(psiFile, codeLine)
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
val scriptDescriptor = when (analysisResult) {
is GenericReplAnalyzer.ReplLineAnalysisResult.WithErrors -> return ReplCompileResult.Error(descriptorsHistory.copySources(), errorHolder.renderedDiagnostics)
is GenericReplAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
is ReplCodeAnalyzer.ReplLineAnalysisResult.WithErrors -> return ReplCompileResult.Error(errorHolder.renderedDiagnostics)
is ReplCodeAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
else -> error("Unexpected result ${analysisResult.javaClass}")
}
val state = GenerationState(
val generationState = GenerationState(
psiFile.project,
ClassBuilderFactories.binaries(false),
analyzerEngine.module,
analyzerEngine.trace.bindingContext,
compilerState.analyzerEngine.module,
compilerState.analyzerEngine.trace.bindingContext,
listOf(psiFile),
compilerConfiguration
)
state.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
state.replSpecific.earlierScriptsForReplInterpreter = descriptorsHistory.copyValues()
state.beforeCompile()
generationState.replSpecific.scriptResultFieldName = SCRIPT_RESULT_FIELD_NAME
generationState.replSpecific.earlierScriptsForReplInterpreter = compilerState.history.map { it.item }
generationState.beforeCompile()
KotlinCodegenFacade.generatePackage(
state,
psiFile.script!!.getContainingKtFile().packageFqName,
setOf(psiFile.script!!.getContainingKtFile()),
generationState,
psiFile.script!!.containingKtFile.packageFqName,
setOf(psiFile.script!!.containingKtFile),
org.jetbrains.kotlin.codegen.CompilationErrorHandler.THROW_EXCEPTION)
val generatedClassname = makeScriptBaseName(codeLine, currentGeneration)
val compiledCodeLine = CompiledReplCodeLine(generatedClassname, codeLine)
descriptorsHistory.add(compiledCodeLine, scriptDescriptor)
compilerState.history.push(LineId(codeLine), scriptDescriptor)
return ReplCompileResult.CompiledClasses(descriptorsHistory.copySources(),
compiledCodeLine,
return ReplCompileResult.CompiledClasses(LineId(codeLine),
generatedClassname,
state.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) },
state.replSpecific.hasResult,
classpathAddendum ?: emptyList())
generationState.factory.asList().map { CompiledClassData(it.relativePath, it.asByteArray()) },
generationState.replSpecific.hasResult,
classpathAddendum ?: emptyList())
}
}
@@ -21,7 +21,6 @@ package org.jetbrains.kotlin.cli.jvm.repl
import org.jetbrains.kotlin.cli.common.repl.CompiledReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine
import org.jetbrains.kotlin.cli.common.repl.ReplHistory
import org.jetbrains.kotlin.cli.common.repl.ReplResettableCodeLine
import org.jetbrains.kotlin.cli.jvm.compiler.CliLightClassGenerationSupport
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
@@ -43,23 +42,18 @@ import org.jetbrains.kotlin.resolve.scopes.ImportingScope
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
import org.jetbrains.kotlin.resolve.scopes.utils.replaceImportingScopes
import org.jetbrains.kotlin.script.ScriptPriorities
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
import kotlin.concurrent.write
class GenericReplAnalyzer(environment: KotlinCoreEnvironment,
protected val stateLock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : ReplResettableCodeLine {
class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
private val topDownAnalysisContext: TopDownAnalysisContext
private val topDownAnalyzer: LazyTopDownAnalyzer
private val resolveSession: ResolveSession
private val scriptDeclarationFactory: ScriptMutableDeclarationProviderFactory
private val replState = ResettableReplState()
private val replState = ResettableAnalyzerState()
val module: ModuleDescriptorImpl
get() = stateLock.read { field }
val trace: BindingTraceContext = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
get() = stateLock.read { field }
init {
// Module source scope is empty because all binary classes are in the dependency module, and all source classes are guaranteed
@@ -94,21 +88,15 @@ class GenericReplAnalyzer(environment: KotlinCoreEnvironment,
}
}
override fun resetToLine(lineNumber: Int): List<ReplCodeLine> {
return stateLock.write { replState.resetToLine(lineNumber) }
}
override fun resetToLine(line: ReplCodeLine): List<ReplCodeLine> = resetToLine(line.no)
fun resetToLine(lineNumber: Int): List<ReplCodeLine> = replState.resetToLine(lineNumber)
fun analyzeReplLine(psiFile: KtFile, codeLine: ReplCodeLine): ReplLineAnalysisResult {
return stateLock.write {
topDownAnalysisContext.scripts.clear()
trace.clearDiagnostics()
topDownAnalysisContext.scripts.clear()
trace.clearDiagnostics()
psiFile.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, codeLine.no)
psiFile.script!!.putUserData(ScriptPriorities.PRIORITY_KEY, codeLine.no)
doAnalyze(psiFile, codeLine)
}
return doAnalyze(psiFile, codeLine)
}
private fun doAnalyze(linePsi: KtFile, codeLine: ReplCodeLine): ReplLineAnalysisResult {
@@ -179,7 +167,8 @@ class GenericReplAnalyzer(environment: KotlinCoreEnvironment,
}
// TODO: merge with org.jetbrains.kotlin.resolve.repl.ReplState when switching to new REPL infrastruct everywhere
class ResettableReplState {
// TODO: review it's place in the extracted state infrastruct (now the analyzer itself is a part of the state
class ResettableAnalyzerState {
private val successfulLines = ReplHistory<LineInfo.SuccessfulLine>()
private val submittedLines = hashMapOf<KtFile, LineInfo>()
@@ -189,8 +178,6 @@ class GenericReplAnalyzer(environment: KotlinCoreEnvironment,
return removed.map { it.first }
}
fun resetToLine(line: ReplCodeLine): List<ReplCodeLine> = resetToLine(line.no)
fun submitLine(ktFile: KtFile, codeLine: ReplCodeLine) {
val line = LineInfo.SubmittedLine(ktFile, successfulLines.lastValue())
submittedLines[ktFile] = line
@@ -64,7 +64,7 @@ class ReplInterpreter(
}
private val psiFileFactory: PsiFileFactoryImpl = PsiFileFactory.getInstance(environment.project) as PsiFileFactoryImpl
private val analyzerEngine = GenericReplAnalyzer(environment)
private val analyzerEngine = ReplCodeAnalyzer(environment)
fun eval(line: String): LineResult {
++lineNumber
@@ -101,8 +101,8 @@ class ReplInterpreter(
val analysisResult = analyzerEngine.analyzeReplLine(psiFile, ReplCodeLine(lineNumber, "fake line"))
AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder)
val scriptDescriptor = when (analysisResult) {
is GenericReplAnalyzer.ReplLineAnalysisResult.WithErrors -> return LineResult.Error.CompileTime(errorHolder.renderedDiagnostics)
is GenericReplAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
is ReplCodeAnalyzer.ReplLineAnalysisResult.WithErrors -> return LineResult.Error.CompileTime(errorHolder.renderedDiagnostics)
is ReplCodeAnalyzer.ReplLineAnalysisResult.Successful -> analysisResult.scriptDescriptor
else -> error("Unexpected result ${analysisResult.javaClass}")
}