Fix eval -x of local members (#1760)

This fixes a regression where local members cannot be seen by the
expression evaluator.

Because variable are now parse-time resolved, this builds a truffle node
by first constructing a synthetic module of all defined local members,
and calls AstBuilder on this synthetic module first.
This commit is contained in:
Daniel Chao
2026-07-11 00:03:15 +00:00
committed by GitHub
parent b4ca82bf36
commit 60b0d86b5f
9 changed files with 171 additions and 63 deletions
@@ -0,0 +1,3 @@
// make sure that we don't trim this identifier when not using the expression evaluator
// see VmUtils.buildSyntheticModuleText()
`THE REPL TEXT EXPR` = throw("uh oh")
@@ -0,0 +1,14 @@
–– Pkl Error ––
uh oh
x | `THE REPL TEXT EXPR` = throw("uh oh")
^^^^^^^^^^^^^^
at replTextPreamble#`THE REPL TEXT EXPR` (file:///$snippetsDir/input/errors/replTextPreamble.pkl)
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)
@@ -134,4 +134,43 @@ class EvaluateExpressionTest {
assertThat(error).hasMessageContaining("Expected value of type `String`, but got type `Int`")
}
@Test
fun `evaluate local property`() {
val result = evaluate("local foo = 1", "foo")
assertThat(result).isEqualTo(1L)
}
@Test
fun `evaluate throwing local property trims expression preamble when rendering stack frames`() {
val error = assertThrows<PklException> { evaluate("local foo = throw(\"uh oh\")", "foo") }
assertThat(error.message)
.isEqualTo(
"""
–– Pkl Error ––
uh oh
1 | local foo = throw("uh oh")
^^^^^^^^^^^^^^
at text#foo (repl:text)
1 | foo
^^^
at (repl:text)
"""
.trimIndent()
)
}
@Test
fun `evaluate import`() {
val result = evaluate("import \"pkl:base\"", "base")
assertThat(result).isInstanceOf(PModule::class.java)
result as PModule
assertThat(result.moduleName).isEqualTo("pkl.base")
}
}
@@ -192,7 +192,7 @@ class StackTraceRendererTest {
val loop = StackTraceRenderer.StackFrameLoop(loopFrames, 1)
val frames = listOf(createFrame("bar", 1), createFrame("baz", 2), loop)
val formatter = AnsiStringBuilder(false)
renderer.doRender(frames, null, null, formatter, "", true)
renderer.doRender(frames, null, null, formatter, "", true, true)
val renderedFrames = formatter.toString()
assertThat(renderedFrames)
.isEqualTo(