A formula typed last, reading an array's cells, closed a cycle through an array blocked by a value, which isn't computed again for it: the array kept spilling where opening the file blocked both (fuzz input 8fbc50e2c14bfe4c). As for arrays blocked by a cycle, the arrays are checked again the first time one is found blocked still in a recalculation.
- commit
- 98cc85531ad3481a822a7d9b4e71c5ef92c63ffe
- parent
- fddc65e77d6cd4e9c1928f37e5d1a7859e9411e5
- author
- Dami <dami.etoile@gmail.com>
- kind
- fix risk score 1.4 of 3, Jev's estimate
| M | internal/ | 4 | +--- |
| M | internal/ | 19 | +++++++++++++++++++ |
| M | internal/ | 7 | +++++++ |
| A | internal/ | 2 | ++ |
@@ -154,9 +154,7 @@ func (s *Sheet) applySpill(a Addr, p pendingSpill) ([]loc, bool) {
154154 changed = s.wb.recheckArrays(loc{s, a})155155 }156156 if why != "" {157- if !circ && (old == nil || old.why == "" || old.area != area) {158- // Blocked over other cells, it may close or open a cycle159- // through arrays that read them (spill.walked).157+ if !circ && s.wb.blockedMoved(old, area) {160158 changed = append(changed, s.wb.recheckArrays(loc{s, a})...)161159 }162160 changed = append(changed, s.dropSpill(a)...)@@ -112,6 +112,25 @@ func (w *Workbook) cycleMoved(circ bool, old *spill) bool {
112112 return false113113 }114114 115+// blockedMoved reports whether the arrays are to be checked again, an116+// array whose spill was old found blocked over area by something other117+// than a cycle: counted as spilling over the cells it needs (walked), it118+// may close or open a cycle through arrays that read them, when it's119+// blocked over other cells, or blocked still, the first time in the120+// recalculation: a formula on the way around a cycle through it may121+// have changed, which the others aren't computed again for, as in122+// cycleMoved.123+func (w *Workbook) blockedMoved(old *spill, area Rect) bool {124+ switch {125+ case old == nil || old.why == "" || old.area != area:126+ return true127+ case !w.spillRechecked:128+ w.spillRechecked = true129+ return true130+ }131+ return false132+}133+115134 // noteCycle counts the array at l found blocked by a cycle, from spilling116135 // or not, in the recalculation.117136 func (w *Workbook) noteCycle(l loc) {@@ -77,6 +77,13 @@ func TestCycleThroughABlockedArray(t *testing.T) {
7777 }7878 }7979 80+// A formula typed last closing a cycle through an array blocked by a81+// value has the arrays checked again, as when the file opens.82+func TestCycleClosedThroughABlockedArray(t *testing.T) {83+ cells := map[string]string{"D9": "=SORT(G15:H19)", "E9": "=COUNTIF(A9:A12,\">2\")", "B16": "=ABS($A$9)+1", "H19": "=SORT(B13:D16)", "H16": "=COUNTIF(H20,\">2\")"}84+ wantSettled(t, "closed", []string{"D9", "E9", "B16", "H19", "H16"}, cells, map[string]string{"D9": "#REF!", "H19": "#REF!"})85+}86+8087 // A blocked array that goes, its formula computing one value, frees the8188 // arrays whose cycle went through the cells it needed (spill.walked):8289 // once Total is defined, B7 reads its own #REF! through G9.