::: { T:{s:s, n:n, qn:n?, r8:r8, qr8:r8?, r4:r4, qr4:r4?, i:i, qi:i?, i8:i8, qi8:i8?, i4:i4, qi4:i4?, i2:i2, qi2:i2?, i1:i1, qi1:i1?, u8:u8, qu8:u8?, u4:u4, qu4:u4?, u2:u2, qu2:u2?, u1:u1, qu1:u1?, b:b, qb:b?}* }
::+ { U:{A:i4}*, R:{A:i4} }
::+ { r8s:r8*, r4s:r4*, i8s:i8*, i4s:i4*, i2s:i2*, i1s:i1*, u8s:u8*, u4s:u4*, u2s:u2*, u1s:u1*, ias:ia*, bs:b* }
::+ { qr8s:r8?*, qr4s:r4?*, qi8s:i8?*, qi4s:i4?*, qi2s:i2?*, qi1s:i1?*, qu8s:u8?*, qu4s:u4?*, qu2s:u2?*, qu1s:u1?*, qias:ia?*, qbs:b?* }
::+ { vs:v* }

// Numeric sequence types.
Sum(r8s)
Min(r8s)
Max(r8s)
MinMax(r8s)
SumC(r8s)
MinC(r8s)
MaxC(r8s)
MinMaxC(r8s)

Sum(r4s)
Min(r4s)
Max(r4s)
MinMax(r4s)
SumC(r4s)
MinC(r4s)
MaxC(r4s)
MinMaxC(r4s)

Sum(i8s)
Min(i8s)
Max(i8s)
MinMax(i8s)
SumC(i8s)
MinC(i8s)
MaxC(i8s)
MinMaxC(i8s)

Sum(i4s)
Min(i4s)
Max(i4s)
MinMax(i4s)
SumC(i4s)
MinC(i4s)
MaxC(i4s)
MinMaxC(i4s)

Sum(i2s)
Min(i2s)
Max(i2s)
MinMax(i2s)
SumC(i2s)
MinC(i2s)
MaxC(i2s)
MinMaxC(i2s)

Sum(i1s)
Min(i1s)
Max(i1s)
MinMax(i1s)
SumC(i1s)
MinC(i1s)
MaxC(i1s)
MinMaxC(i1s)

Sum(u8s)
Min(u8s)
Max(u8s)
MinMax(u8s)
SumC(u8s)
MinC(u8s)
MaxC(u8s)
MinMaxC(u8s)

Sum(u4s)
Min(u4s)
Max(u4s)
MinMax(u4s)
SumC(u4s)
MinC(u4s)
MaxC(u4s)
MinMaxC(u4s)

Sum(u2s)
Min(u2s)
Max(u2s)
MinMax(u2s)
SumC(u2s)
MinC(u2s)
MaxC(u2s)
MinMaxC(u2s)

Sum(u1s)
Min(u1s)
Max(u1s)
MinMax(u1s)
SumC(u1s)
MinC(u1s)
MaxC(u1s)
MinMaxC(u1s)

Sum(ias)
Min(ias)
Max(ias)
MinMax(ias)
SumC(ias)
MinC(ias)
MaxC(ias)
MinMaxC(ias)

Sum(bs)
Min(bs)
Max(bs)
MinMax(bs)
SumC(bs)
MinC(bs)
MaxC(bs)
MinMaxC(bs)

// Opt numeric sequence types.
Sum(qr8s)
Min(qr8s)
Max(qr8s)
MinMax(qr8s)
SumC(qr8s)
MinC(qr8s)
MaxC(qr8s)
MinMaxC(qr8s)

Sum(qr4s)
Min(qr4s)
Max(qr4s)
MinMax(qr4s)
SumC(qr4s)
MinC(qr4s)
MaxC(qr4s)
MinMaxC(qr4s)

Sum(qi8s)
Min(qi8s)
Max(qi8s)
MinMax(qi8s)
SumC(qi8s)
MinC(qi8s)
MaxC(qi8s)
MinMaxC(qi8s)

