Recalc: an array that read another array's old spill is evaluated again

When two dynamic arrays were recalculated in the same pass and the
first read the second's spill area before the second was evaluated, it
read the old values. Formulas reading a spill area that changed are
evaluated again, but dynamic arrays were left out of that second round
(only to keep an array from re-queuing itself), so with D11 =
SEQUENCE(1,3,A1) and G5 = UNIQUE(VSTACK(F9:F12,A1)), changing A1 from 1
to 10 left 3 in G6 instead of 12. Only the array itself is left out
now.
This commit is contained in:
nihilist-narwhal
2026-10-10 04:42:51 -05:00
parent 880163d135
commit 303eabaad1
2 changed files with 14 additions and 2 deletions
+1 -2
View File
@@ -571,7 +571,7 @@ impl Calc {
if let Some(r) = changed_range {
let mut deps = Vec::new();
self.graph.dependents_of_range(k.0, r, &mut deps);
spill_changes.extend(deps);
spill_changes.extend(deps.into_iter().filter(|d| d != k));
}
if let Some(o) = old
&& !sheet.spill_ranges.get(&k.1).is_some_and(|n| n.contains(o.start) && n.contains(o.end))
@@ -599,7 +599,6 @@ impl Calc {
}
spill_changes.sort_by_key(|(s, c)| (*s, c.row, c.col));
spill_changes.dedup();
spill_changes.retain(|k| !spills.contains_key(k));
if spill_changes.is_empty() {
break;
}
+13
View File
@@ -206,6 +206,19 @@ fn a_spill_that_goes_away_unblocks_another() {
assert_eq!((v(&s, "E10"), v(&s, "G10")), (Value::Number(1.0), Value::Number(3.0)));
}
#[test]
fn an_array_reading_another_arrays_spill_is_updated() {
// G5 is evaluated before D11 in the same pass, so it first reads D11's old spill.
let mut s = s();
s.execute("cell.set", json!({"cell": "A1", "input": "1"})).unwrap();
s.execute("cell.set", json!({"cell": "D11", "input": "=SEQUENCE(1,3,A1)"})).unwrap();
s.execute("cell.set", json!({"cell": "G5", "input": "=UNIQUE(VSTACK(F9:F12,A1))"})).unwrap();
s.execute("cell.set", json!({"cell": "A1", "input": "10"})).unwrap();
assert_eq!((v(&s, "G6"), v(&s, "G7")), (Value::Number(12.0), Value::Number(10.0)));
s.execute("formulas.calculateNow", json!({})).unwrap();
assert_eq!((v(&s, "G6"), v(&s, "G7")), (Value::Number(12.0), Value::Number(10.0)));
}
#[test]
fn every_command_survives_empty_params() {
let mut s = Session::new();