diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/BasicReplState.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/BasicReplState.kt index 0636a3e7c3b..4214f95244b 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/BasicReplState.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/BasicReplState.kt @@ -36,6 +36,7 @@ data class LineId(override val no: Int, override val generation: Int, private va open class BasicReplStageHistory(override val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()) : IReplStageHistory, ArrayList>() { + val currentLineNumber = AtomicInteger(REPL_CODE_LINE_FIRST_NO) val currentGeneration = AtomicInteger(REPL_CODE_LINE_FIRST_GEN) override fun push(id: ILineId, item: T) { @@ -51,6 +52,7 @@ open class BasicReplStageHistory(override val lock: ReentrantReadWriteLock = val removed = map { it.id } clear() currentGeneration.incrementAndGet() + currentLineNumber.set(REPL_CODE_LINE_FIRST_NO) return removed } } @@ -68,9 +70,13 @@ open class BasicReplStageHistory(override val lock: ReentrantReadWriteLock = val removed = asSequence().drop(idx + 1).map { it.id }.toList() removeRange(idx + 1, size) currentGeneration.incrementAndGet() + removed.lastOrNull()?.no?.let { + currentLineNumber.set(it) + } removed } else { currentGeneration.incrementAndGet() + currentLineNumber.set(id.no + 1) emptyList() } } @@ -80,5 +86,7 @@ open class BasicReplStageState(override final val lock: ReentrantR override val currentGeneration: Int get() = history.currentGeneration.get() + override fun getNextLineNo(): Int = history.currentLineNumber.getAndIncrement() + override val history: BasicReplStageHistory = BasicReplStageHistory(lock) } diff --git a/libraries/scripting/jsr223-test/test/kotlin/script/experimental/jsr223/test/KotlinJsr223ScriptEngineIT.kt b/libraries/scripting/jsr223-test/test/kotlin/script/experimental/jsr223/test/KotlinJsr223ScriptEngineIT.kt index 94a86cc5fe4..bd2ae9d572e 100644 --- a/libraries/scripting/jsr223-test/test/kotlin/script/experimental/jsr223/test/KotlinJsr223ScriptEngineIT.kt +++ b/libraries/scripting/jsr223-test/test/kotlin/script/experimental/jsr223/test/KotlinJsr223ScriptEngineIT.kt @@ -441,6 +441,18 @@ obj tempDir.toFile().deleteRecursively() } } + + @Test + fun testEvalWithCompilationError() { + val engine = ScriptEngineManager().getEngineByExtension("kts") + val compilable: Compilable = engine as Compilable + assertThrows(ScriptException::class.java) { + compilable.compile("foo") + } + compilable.compile("true") + engine.eval("val x = 3") + compilable.compile("x") + } } fun assertThrows(exceptionClass: Class<*>, body: () -> Unit) { 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 5a827359036..c1083b3613c 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 @@ -369,6 +369,19 @@ class ReplTest : TestCase() { ) } + @Test + fun testCompileWithoutEval() { + val replCompiler = KJvmReplCompilerBase() + val replEvaluator = BasicJvmReplEvaluator() + val compCfg = simpleScriptCompilationConfiguration + runBlocking { + replCompiler.compile("false".toScriptSource(), compCfg) + replCompiler.compile("true".toScriptSource(), compCfg).onSuccess { + replEvaluator.eval(it, simpleScriptEvaluationConfiguration) + } + } + } + companion object { private fun positionsEqual(a: SourceCode.Position?, b: SourceCode.Position?): Boolean { if (a == null || b == null) { 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 4f10a7f9266..1b672fadc21 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 @@ -7,6 +7,7 @@ package kotlin.script.experimental.jvmhost.repl import org.jetbrains.kotlin.cli.common.repl.* import org.jetbrains.kotlin.scripting.compiler.plugin.impl.KJvmReplCompilerBase +import org.jetbrains.kotlin.scripting.compiler.plugin.impl.currentLineId import org.jetbrains.kotlin.scripting.compiler.plugin.repl.JvmReplCompilerState import org.jetbrains.kotlin.scripting.compiler.plugin.repl.ReplCodeAnalyzerBase import java.util.concurrent.locks.ReentrantReadWriteLock @@ -38,10 +39,21 @@ class JvmReplCompiler( replCompilerState ) + val lineId = LineId(codeLine.no, codeLine.generation, snippet.hashCode()) + @Suppress("DEPRECATION_ERROR") - when (val res = internalScriptingRunSuspend { replCompiler.compile(listOf(snippet), scriptCompilationConfiguration) }) { + val res = internalScriptingRunSuspend { + replCompiler.compile( + listOf(snippet), + scriptCompilationConfiguration.with { + repl { + currentLineId(lineId) + } + } + ) + } + when (res) { is ResultWithDiagnostics.Success -> { - val lineId = LineId(codeLine.no, 0, snippet.hashCode()) ReplCompileResult.CompiledClasses( lineId, replCompiler.state.history.map { it.id }, 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 3aabdfec432..9cb2cbb9d4a 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 @@ -45,6 +45,7 @@ import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.impl.KJvmCompiledScript import kotlin.script.experimental.util.LinkedSnippet import kotlin.script.experimental.util.LinkedSnippetImpl +import kotlin.script.experimental.util.PropertiesCollection import kotlin.script.experimental.util.add // NOTE: this implementation, as it is used in the REPL infrastructure, may be created for every snippet and provided with the state @@ -105,14 +106,16 @@ open class KJvmReplCompilerBase( ) } - val snippetNo = state.getNextLineNo() + // TODO: ensure that currentLineId passing is only used for single snippet compilation + val lineId = configuration[ScriptCompilationConfiguration.repl.currentLineId] + ?: LineId(state.getNextLineNo(), state.currentGeneration, snippet.hashCode()) val analysisResult = compilationState.analyzerEngine.analyzeReplLineWithImportedScripts( snippetKtFile, sourceFiles.drop(1), snippet, - snippetNo + lineId.no ) AnalyzerWithCompilerReport.reportDiagnostics(analysisResult.diagnostics, errorHolder, renderDiagnosticName = false) @@ -148,7 +151,7 @@ open class KJvmReplCompilerBase( return failure(messageCollector, *scriptDiagnostics.toTypedArray()) } - state.history.push(LineId(snippetNo, 0, snippet.hashCode()), scriptDescriptor) + state.history.push(lineId, scriptDescriptor) val dependenciesProvider = ScriptDependenciesProvider.getInstance(context.environment.project) makeCompiledScript( @@ -366,3 +369,8 @@ class ReplCompilationState( val mangler: JvmDescriptorMangler get() = manglerAndSymbolTable.first val symbolTable: SymbolTable get() = manglerAndSymbolTable.second } + +/** + * Internal property for transferring line id information when using new repl infrastructure with legacy one + */ +val ReplScriptCompilationConfigurationKeys.currentLineId by PropertiesCollection.key(isTransient = true) 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 3582e01a40f..e1cc90781d5 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 @@ -26,6 +26,7 @@ class JvmReplCompilerState( override val history = JvmReplCompilerStageHistory(this) override val currentGeneration: Int get() = (history as BasicReplStageHistory<*>).currentGeneration.get() + override fun getNextLineNo(): Int = history.currentLineNumber.getAndIncrement() override fun dispose() { lock.write {