Do not activate power assertions when a single union member containing a type constraint fails (#1462)

Prior to this change, this code would activate powers assertions /
instrumentation permanently:
```pkl
foo: String(contains("a")) | String(contains("b")) = "boo"
```

This is because the `contains("a")` constraint would fail, triggering
power assertions, but the subsequent check of the union's
`contains("b")` branch would succeed.
As observed in #1419, once instrumentation is enabled, all subsequent
evaluation slows significantly.
As with #1419, the fix here is to disable power assertions via
`VmLocalContext` until we know that all union members failed type
checking; then, each member is re-executed with power assertions allowed
to provide the improved user-facing error.
This commit is contained in:
Jen Basch
2026-03-25 11:52:37 -07:00
committed by GitHub
parent f23c37a993
commit a9c890e2f9
4 changed files with 134 additions and 6 deletions
@@ -566,6 +566,69 @@ class EvaluatorTest {
)
}
@Test
fun `constraint failures activate instrumentation`() {
val evaluator =
with(EvaluatorBuilder.preconfigured()) {
powerAssertionsEnabled = true
build()
}
val exc =
assertThrows<PklException> {
evaluator.evaluate(
text(
"""
foo: String(chars.first == "a") = "boo"
"""
.trimIndent()
)
)
}
assertThat((evaluator as EvaluatorImpl).isInstrumentationEverUsed()).isTrue
}
@Test
fun `union single-member constraint failures do not activate instrumentation`() {
val evaluator =
with(EvaluatorBuilder.preconfigured()) {
powerAssertionsEnabled = true
build()
}
evaluator.evaluate(
text(
"""
foo: String(startsWith("a")) | String(startsWith("b")) | String(startsWith("c")) = "cool"
"""
.trimIndent()
)
)
assertThat((evaluator as EvaluatorImpl).isInstrumentationEverUsed()).isFalse
}
@Test
fun `type test failures do not activate instrumentation`() {
val evaluator =
with(EvaluatorBuilder.preconfigured()) {
powerAssertionsEnabled = true
build()
}
evaluator.evaluate(
text(
"""
foo = "bar" is Int(this > 0)
"""
.trimIndent()
)
)
assertThat((evaluator as EvaluatorImpl).isInstrumentationEverUsed()).isFalse
}
private fun checkModule(module: PModule) {
assertThat(module.properties.size).isEqualTo(2)
assertThat(module.getProperty("name")).isEqualTo("pigeon")