Sum(qi4s)
Min(qi4s)
Max(qi4s)
MinMax(qi4s)
SumC(qi4s)
MinC(qi4s)
MaxC(qi4s)
MinMaxC(qi4s)

Sum(qi2s)
Min(qi2s)
Max(qi2s)
MinMax(qi2s)
SumC(qi2s)
MinC(qi2s)
MaxC(qi2s)
MinMaxC(qi2s)

Sum(qi1s)
Min(qi1s)
Max(qi1s)
MinMax(qi1s)
SumC(qi1s)
MinC(qi1s)
MaxC(qi1s)
MinMaxC(qi1s)

Sum(qu8s)
Min(qu8s)
Max(qu8s)
MinMax(qu8s)
SumC(qu8s)
MinC(qu8s)
MaxC(qu8s)
MinMaxC(qu8s)

Sum(qu4s)
Min(qu4s)
Max(qu4s)
MinMax(qu4s)
SumC(qu4s)
MinC(qu4s)
MaxC(qu4s)
MinMaxC(qu4s)

Sum(qu2s)
Min(qu2s)
Max(qu2s)
MinMax(qu2s)
SumC(qu2s)
MinC(qu2s)
MaxC(qu2s)
MinMaxC(qu2s)

Sum(qu1s)
Min(qu1s)
Max(qu1s)
MinMax(qu1s)
SumC(qu1s)
MinC(qu1s)
MaxC(qu1s)
MinMaxC(qu1s)

Sum(qias)
Min(qias)
Max(qias)
MinMax(qias)
SumC(qias)
MinC(qias)
MaxC(qias)
MinMaxC(qias)

Sum(qbs)
Min(qbs)
Max(qbs)
MinMax(qbs)
SumC(qbs)
MinC(qbs)
MaxC(qbs)
MinMaxC(qbs)

// These pairs should produce identical bound trees.

Sum(T, n)
Sum(T.n)
Min(T, n)
Min(T.n)
Max(T, n)
Max(T.n)
MinMax(T, n)
MinMax(T.n)
SumC(T, n)
SumC(T.n)
MinC(T, n)
MinC(T.n)
MaxC(T, n)
MaxC(T.n)
MinMaxC(T, n)
MinMaxC(T.n)

Sum(T, qn)
Sum(T.qn)
Min(T, qn)
Min(T.qn)
Max(T, qn)
Max(T.qn)
MinMax(T, qn)
MinMax(T.qn)
SumC(T, qn)
SumC(T.qn)
MinC(T, qn)
MinC(T.qn)
MaxC(T, qn)
MaxC(T.qn)
MinMaxC(T, qn)
MinMaxC(T.qn)

Sum(T, i2) // Needs type promotion.
Sum(T.i2) // Needs type promotion.
Min(T, i2)
Min(T.i2)
Max(T, i2)
Max(T.i2)
MinMax(T, i2)
MinMax(T.i2)
SumC(T, i2) // Needs type promotion.
SumC(T.i2) // Needs type promotion.
MinC(T, i2)
MinC(T.i2)
MaxC(T, i2)
MaxC(T.i2)
MinMaxC(T, i2)
MinMaxC(T.i2)

Sum(T, u1) // Needs type promotion.
Sum(T.u1) // Needs type promotion.

Sum(T, i4 * i2)
Sum(T.i4 * T.i2)
Min(T, i4 * i2)
Min(T.i4 * T.i2)
Max(T, i4 * i2)
Max(T.i4 * T.i2)
MinMax(T, i4 * i2)
MinMax(T.i4 * T.i2)
SumC(T, i4 * i2)
SumC(T.i4 * T.i2)
MinC(T, i4 * i2)
MinC(T.i4 * T.i2)
MaxC(T, i4 * i2)
MaxC(T.i4 * T.i2)
MinMaxC(T, i4 * i2)
MinMaxC(T.i4 * T.i2)

