diff --git a/crates/calc/src/recalc.rs b/crates/calc/src/recalc.rs index 2aa23645c..cfef5f478 100644 --- a/crates/calc/src/recalc.rs +++ b/crates/calc/src/recalc.rs @@ -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; } diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index c90802128..72d67f5cd 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -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();