1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use crateevaluate_expr;
use crateEvalCtx;
use crateExpr;
use crate;
// ── Eager versions (kept for unit tests) ─────────────────────────────────────
/// `COUNT(value1, ...)` — count of Numbers and Dates.
/// Used only in unit tests; the evaluator uses the lazy version, which is the
/// one that implements COUNT's real direct-arg / array-context split.
///
/// A `Date` counts, for the reason set out on [`count_lazy_fn`].
/// `COUNTA(value1, ...)` — count of non-empty values.
// ── Lazy versions (registered) ────────────────────────────────────────────────
/// Lazy COUNT: in direct args counts Numbers, Dates, Bool, numeric Text; in
/// arrays counts only Numbers and Dates.
/// Returns #N/A when called with no arguments.
///
/// **A date counts.** In Google Sheets a date is a serial number carrying a
/// display format, and COUNT counts it wherever it appears — as a direct
/// argument, inside an array literal, and through a range. Captured on the
/// conformance-fixtures pipeline (2026-08-04, locale `en_US`, timezone
/// `Etc/GMT`), with the control `=COUNT(5)` → 1 proving the probe resolved:
///
/// ```text
/// =COUNT(DATE(2020,1,1)) 1
/// =COUNT(DATE(2020,1,1),DATE(2021,1,1)) 2
/// =COUNT({DATE(2020,1,1),DATE(2021,1,1)}) 2
/// =COUNT({DATE(2020,1,1),5}) 2
/// =COUNT(<a range of three dates>) 3
/// =COUNT(<a range of two dates and a 5>) 3
/// =COUNT(MAX(<a range of three dates>)) 1
/// =COUNT({DATE(2020,1,1),TRUE}) 1
/// =COUNT({DATE(2020,1,1),"a"}) 1
/// ```
///
/// Sibling extremes were probed alongside it: `=COUNT(MIN(...))`,
/// `=COUNT(MAXA(...))`, `=COUNT(MINA(...))` and `=COUNT(LARGE(...,1))` over a
/// date range are all 1.
///
/// **None of those rows are in this repo yet.** They come off the
/// conformance-fixtures pipeline and land in a separate fixtures-only PR — CI
/// rejects a PR that mixes fixture TSVs with code. A reviewer working from
/// this repo alone can check the unit tests and this comment; the Sheets
/// answers themselves have to be taken from that pipeline.
///
/// Counting a date changes nothing else. The last two captured rows above say
/// so directly, and they agree with what `statistical.tsv` already records for
/// booleans and text on their own (`=COUNT(TRUE,FALSE,1)` is 3,
/// `=COUNT({TRUE,FALSE,1,2})` is 2, `=COUNT({"1","2","3"})` is 0): a date
/// beside a boolean or a string does not pull either into an array's scope.
///
/// Two gaps this probe found are **not** fixed here:
///
/// - `=COUNT("2020-01-01")` is 1 in Sheets and 0 here. That is a rule about
/// *text* — Sheets reads a date- or time-shaped string as a number in direct
/// args, while this arm counts only text that parses as an `f64` — not a
/// rule about `Date` values. Array context already agrees. See #790.
/// - `SUBTOTAL`'s collector and `DCOUNT` drop a `Date` through the same shape
/// of catch-all this function just lost. See #792.
/// COUNT's direct-argument rules.
///
/// Every `Value` variant is spelled out rather than swept up by a catch-all,
/// so a variant added later is a compile error here instead of being silently
/// uncounted — which is exactly how `Date` came to be missed.
/// COUNT's array-context rules: only Numbers and Dates count — booleans and
/// text do not, which `statistical.tsv` records (`=COUNT({TRUE,FALSE,1,2})` is
/// 2, `=COUNT({"1","2","3"})` is 0).
///
/// Exhaustive for the same reason as [`count_direct`].
/// Lazy COUNTA: counts everything that is not Empty (including errors).
/// Arrays are flattened: each non-empty element is counted individually.
/// Returns #N/A when called with no arguments.
/// COUNTA's rule: everything that is not blank counts, errors included.
///
/// Spelled out rather than left as a catch-all so a variant added later is a
/// compile error here too — the rule below is "count it", but that is a
/// decision to take deliberately for a new kind of value rather than inherit.