Sum(T, qi4 * i2)
Sum(T.qi4 * T.i2)
Min(T, qi4 * i2)
Min(T.qi4 * T.i2)
Max(T, qi4 * i2)
Max(T.qi4 * T.i2)
MinMax(T, qi4 * i2)
MinMax(T.qi4 * T.i2)
SumC(T, qi4 * i2)
SumC(T.qi4 * T.i2)
MinC(T, qi4 * i2)
MinC(T.qi4 * T.i2)
MaxC(T, qi4 * i2)
MaxC(T.qi4 * T.i2)
MinMaxC(T, qi4 * i2)
MinMaxC(T.qi4 * T.i2)

Sum(T, U, i4 * A)
Sum(T.i4 * U.A)
Min(T, U, i4 * A)
Min(T.i4 * U.A)
Max(T, U, i4 * A)
Max(T.i4 * U.A)
MinMax(T, U, i4 * A)
MinMax(T.i4 * U.A)
SumC(T, U, i4 * A)
SumC(T.i4 * U.A)
MinC(T, U, i4 * A)
MinC(T.i4 * U.A)
MaxC(T, U, i4 * A)
MaxC(T.i4 * U.A)
MinMaxC(T, U, i4 * A)
MinMaxC(T.i4 * U.A)

Sum(T, U, qi4 * A)
Sum(T.qi4 * U.A)
Min(T, U, qi4 * A)
Min(T.qi4 * U.A)
Max(T, U, qi4 * A)
Max(T.qi4 * U.A)
MinMax(T, U, qi4 * A)
MinMax(T.qi4 * U.A)
SumC(T, U, qi4 * A)
SumC(T.qi4 * U.A)
MinC(T, U, qi4 * A)
MinC(T.qi4 * U.A)
MaxC(T, U, qi4 * A)
MaxC(T.qi4 * U.A)
MinMaxC(T, U, qi4 * A)
MinMaxC(T.qi4 * U.A)

