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 de787924bdd..64b15122d46 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 @@ -53,6 +53,7 @@ open class BasicReplStageHistory(override val lock: ReentrantReadWriteLock = lock.write { val removed = map { it.id } clear() + currentGeneration.incrementAndGet() return removed } } @@ -67,7 +68,10 @@ open class BasicReplStageHistory(override val lock: ReentrantReadWriteLock = currentGeneration.incrementAndGet() removed } - else emptyList() + else { + currentGeneration.incrementAndGet() + emptyList() + } } } } diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/GenericReplCompilingEvaluator.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/GenericReplCompilingEvaluator.kt index dbbc4fb8d38..cda2ce466ff 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/GenericReplCompilingEvaluator.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/repl/GenericReplCompilingEvaluator.kt @@ -35,7 +35,15 @@ class GenericReplCompilingEvaluator(val compiler: ReplCompiler, val aggregatedState = state.asState(AggregatedReplStageState::class.java) val compiled = compiler.compile(state, codeLine) when (compiled) { - is ReplCompileResult.Error -> ReplEvalResult.Error.CompileTime(compiled.message, compiled.location) + is ReplCompileResult.Error -> { + aggregatedState.apply { + lock.write { + assert(state1.history.size == state2.history.size) + adjustHistories() // needed due to statefulness of AnalyzerEngine - in case of compilation errors the line name reuse leads to #KT-17921 + } + } + ReplEvalResult.Error.CompileTime(compiled.message, compiled.location) + } is ReplCompileResult.Incomplete -> ReplEvalResult.Incomplete() is ReplCompileResult.CompiledClasses -> { val result = eval(state, compiled, scriptArgs, invokeWrapper) @@ -46,14 +54,7 @@ class GenericReplCompilingEvaluator(val compiler: ReplCompiler, aggregatedState.apply { lock.write { if (state1.history.size > state2.history.size) { - if (state2.history.size == 0) { - state1.history.reset() - } - else { - state2.history.peek()?.let { - state1.history.resetTo(it.id) - } - } + adjustHistories() assert(state1.history.size == state2.history.size) } } @@ -91,3 +92,9 @@ class GenericReplCompilingEvaluator(val compiler: ReplCompiler, evaluator.eval(state, compiledCode, scriptArgs ?: defaultScriptArgs, invokeWrapper) } } + +private fun AggregatedReplStageState<*, *>.adjustHistories(): Iterable? = + state2.history.peek()?.let { + state1.history.resetTo(it.id) + } + ?: state1.history.reset() diff --git a/libraries/examples/kotlin-jsr223-local-example/src/test/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineIT.kt b/libraries/examples/kotlin-jsr223-local-example/src/test/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineIT.kt index 1aeccf325df..c2128c720e5 100644 --- a/libraries/examples/kotlin-jsr223-local-example/src/test/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineIT.kt +++ b/libraries/examples/kotlin-jsr223-local-example/src/test/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineIT.kt @@ -72,6 +72,46 @@ class KotlinJsr223LocalScriptEngineIT { Assert.assertEquals(5, res2) } + @Test + fun testEvalWithError() { + val engine = ScriptEngineManager().getEngineByExtension("kts")!! + + try { + engine.eval("java.lang.fish") + Assert.fail("Script error expected") + } + catch (e: ScriptException) {} + + val res1 = engine.eval("val x = 3") + Assert.assertNull(res1) + + try { + engine.eval("y") + Assert.fail("Script error expected") + } + catch (e: ScriptException) { + Assert.assertTrue("Expected message to contain \"unresolved reference: y\", actual: \"${e.message}\"", + e.message?.contains("unresolved reference: y") ?: false) + } + + val res3 = engine.eval("x + 2") + Assert.assertEquals(5, res3) + } + + @Test + fun testEngineRepeatWithReset() { + val code = "open class A {}\n" + + "class B : A() {}" + val engine = ScriptEngineManager().getEngineByExtension("kts") as KotlinJsr223JvmLocalScriptEngine + + val res1 = engine.eval(code) + Assert.assertNull(res1) + + engine.state.history.reset() + + engine.eval(code) + } + @Test fun testInvocable() { val engine = ScriptEngineManager().getEngineByExtension("kts")!!