Fix: Apply substitutions to upvalue types

When an identifier is used as an upvalue within a nested scope (e.g., a
`while` loop), the type checker needs to apply the global substitution
map to resolve `TypeVar`s that might have been determined in outer
scopes. This ensures that the correct type is used even if
`ctx.set_type` couldn't propagate the change directly through the
upvalue address.

This fix also includes a regression test to specifically cover this
scenario with series and closures.
This commit is contained in:
2026-03-28 14:22:25 +01:00
parent 9c85fb605b
commit 350b7b49b6
2 changed files with 30 additions and 2 deletions
+25
View File
@@ -40,6 +40,31 @@ fn test_series_infer_type_from_nested_closure() {
}
}
/// Regression test: TypeVar on a series used as an upvalue inside a `while` loop
/// (zero-parameter lambda created by the macro) must be resolved via the global
/// substitution even when `ctx.set_type` silently ignores the upvalue address.
#[test]
fn test_series_typevar_resolved_through_while_upvalue() {
let env = Environment::new();
let source = r#"
(do
(def ticks (series 10))
(def i 0)
(while (< i 3)
(do
(push ticks {:price (* i 1.0)})
(assign i (+ i 1))))
(def p (.price ticks))
(p 0)
)
"#;
let result = env.run_script(source);
match result {
Ok(Value::Float(v)) if (v - 2.0).abs() < 1e-9 => {}
other => panic!("Expected Float(2.0), got {:?}", other),
}
}
#[test]
fn test_record_structural_equality_order() {
let env = Environment::new();