Sum(x: T.i4 * 2, 9 max #x)
Min(x: T.i4 * 2, 9 max #x)
Max(x: T.i4 * 2, 9 max #x)
MinMax(x: T.i4 * 2, 9 max #x)
SumC(x: T.i4 * 2, 9 max #x)
MinC(x: T.i4 * 2, 9 max #x)
MaxC(x: T.i4 * 2, 9 max #x)
MinMaxC(x: T.i4 * 2, 9 max #x)

// Reduce empty to default.
Sum(null)
Sum([])
Sum(vs) // Not necessarily empty, so doesn't reduce.
Sum(null, 1)
Sum([], 1)
Sum(vs, 1) // Not necessarily empty, so doesn't reduce.

Sum(i8s->Take(0))
Sum(i8s->Take(0)->CastU2())
Sum(i8s->Take(0)->CastU8())
Sum(i8s->Take(0)->CastR8())
SumC(i8s->Take(0))
SumC(i8s->Take(0)->CastU2())
SumC(i8s->Take(0)->CastU8())
SumC(i8s->Take(0)->CastR8())

Sum(qi8s->Take(0))
Sum(qi8s->Take(0)->CastU2())
Sum(qi8s->Take(0)->CastU8())
Sum(qi8s->Take(0)->CastR8())
SumC(qi8s->Take(0))
SumC(qi8s->Take(0)->CastU2())
SumC(qi8s->Take(0)->CastU8())
SumC(qi8s->Take(0)->CastR8())

Mean(i8s->Take(0))
Mean(i8s->Take(0)->CastU2())
Mean(i8s->Take(0)->CastU8())
Mean(i8s->Take(0)->CastR8())
MeanC(i8s->Take(0))
MeanC(i8s->Take(0)->CastU2())
MeanC(i8s->Take(0)->CastU8())
MeanC(i8s->Take(0)->CastR8())

Min(i8s->Take(0))
Min(i8s->Take(0)->CastU2())
Min(i8s->Take(0)->CastU8())
Min(i8s->Take(0)->CastR8())
MinC(i8s->Take(0))
MinC(i8s->Take(0)->CastU2())
MinC(i8s->Take(0)->CastU8())
MinC(i8s->Take(0)->CastR8())

Max(i8s->Take(0))
Max(i8s->Take(0)->CastU2())
Max(i8s->Take(0)->CastU8())
Max(i8s->Take(0)->CastR8())
MaxC(i8s->Take(0))
MaxC(i8s->Take(0)->CastU2())
MaxC(i8s->Take(0)->CastU8())
MaxC(i8s->Take(0)->CastR8())

MinMax(i8s->Take(0))
MinMax(i8s->Take(0)->CastU2())
MinMax(i8s->Take(0)->CastU8())
MinMax(i8s->Take(0)->CastR8())
MinMaxC(i8s->Take(0))
MinMaxC(i8s->Take(0)->CastU2())
MinMaxC(i8s->Take(0)->CastU8())
MinMaxC(i8s->Take(0)->CastR8())

Sum(i8s->Take(0), it * it)
Sum(i8s->Take(0), it->CastU2())
Sum(i8s->Take(0), it->CastU8())
Sum(i8s->Take(0), it->CastR8())
SumC(i8s->Take(0), it * it)
SumC(i8s->Take(0), it->CastU2())
SumC(i8s->Take(0), it->CastU8())
SumC(i8s->Take(0), it->CastR8())

Sum(i8s->Take(0), Opt(it * it))
Sum(i8s->Take(0), Opt(it->CastU2()))
Sum(i8s->Take(0), Opt(it->CastU8()))
Sum(i8s->Take(0), Opt(it->CastR8()))
SumC(i8s->Take(0), Opt(it * it))
SumC(i8s->Take(0), Opt(it->CastU2()))
SumC(i8s->Take(0), Opt(it->CastU8()))
SumC(i8s->Take(0), Opt(it->CastR8()))

Mean(i8s->Take(0), it * it)
Mean(i8s->Take(0), it->CastU2())
Mean(i8s->Take(0), it->CastU8())
Mean(i8s->Take(0), it->CastR8())
MeanC(i8s->Take(0), it * it)
MeanC(i8s->Take(0), it->CastU2())
MeanC(i8s->Take(0), it->CastU8())
MeanC(i8s->Take(0), it->CastR8())

Min(i8s->Take(0), it * it)
Min(i8s->Take(0), it->CastU2())
Min(i8s->Take(0), it->CastU8())
Min(i8s->Take(0), it->CastR8())
MinC(i8s->Take(0), it * it)
MinC(i8s->Take(0), it->CastU2())
MinC(i8s->Take(0), it->CastU8())
MinC(i8s->Take(0), it->CastR8())

Max(i8s->Take(0), it * it)
Max(i8s->Take(0), it->CastU2())
Max(i8s->Take(0), it->CastU8())
Max(i8s->Take(0), it->CastR8())
MaxC(i8s->Take(0), it * it)
MaxC(i8s->Take(0), it->CastU2())
MaxC(i8s->Take(0), it->CastU8())
MaxC(i8s->Take(0), it->CastR8())

MinMax(i8s->Take(0), it * it)
MinMax(i8s->Take(0), it->CastU2())
MinMax(i8s->Take(0), it->CastU8())
MinMax(i8s->Take(0), it->CastR8())
MinMaxC(i8s->Take(0), it * it)
MinMaxC(i8s->Take(0), it->CastU2())
MinMaxC(i8s->Take(0), it->CastU8())
MinMaxC(i8s->Take(0), it->CastR8())

// Errors.

Sum(T, s)
Sum(T.s)
Sum(T)
Sum(R)
Sum(R.A)
Sum(T, R, n * A)

:: { A:i4*, B:i4*, C:i4*, D:i4*, E:i4* }

// These convert to ForEach composed with Sum.
Sum(a:A, b:B, c:C, d:D, e:E, a*b*c*d*e)
SumBig(a:A, b:B, c:C, d:D, e:E, a*b*c*d*e)

// These cannot convert due to the directive.
Sum(ForEach(a:A, [if] a > 1, it + 1))
Sum(ForEach(a:A, [while] a > 1, it + 1))
Sum(ForEachIf(a:A, a > 1, it + 1))
Sum(ForEachWhile(a:A, a > 1, it + 1))
