fix(logic): single-eval array index + typed reduce accumulators

- Fix redundant double-evaluation of n.a in the 'index' case by extracting
  to a local const before use in both idx() call and array indexing.
- Add explicit <number> type argument to reduce() calls in sum and mean
  functions to fix TypeScript TS2345 accumulator type error: the inferred
  ArrVal union type was not compatible with numeric addition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Martino Ferrari
2026-06-24 10:57:45 +02:00
parent 5578bceea2
commit f776de378f
+6 -3
View File
@@ -229,8 +229,8 @@ function idx(i: number, len: number): number {
const ARR_FUNCS: Record<string, (a: ArrVal[]) => ArrVal> = { const ARR_FUNCS: Record<string, (a: ArrVal[]) => ArrVal> = {
len: a => asArr(a[0]).length, len: a => asArr(a[0]).length,
sum: a => asArr(a[0]).reduce((s, x) => s + asNum(x), 0), sum: a => asArr(a[0]).reduce<number>((s, x) => s + asNum(x), 0),
mean: a => { const r = asArr(a[0]); return r.length ? r.reduce((s, x) => s + asNum(x), 0) / r.length : 0; }, mean: a => { const r = asArr(a[0]); return r.length ? r.reduce<number>((s, x) => s + asNum(x), 0) / r.length : 0; },
// min/max: scalar-variadic OR single-array — see ev() dispatch below // min/max: scalar-variadic OR single-array — see ev() dispatch below
slice: a => { const r = asArr(a[0]); const s = a[1] === undefined ? 0 : asNum(a[1]); const e = a[2] === undefined ? r.length : asNum(a[2]); return r.slice(s, e); }, slice: a => { const r = asArr(a[0]); const s = a[1] === undefined ? 0 : asNum(a[1]); const e = a[2] === undefined ? r.length : asNum(a[2]); return r.slice(s, e); },
concat: a => asArr(a[0]).concat(asArr(a[1])), concat: a => asArr(a[0]).concat(asArr(a[1])),
@@ -256,7 +256,10 @@ function ev(n: Node, R: Resolver): ArrVal {
case 'arr': return n.items.map(it => ev(it, R)); case 'arr': return n.items.map(it => ev(it, R));
case 'sig': return R(n.ds, n.name); case 'sig': return R(n.ds, n.name);
case 'var': return R('local', n.name); case 'var': return R('local', n.name);
case 'index': return asArr(ev(n.a, R))[idx(asNum(ev(n.i, R)), asArr(ev(n.a, R)).length)]; case 'index': {
const arr = asArr(ev(n.a, R));
return arr[idx(asNum(ev(n.i, R)), arr.length)];
}
case 'un': return n.op === '-' ? -asNum(ev(n.a, R)) : (asNum(ev(n.a, R)) === 0 ? 1 : 0); case 'un': return n.op === '-' ? -asNum(ev(n.a, R)) : (asNum(ev(n.a, R)) === 0 ? 1 : 0);
case 'tern': return asNum(ev(n.c, R)) !== 0 ? ev(n.a, R) : ev(n.b, R); case 'tern': return asNum(ev(n.c, R)) !== 0 ? ev(n.a, R) : ev(n.b, R);
case 'call': { case 'call': {