blob: 29154cea80d3b446010207562208e04e13e91817 [file] [log] [blame]
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Test the rules for static types of number operators,
// as modified by Null Safety
import "static_type_helper.dart";
// ignore_for_file: receiver_of_type_never
// The typing rules for `e` of the form:
// * `e1 op e2` (op in `+`, `-`, `*` or `%`), or
// * `e1.remainder(e2)`,
//
// where *T* is the static type of `e1`, *S* is the static type of `e2`
// and *T* is a non-`Never` subtype of `num`.
//
// * If *T* <: `double`, then the static type of `e` is *T*.
// * Otherwise, if *S* is a non-`Never` subtype of `double`
// then the static type of `e` is `double`.
// * Otherwise, if *S* is a non-`Never` subtype of `int`
// then the static type of `e` is *T*.
// * Otherwise, if *S* is a non-`Never` subtype of *T*,
// then the static type of `e` is *T*.
// * Otherwise the static type of *e* is `num`.
//
// For `e1.clamp(e2, e3)` where
// * *T1* is the static type of `e1`,
// * *T2* is the static type of `e2`,
// * *T3* is the static type of `e3`,
//
// and T1 is a non-`Never` subtype of `num`, the static type is:
// min(num, LUB(T1, T2, T3))
// (That is, the LUB if it's a subtype of `num`, otherwise `num`.)
main() {
testPlainVariables(1, 1.0, 1);
testPromotedVariables(1, 1.0, 1);
testTypeVariables<int, double, int>(1, 1.0, 1);
testPromotedTypeVariables<Object>(1, 1.0, 1);
testComplex<int, double, num, Object, num>(1, 1.0, 1, 1, 1);
const TestConst<int, double, num>(1, 1.0, 1);
}
final num n1 = 1;
final num n2 = 2;
final int i1 = 1;
final int i2 = 2;
final dynamic dyn1 = 1;
final dynamic dyn2 = 2;
late final Never never = throw "unreachable"; // Only used for static tests.
// Check the static type of operations on plain variables.
void testPlainVariables(int i, double d, num n) {
(i + i).expectStaticType<Exactly<int>>();
(i - i).expectStaticType<Exactly<int>>();
(i * i).expectStaticType<Exactly<int>>();
(i % i).expectStaticType<Exactly<int>>();
i.remainder(i).expectStaticType<Exactly<int>>();
(d + i).expectStaticType<Exactly<double>>();
(d - i).expectStaticType<Exactly<double>>();
(d * i).expectStaticType<Exactly<double>>();
(d % i).expectStaticType<Exactly<double>>();
d.remainder(i).expectStaticType<Exactly<double>>();
(i + d).expectStaticType<Exactly<double>>();
(i - d).expectStaticType<Exactly<double>>();
(i * d).expectStaticType<Exactly<double>>();
(i % d).expectStaticType<Exactly<double>>();
i.remainder(d).expectStaticType<Exactly<double>>();
(n + i).expectStaticType<Exactly<num>>();
(n - i).expectStaticType<Exactly<num>>();
(n * i).expectStaticType<Exactly<num>>();
(n % i).expectStaticType<Exactly<num>>();
n.remainder(i).expectStaticType<Exactly<num>>();
(i + n).expectStaticType<Exactly<num>>();
(i - n).expectStaticType<Exactly<num>>();
(i * n).expectStaticType<Exactly<num>>();
(i % n).expectStaticType<Exactly<num>>();
i.remainder(n).expectStaticType<Exactly<num>>();
(i + dyn1).expectStaticType<Exactly<num>>();
(i - dyn1).expectStaticType<Exactly<num>>();
(i * dyn1).expectStaticType<Exactly<num>>();
(i % dyn1).expectStaticType<Exactly<num>>();
i.remainder(dyn1).expectStaticType<Exactly<num>>();
(d + d).expectStaticType<Exactly<double>>();
(d - d).expectStaticType<Exactly<double>>();
(d * d).expectStaticType<Exactly<double>>();
(d % d).expectStaticType<Exactly<double>>();
d.remainder(d).expectStaticType<Exactly<double>>();
(d + n).expectStaticType<Exactly<double>>();
(d - n).expectStaticType<Exactly<double>>();
(d * n).expectStaticType<Exactly<double>>();
(d % n).expectStaticType<Exactly<double>>();
d.remainder(n).expectStaticType<Exactly<double>>();
(d + dyn1).expectStaticType<Exactly<double>>();
(d - dyn1).expectStaticType<Exactly<double>>();
(d * dyn1).expectStaticType<Exactly<double>>();
(d % dyn1).expectStaticType<Exactly<double>>();
d.remainder(dyn1).expectStaticType<Exactly<double>>();
(n + d).expectStaticType<Exactly<double>>();
(n - d).expectStaticType<Exactly<double>>();
(n * d).expectStaticType<Exactly<double>>();
(n % d).expectStaticType<Exactly<double>>();
n.remainder(d).expectStaticType<Exactly<double>>();
(n + n).expectStaticType<Exactly<num>>();
(n - n).expectStaticType<Exactly<num>>();
(n * n).expectStaticType<Exactly<num>>();
(n % n).expectStaticType<Exactly<num>>();
n.remainder(n).expectStaticType<Exactly<num>>();
(n + dyn1).expectStaticType<Exactly<num>>();
(n - dyn1).expectStaticType<Exactly<num>>();
(n * dyn1).expectStaticType<Exactly<num>>();
(n % dyn1).expectStaticType<Exactly<num>>();
n.remainder(dyn1).expectStaticType<Exactly<num>>();
if (false) {
// Only for the static checks
// since we have sub-expressions of type Never.
(i + never).expectStaticType<Exactly<num>>();
(i - never).expectStaticType<Exactly<num>>();
(i * never).expectStaticType<Exactly<num>>();
(i % never).expectStaticType<Exactly<num>>();
i.remainder(never).expectStaticType<Exactly<num>>();
(d + never).expectStaticType<Exactly<double>>();
(d - never).expectStaticType<Exactly<double>>();
(d * never).expectStaticType<Exactly<double>>();
(d % never).expectStaticType<Exactly<double>>();
d.remainder(never).expectStaticType<Exactly<double>>();
(n + never).expectStaticType<Exactly<num>>();
(n - never).expectStaticType<Exactly<num>>();
(n * never).expectStaticType<Exactly<num>>();
(n % never).expectStaticType<Exactly<num>>();
n.remainder(never).expectStaticType<Exactly<num>>();
(never + d).expectStaticType<Exactly<Never>>();
(never - d).expectStaticType<Exactly<Never>>();
(never * d).expectStaticType<Exactly<Never>>();
(never % d).expectStaticType<Exactly<Never>>();
never.remainder(d).expectStaticType<Exactly<Never>>();
}
i.clamp(i, i).expectStaticType<Exactly<int>>();
d.clamp(d, d).expectStaticType<Exactly<double>>();
i.clamp(i, d).expectStaticType<Exactly<num>>();
i.clamp(d, i).expectStaticType<Exactly<num>>();
d.clamp(i, i).expectStaticType<Exactly<num>>();
i.clamp(d, d).expectStaticType<Exactly<num>>();
d.clamp(i, d).expectStaticType<Exactly<num>>();
d.clamp(d, i).expectStaticType<Exactly<num>>();
i.clamp(i, n).expectStaticType<Exactly<num>>();
i.clamp(n, i).expectStaticType<Exactly<num>>();
n.clamp(i, i).expectStaticType<Exactly<num>>();
d.clamp(d, n).expectStaticType<Exactly<num>>();
d.clamp(n, d).expectStaticType<Exactly<num>>();
n.clamp(d, d).expectStaticType<Exactly<num>>();
i.clamp(i, dyn1).expectStaticType<Exactly<num>>();
i.clamp(dyn1, i).expectStaticType<Exactly<num>>();
d.clamp(d, dyn1).expectStaticType<Exactly<num>>();
d.clamp(dyn1, d).expectStaticType<Exactly<num>>();
n.clamp(n, dyn1).expectStaticType<Exactly<num>>();
n.clamp(dyn1, n).expectStaticType<Exactly<num>>();
if (false) {
i.clamp(i, never).expectStaticType<Exactly<int>>();
d.clamp(d, never).expectStaticType<Exactly<double>>();
n.clamp(n, never).expectStaticType<Exactly<num>>();
never.clamp(i, i).expectStaticType<Exactly<Never>>();
}
;
(i += i1).expectStaticType<Exactly<int>>();
(i -= i1).expectStaticType<Exactly<int>>();
(i *= i1).expectStaticType<Exactly<int>>();
(i %= i2).expectStaticType<Exactly<int>>();
(i++).expectStaticType<Exactly<int>>();
(i--).expectStaticType<Exactly<int>>();
(++i).expectStaticType<Exactly<int>>();
(--i).expectStaticType<Exactly<int>>();
(d += i1).expectStaticType<Exactly<double>>();
(d -= i1).expectStaticType<Exactly<double>>();
(d *= i1).expectStaticType<Exactly<double>>();
(d %= i2).expectStaticType<Exactly<double>>();
(d += 1.0).expectStaticType<Exactly<double>>();
(d -= 1.0).expectStaticType<Exactly<double>>();
(d *= 1.0).expectStaticType<Exactly<double>>();
(d %= 1.0).expectStaticType<Exactly<double>>();
(d += n1).expectStaticType<Exactly<double>>();
(d -= n1).expectStaticType<Exactly<double>>();
(d *= n1).expectStaticType<Exactly<double>>();
(d %= n2).expectStaticType<Exactly<double>>();
(d += dyn1).expectStaticType<Exactly<double>>();
(d -= dyn1).expectStaticType<Exactly<double>>();
(d *= dyn1).expectStaticType<Exactly<double>>();
(d %= dyn2).expectStaticType<Exactly<double>>();
(d++).expectStaticType<Exactly<double>>();
(d--).expectStaticType<Exactly<double>>();
(++d).expectStaticType<Exactly<double>>();
(--d).expectStaticType<Exactly<double>>();
(n += i1).expectStaticType<Exactly<num>>();
(n -= i1).expectStaticType<Exactly<num>>();
(n *= i1).expectStaticType<Exactly<num>>();
(n %= i2).expectStaticType<Exactly<num>>();
(n += 1.0).expectStaticType<Exactly<double>>();
(n -= 1.0).expectStaticType<Exactly<double>>();
(n *= 1.0).expectStaticType<Exactly<double>>();
(n %= 1.0).expectStaticType<Exactly<double>>();
(n += n1).expectStaticType<Exactly<num>>();
(n -= n1).expectStaticType<Exactly<num>>();
(n *= n1).expectStaticType<Exactly<num>>();
(n %= n2).expectStaticType<Exactly<num>>();
(n += dyn1).expectStaticType<Exactly<num>>();
(n -= dyn1).expectStaticType<Exactly<num>>();
(n *= dyn1).expectStaticType<Exactly<num>>();
(n %= dyn2).expectStaticType<Exactly<num>>();
(n++).expectStaticType<Exactly<num>>();
(n--).expectStaticType<Exactly<num>>();
(++n).expectStaticType<Exactly<num>>();
(--n).expectStaticType<Exactly<num>>();
if (false) {
(d += never).expectStaticType<Exactly<double>>();
(n += never).expectStaticType<Exactly<num>>();
}
}
// Check the static type of operations on promoted variables.
void testPromotedVariables(Object i, Object d, Object n) {
if (i is! int) throw "promote i to int";
if (d is! double) throw "promote d to double";
if (n is! num) throw "promote n to num";
i.expectStaticType<Exactly<int>>();
d.expectStaticType<Exactly<double>>();
n.expectStaticType<Exactly<num>>();
(i + i).expectStaticType<Exactly<int>>();
(i - i).expectStaticType<Exactly<int>>();
(i * i).expectStaticType<Exactly<int>>();
(i % i).expectStaticType<Exactly<int>>();
i.remainder(i).expectStaticType<Exactly<int>>();
(d + i).expectStaticType<Exactly<double>>();
(d - i).expectStaticType<Exactly<double>>();
(d * i).expectStaticType<Exactly<double>>();
(d % i).expectStaticType<Exactly<double>>();
d.remainder(i).expectStaticType<Exactly<double>>();
(i + d).expectStaticType<Exactly<double>>();
(i - d).expectStaticType<Exactly<double>>();
(i * d).expectStaticType<Exactly<double>>();
(i % d).expectStaticType<Exactly<double>>();
i.remainder(d).expectStaticType<Exactly<double>>();
(n + i).expectStaticType<Exactly<num>>();
(n - i).expectStaticType<Exactly<num>>();
(n * i).expectStaticType<Exactly<num>>();
(n % i).expectStaticType<Exactly<num>>();
n.remainder(i).expectStaticType<Exactly<num>>();
(i + n).expectStaticType<Exactly<num>>();
(i - n).expectStaticType<Exactly<num>>();
(i * n).expectStaticType<Exactly<num>>();
(i % n).expectStaticType<Exactly<num>>();
i.remainder(n).expectStaticType<Exactly<num>>();
(i + dyn1).expectStaticType<Exactly<num>>();
(i - dyn1).expectStaticType<Exactly<num>>();
(i * dyn1).expectStaticType<Exactly<num>>();
(i % dyn1).expectStaticType<Exactly<num>>();
i.remainder(dyn1).expectStaticType<Exactly<num>>();
(d + d).expectStaticType<Exactly<double>>();
(d - d).expectStaticType<Exactly<double>>();
(d * d).expectStaticType<Exactly<double>>();
(d % d).expectStaticType<Exactly<double>>();
d.remainder(d).expectStaticType<Exactly<double>>();
(d + n).expectStaticType<Exactly<double>>();
(d - n).expectStaticType<Exactly<double>>();
(d * n).expectStaticType<Exactly<double>>();
(d % n).expectStaticType<Exactly<double>>();
d.remainder(n).expectStaticType<Exactly<double>>();
(d + dyn1).expectStaticType<Exactly<double>>();
(d - dyn1).expectStaticType<Exactly<double>>();
(d * dyn1).expectStaticType<Exactly<double>>();
(d % dyn1).expectStaticType<Exactly<double>>();
d.remainder(dyn1).expectStaticType<Exactly<double>>();
(n + d).expectStaticType<Exactly<double>>();
(n - d).expectStaticType<Exactly<double>>();
(n * d).expectStaticType<Exactly<double>>();
(n % d).expectStaticType<Exactly<double>>();
n.remainder(d).expectStaticType<Exactly<double>>();
(n + n).expectStaticType<Exactly<num>>();
(n - n).expectStaticType<Exactly<num>>();
(n * n).expectStaticType<Exactly<num>>();
(n % n).expectStaticType<Exactly<num>>();
n.remainder(n).expectStaticType<Exactly<num>>();
(n + dyn1).expectStaticType<Exactly<num>>();
(n - dyn1).expectStaticType<Exactly<num>>();
(n * dyn1).expectStaticType<Exactly<num>>();
(n % dyn1).expectStaticType<Exactly<num>>();
n.remainder(dyn1).expectStaticType<Exactly<num>>();
if (false) {
(i + never).expectStaticType<Exactly<num>>();
(i - never).expectStaticType<Exactly<num>>();
(i * never).expectStaticType<Exactly<num>>();
(i % never).expectStaticType<Exactly<num>>();
i.remainder(never).expectStaticType<Exactly<num>>();
(d + never).expectStaticType<Exactly<double>>();
(d - never).expectStaticType<Exactly<double>>();
(d * never).expectStaticType<Exactly<double>>();
(d % never).expectStaticType<Exactly<double>>();
d.remainder(never).expectStaticType<Exactly<double>>();
(n + never).expectStaticType<Exactly<num>>();
(n - never).expectStaticType<Exactly<num>>();
(n * never).expectStaticType<Exactly<num>>();
(n % never).expectStaticType<Exactly<num>>();
n.remainder(never).expectStaticType<Exactly<num>>();
(never + d).expectStaticType<Exactly<Never>>();
(never - d).expectStaticType<Exactly<Never>>();
(never * d).expectStaticType<Exactly<Never>>();
(never % d).expectStaticType<Exactly<Never>>();
never.remainder(double).expectStaticType<Exactly<Never>>();
}
i.clamp(i, i).expectStaticType<Exactly<int>>();
d.clamp(d, d).expectStaticType<Exactly<double>>();
i.clamp(i, d).expectStaticType<Exactly<num>>();
i.clamp(d, i).expectStaticType<Exactly<num>>();
d.clamp(i, i).expectStaticType<Exactly<num>>();
i.clamp(d, d).expectStaticType<Exactly<num>>();
d.clamp(i, d).expectStaticType<Exactly<num>>();
d.clamp(d, i).expectStaticType<Exactly<num>>();
i.clamp(i, n).expectStaticType<Exactly<num>>();
i.clamp(n, i).expectStaticType<Exactly<num>>();
n.clamp(i, i).expectStaticType<Exactly<num>>();
d.clamp(d, n).expectStaticType<Exactly<num>>();
d.clamp(n, d).expectStaticType<Exactly<num>>();
n.clamp(d, d).expectStaticType<Exactly<num>>();
i.clamp(i, dyn1).expectStaticType<Exactly<num>>();
i.clamp(dyn1, i).expectStaticType<Exactly<num>>();
d.clamp(d, dyn1).expectStaticType<Exactly<num>>();
d.clamp(dyn1, d).expectStaticType<Exactly<num>>();
n.clamp(n, dyn1).expectStaticType<Exactly<num>>();
n.clamp(dyn1, n).expectStaticType<Exactly<num>>();
if (false) {
i.clamp(i, never).expectStaticType<Exactly<int>>();
d.clamp(d, never).expectStaticType<Exactly<double>>();
n.clamp(n, never).expectStaticType<Exactly<num>>();
never.clamp(i, i).expectStaticType<Exactly<Never>>();
}
;
(i += i1).expectStaticType<Exactly<int>>();
(i -= i1).expectStaticType<Exactly<int>>();
(i *= i1).expectStaticType<Exactly<int>>();
(i %= i2).expectStaticType<Exactly<int>>();
(i++).expectStaticType<Exactly<int>>();
(i--).expectStaticType<Exactly<int>>();
(++i).expectStaticType<Exactly<int>>();
(--i).expectStaticType<Exactly<int>>();
(d += i1).expectStaticType<Exactly<double>>();
(d -= i1).expectStaticType<Exactly<double>>();
(d *= i1).expectStaticType<Exactly<double>>();
(d %= i2).expectStaticType<Exactly<double>>();
(d += 1.0).expectStaticType<Exactly<double>>();
(d -= 1.0).expectStaticType<Exactly<double>>();
(d *= 1.0).expectStaticType<Exactly<double>>();
(d %= 1.0).expectStaticType<Exactly<double>>();
(d += n1).expectStaticType<Exactly<double>>();
(d -= n1).expectStaticType<Exactly<double>>();
(d *= n1).expectStaticType<Exactly<double>>();
(d %= n2).expectStaticType<Exactly<double>>();
(d += dyn1).expectStaticType<Exactly<double>>();
(d -= dyn1).expectStaticType<Exactly<double>>();
(d *= dyn1).expectStaticType<Exactly<double>>();
(d %= dyn2).expectStaticType<Exactly<double>>();
(d++).expectStaticType<Exactly<double>>();
(d--).expectStaticType<Exactly<double>>();
(++d).expectStaticType<Exactly<double>>();
(--d).expectStaticType<Exactly<double>>();
(n += i1).expectStaticType<Exactly<num>>();
(n -= i1).expectStaticType<Exactly<num>>();
(n *= i1).expectStaticType<Exactly<num>>();
(n %= i2).expectStaticType<Exactly<num>>();
(n += 1.0).expectStaticType<Exactly<double>>();
(n -= 1.0).expectStaticType<Exactly<double>>();
(n *= 1.0).expectStaticType<Exactly<double>>();
(n %= 1.0).expectStaticType<Exactly<double>>();
(n += n1).expectStaticType<Exactly<num>>();
(n -= n1).expectStaticType<Exactly<num>>();
(n *= n1).expectStaticType<Exactly<num>>();
(n %= n2).expectStaticType<Exactly<num>>();
(n += dyn1).expectStaticType<Exactly<num>>();
(n -= dyn1).expectStaticType<Exactly<num>>();
(n *= dyn1).expectStaticType<Exactly<num>>();
(n %= dyn2).expectStaticType<Exactly<num>>();
(n++).expectStaticType<Exactly<num>>();
(n--).expectStaticType<Exactly<num>>();
(++n).expectStaticType<Exactly<num>>();
(--n).expectStaticType<Exactly<num>>();
if (false) {
(d += never).expectStaticType<Exactly<double>>();
(n += never).expectStaticType<Exactly<num>>();
}
}
// Check the static type of operations on promoted variables.
void testTypeVariables<I extends int, D extends double, N extends num>(
I i, D d, N n) {
int ii = i; // Actual int type.
(ii + i).expectStaticType<Exactly<int>>();
(ii - i).expectStaticType<Exactly<int>>();
(ii * i).expectStaticType<Exactly<int>>();
(ii % i).expectStaticType<Exactly<int>>();
ii.remainder(i).expectStaticType<Exactly<int>>();
(i + ii).expectStaticType<Exactly<I>>();
(i - ii).expectStaticType<Exactly<I>>();
(i * ii).expectStaticType<Exactly<I>>();
(i % ii).expectStaticType<Exactly<I>>();
i.remainder(ii).expectStaticType<Exactly<I>>();
(i + i).expectStaticType<Exactly<I>>();
(i - i).expectStaticType<Exactly<I>>();
(i * i).expectStaticType<Exactly<I>>();
(i % i).expectStaticType<Exactly<I>>();
i.remainder(i).expectStaticType<Exactly<I>>();
(d + i).expectStaticType<Exactly<D>>();
(d - i).expectStaticType<Exactly<D>>();
(d * i).expectStaticType<Exactly<D>>();
(d % i).expectStaticType<Exactly<D>>();
d.remainder(i).expectStaticType<Exactly<D>>();
(i + d).expectStaticType<Exactly<double>>();
(i - d).expectStaticType<Exactly<double>>();
(i * d).expectStaticType<Exactly<double>>();
(i % d).expectStaticType<Exactly<double>>();
i.remainder(d).expectStaticType<Exactly<double>>();
(n + i).expectStaticType<Exactly<N>>();
(n - i).expectStaticType<Exactly<N>>();
(n * i).expectStaticType<Exactly<N>>();
(n % i).expectStaticType<Exactly<N>>();
n.remainder(i).expectStaticType<Exactly<N>>();
(i + n).expectStaticType<Exactly<num>>();
(i - n).expectStaticType<Exactly<num>>();
(i * n).expectStaticType<Exactly<num>>();
(i % n).expectStaticType<Exactly<num>>();
i.remainder(n).expectStaticType<Exactly<num>>();
(i + dyn1).expectStaticType<Exactly<num>>();
(i - dyn1).expectStaticType<Exactly<num>>();
(i * dyn1).expectStaticType<Exactly<num>>();
(i % dyn1).expectStaticType<Exactly<num>>();
i.remainder(dyn1).expectStaticType<Exactly<num>>();
double dd = d; // Actual double type.
(dd + d).expectStaticType<Exactly<double>>();
(dd - d).expectStaticType<Exactly<double>>();
(dd * d).expectStaticType<Exactly<double>>();
(dd % d).expectStaticType<Exactly<double>>();
dd.remainder(d).expectStaticType<Exactly<double>>();
(d + dd).expectStaticType<Exactly<D>>();
(d - dd).expectStaticType<Exactly<D>>();
(d * dd).expectStaticType<Exactly<D>>();
(d % dd).expectStaticType<Exactly<D>>();
d.remainder(dd).expectStaticType<Exactly<D>>();
(d + d).expectStaticType<Exactly<D>>();
(d - d).expectStaticType<Exactly<D>>();
(d * d).expectStaticType<Exactly<D>>();
(d % d).expectStaticType<Exactly<D>>();
d.remainder(d).expectStaticType<Exactly<D>>();
(d + n).expectStaticType<Exactly<D>>();
(d - n).expectStaticType<Exactly<D>>();
(d * n).expectStaticType<Exactly<D>>();
(d % n).expectStaticType<Exactly<D>>();
d.remainder(n).expectStaticType<Exactly<D>>();
(d + dyn1).expectStaticType<Exactly<D>>();
(d - dyn1).expectStaticType<Exactly<D>>();
(d * dyn1).expectStaticType<Exactly<D>>();
(d % dyn1).expectStaticType<Exactly<D>>();
d.remainder(dyn1).expectStaticType<Exactly<D>>();
(n + d).expectStaticType<Exactly<double>>();
(n - d).expectStaticType<Exactly<double>>();
(n * d).expectStaticType<Exactly<double>>();
(n % d).expectStaticType<Exactly<double>>();
n.remainder(d).expectStaticType<Exactly<double>>();
num nn = n; // Actual num type.
(nn + n).expectStaticType<Exactly<num>>();
(nn - n).expectStaticType<Exactly<num>>();
(nn * n).expectStaticType<Exactly<num>>();
(nn % n).expectStaticType<Exactly<num>>();
nn.remainder(n).expectStaticType<Exactly<num>>();
(n + nn).expectStaticType<Exactly<num>>();
(n - nn).expectStaticType<Exactly<num>>();
(n * nn).expectStaticType<Exactly<num>>();
(n % nn).expectStaticType<Exactly<num>>();
n.remainder(nn).expectStaticType<Exactly<num>>();
(n + n).expectStaticType<Exactly<N>>();
(n - n).expectStaticType<Exactly<N>>();
(n * n).expectStaticType<Exactly<N>>();
(n % n).expectStaticType<Exactly<N>>();
n.remainder(n).expectStaticType<Exactly<N>>();
(n + dyn1).expectStaticType<Exactly<num>>();
(n - dyn1).expectStaticType<Exactly<num>>();
(n * dyn1).expectStaticType<Exactly<num>>();
(n % dyn1).expectStaticType<Exactly<num>>();
n.remainder(dyn1).expectStaticType<Exactly<num>>();
if (false) {
(i + never).expectStaticType<Exactly<num>>();
(i - never).expectStaticType<Exactly<num>>();
(i * never).expectStaticType<Exactly<num>>();
(i % never).expectStaticType<Exactly<num>>();
i.remainder(never).expectStaticType<Exactly<num>>();
(d + never).expectStaticType<Exactly<D>>();
(d - never).expectStaticType<Exactly<D>>();
(d * never).expectStaticType<Exactly<D>>();
(d % never).expectStaticType<Exactly<D>>();
d.remainder(never).expectStaticType<Exactly<D>>();
(n + never).expectStaticType<Exactly<num>>();
(n - never).expectStaticType<Exactly<num>>();
(n * never).expectStaticType<Exactly<num>>();
(n % never).expectStaticType<Exactly<num>>();
n.remainder(never).expectStaticType<Exactly<num>>();
(never + d).expectStaticType<Exactly<Never>>();
(never - d).expectStaticType<Exactly<Never>>();
(never * d).expectStaticType<Exactly<Never>>();
(never % d).expectStaticType<Exactly<Never>>();
never.remainder(d).expectStaticType<Exactly<Never>>();
}
i.clamp(i, i).expectStaticType<Exactly<I>>();
i.clamp(i, ii).expectStaticType<Exactly<int>>();
i.clamp(ii, i).expectStaticType<Exactly<int>>();
ii.clamp(i, i).expectStaticType<Exactly<int>>();
d.clamp(d, d).expectStaticType<Exactly<D>>();
d.clamp(d, dd).expectStaticType<Exactly<double>>();
d.clamp(dd, d).expectStaticType<Exactly<double>>();
dd.clamp(d, d).expectStaticType<Exactly<double>>();
n.clamp(n, n).expectStaticType<Exactly<N>>();
n.clamp(n, nn).expectStaticType<Exactly<num>>();
n.clamp(nn, n).expectStaticType<Exactly<num>>();
nn.clamp(n, n).expectStaticType<Exactly<num>>();
i.clamp(i, d).expectStaticType<Exactly<num>>();
i.clamp(d, i).expectStaticType<Exactly<num>>();
d.clamp(i, i).expectStaticType<Exactly<num>>();
i.clamp(d, d).expectStaticType<Exactly<num>>();
d.clamp(i, d).expectStaticType<Exactly<num>>();
d.clamp(d, i).expectStaticType<Exactly<num>>();
i.clamp(i, n).expectStaticType<Exactly<num>>();
i.clamp(n, i).expectStaticType<Exactly<num>>();
n.clamp(i, i).expectStaticType<Exactly<num>>();
d.clamp(d, n).expectStaticType<Exactly<num>>();
d.clamp(n, d).expectStaticType<Exactly<num>>();
n.clamp(d, d).expectStaticType<Exactly<num>>();
i.clamp(i, dyn1).expectStaticType<Exactly<num>>();
i.clamp(dyn1, i).expectStaticType<Exactly<num>>();
d.clamp(d, dyn1).expectStaticType<Exactly<num>>();
d.clamp(dyn1, d).expectStaticType<Exactly<num>>();
n.clamp(i, dyn1).expectStaticType<Exactly<num>>();
n.clamp(dyn1, d).expectStaticType<Exactly<num>>();
if (false) {
i.clamp(i, never).expectStaticType<Exactly<I>>();
d.clamp(d, never).expectStaticType<Exactly<D>>();
n.clamp(n, never).expectStaticType<Exactly<N>>();
never.clamp(i, i).expectStaticType<Exactly<Never>>();
}
;
(i += i1).expectStaticType<Exactly<I>>();
(i -= i1).expectStaticType<Exactly<I>>();
(i *= i1).expectStaticType<Exactly<I>>();
(i %= i2).expectStaticType<Exactly<I>>();
(i++).expectStaticType<Exactly<I>>();
(i--).expectStaticType<Exactly<I>>();
(++i).expectStaticType<Exactly<I>>();
(--i).expectStaticType<Exactly<I>>();
(d += i1).expectStaticType<Exactly<D>>();
(d -= i1).expectStaticType<Exactly<D>>();
(d *= i1).expectStaticType<Exactly<D>>();
(d %= i2).expectStaticType<Exactly<D>>();
(d += 1.0).expectStaticType<Exactly<D>>();
(d -= 1.0).expectStaticType<Exactly<D>>();
(d *= 1.0).expectStaticType<Exactly<D>>();
(d %= 1.0).expectStaticType<Exactly<D>>();
(d += n1).expectStaticType<Exactly<D>>();
(d -= n1).expectStaticType<Exactly<D>>();
(d *= n1).expectStaticType<Exactly<D>>();
(d %= n2).expectStaticType<Exactly<D>>();
(d += dyn1).expectStaticType<Exactly<D>>();
(d -= dyn1).expectStaticType<Exactly<D>>();
(d *= dyn1).expectStaticType<Exactly<D>>();
(d %= dyn2).expectStaticType<Exactly<D>>();
(d++).expectStaticType<Exactly<D>>();
(d--).expectStaticType<Exactly<D>>();
(++d).expectStaticType<Exactly<D>>();
(--d).expectStaticType<Exactly<D>>();
(n += i1).expectStaticType<Exactly<N>>();
(n -= i1).expectStaticType<Exactly<N>>();
(n *= i1).expectStaticType<Exactly<N>>();
(n %= i2).expectStaticType<Exactly<N>>();
(n += 1.0).expectStaticType<Exactly<double>>();
(n -= 1.0).expectStaticType<Exactly<double>>();
(n *= 1.0).expectStaticType<Exactly<double>>();
(n %= 1.0).expectStaticType<Exactly<double>>();
(n += n1).expectStaticType<Exactly<num>>();
(n -= n1).expectStaticType<Exactly<num>>();
(n *= n1).expectStaticType<Exactly<num>>();
(n %= n2).expectStaticType<Exactly<num>>();
(n += dyn1).expectStaticType<Exactly<num>>();
(n -= dyn1).expectStaticType<Exactly<num>>();
(n *= dyn1).expectStaticType<Exactly<num>>();
(n %= dyn2).expectStaticType<Exactly<num>>();
(n++).expectStaticType<Exactly<N>>();
(n--).expectStaticType<Exactly<N>>();
(++n).expectStaticType<Exactly<N>>();
(--n).expectStaticType<Exactly<N>>();
if (false) {
(d += never).expectStaticType<Exactly<D>>();
}
Object on = 1;
if (on is! N) throw "promote on to O&N";
var onn = on;
if (onn is! num) throw "promote onn O&N&num";
// With three different type variable types,
// still pick the LUB.
n.clamp(on, onn).expectStaticType<Exactly<N>>();
on.clamp(n, onn).expectStaticType<Exactly<N>>();
onn.clamp(on, n).expectStaticType<Exactly<N>>();
/// If the second operand of a binary oprator is a subtype of the first,
/// the type is that of the first, even if both are subtypes of `num`.
///
/// If one or more of the operands of `clamp` is a
/// supertype of the others, the LUB is undefined.
<X extends num, Y extends X, Z extends Y>(X x, Y y, Z z) {
X n = x;
(n += y).expectStaticType<Exactly<X>>();
(n -= y).expectStaticType<Exactly<X>>();
(n *= y).expectStaticType<Exactly<X>>();
(n %= y).expectStaticType<Exactly<X>>();
x.clamp(y, z).expectStaticType<Exactly<X>>();
y.clamp(x, z).expectStaticType<Exactly<X>>();
z.clamp(x, y).expectStaticType<Exactly<X>>();
if (x is! Y) throw "promote x to X&Y";
y.clamp(x, z).expectStaticType<Exactly<Y>>();
if (x is! Z) throw "promote x to X&Y&Z";
if (y is! Z) throw "promote x to Y&Z";
y.clamp(x, z).expectStaticType<Exactly<Y>>();
z.clamp(x, y).expectStaticType<Exactly<Z>>();
}<num, num, num>(1, 1, 1);
}
// Check the static type of operations on promoted type variables.
void testPromotedTypeVariables<T>(T i, T d, T n) {
if (i is! int) throw "promote i to T & int";
if (d is! double) throw "promote d to T & double";
if (n is! num) throw "promote n to T & num";
// We cannot pass intersection types to type parameters,
// so we need to check them in-place.
// We check that the value is assignable to both types,
// and are not dynamic (assignable to `Object`).
checkIntersectionType<int, T>(i, i, i);
checkIntersectionType<double, T>(d, d, d);
checkIntersectionType<num, T>(n, n, n);
int ii = i; // Actual integer type.
(ii + i).expectStaticType<Exactly<int>>();
(ii - i).expectStaticType<Exactly<int>>();
(ii * i).expectStaticType<Exactly<int>>();
(ii % i).expectStaticType<Exactly<int>>();
ii.remainder(i).expectStaticType<Exactly<int>>();
// Result type T&int
var result11 = i + i;
checkIntersectionType<int, T>(result11, result11, result11);
var result12 = i - i;
checkIntersectionType<int, T>(result12, result12, result12);
var result13 = i * i;
checkIntersectionType<int, T>(result13, result13, result13);
var result14 = i % i;
checkIntersectionType<int, T>(result14, result14, result14);
var result15 = i.remainder(i);
checkIntersectionType<int, T>(result15, result15, result15);
// Result type T&int
var result16 = i + ii;
checkIntersectionType<int, T>(result16, result16, result16);
var result17 = i - ii;
checkIntersectionType<int, T>(result17, result17, result17);
var result18 = i * ii;
checkIntersectionType<int, T>(result18, result18, result18);
var result19 = i % ii;
checkIntersectionType<int, T>(result19, result19, result19);
var result20 = i.remainder(ii);
checkIntersectionType<int, T>(result20, result20, result20);
// Result type T&double
var result21 = (d + i);
checkIntersectionType<double, T>(result21, result21, result21);
var result22 = (d - i);
checkIntersectionType<double, T>(result22, result22, result22);
var result23 = (d * i);
checkIntersectionType<double, T>(result23, result23, result23);
var result24 = (d % i);
checkIntersectionType<double, T>(result24, result24, result24);
var result25 = d.remainder(i);
checkIntersectionType<double, T>(result25, result25, result25);
(i + d).expectStaticType<Exactly<double>>();
(i - d).expectStaticType<Exactly<double>>();
(i * d).expectStaticType<Exactly<double>>();
(i % d).expectStaticType<Exactly<double>>();
i.remainder(d).expectStaticType<Exactly<double>>();
// Result type T&num
var result26 = (n + i);
checkIntersectionType<num, T>(result26, result26, result26);
var result27 = (n - i);
checkIntersectionType<num, T>(result27, result27, result27);
var result28 = (n * i);
checkIntersectionType<num, T>(result28, result28, result28);
var result29 = (n % i);
checkIntersectionType<num, T>(result29, result29, result29);
var result30 = n.remainder(i);
checkIntersectionType<num, T>(result30, result30, result30);
(i + n).expectStaticType<Exactly<num>>();
(i - n).expectStaticType<Exactly<num>>();
(i * n).expectStaticType<Exactly<num>>();
(i % n).expectStaticType<Exactly<num>>();
i.remainder(n).expectStaticType<Exactly<num>>();
(i + dyn1).expectStaticType<Exactly<num>>();
(i - dyn1).expectStaticType<Exactly<num>>();
(i * dyn1).expectStaticType<Exactly<num>>();
(i % dyn1).expectStaticType<Exactly<num>>();
i.remainder(dyn1).expectStaticType<Exactly<num>>();
double dd = d; // Actual double type.
(dd + d).expectStaticType<Exactly<double>>();
(dd - d).expectStaticType<Exactly<double>>();
(dd * d).expectStaticType<Exactly<double>>();
(dd % d).expectStaticType<Exactly<double>>();
dd.remainder(d).expectStaticType<Exactly<double>>();
// Result type T&double;
var result41 = d + dd;
checkIntersectionType<double, T>(result41, result41, result41);
var result42 = d - dd;
checkIntersectionType<double, T>(result42, result42, result42);
var result43 = d * dd;
checkIntersectionType<double, T>(result43, result43, result43);
var result44 = d % dd;
checkIntersectionType<double, T>(result44, result44, result44);
var result45 = d.remainder(dd);
checkIntersectionType<double, T>(result45, result45, result45);
var result46 = d + d;
checkIntersectionType<double, T>(result46, result46, result46);
var result47 = d - d;
checkIntersectionType<double, T>(result47, result47, result47);
var result48 = d * d;
checkIntersectionType<double, T>(result48, result48, result48);
var result49 = d % d;
checkIntersectionType<double, T>(result49, result49, result49);
var result50 = d.remainder(d);
checkIntersectionType<double, T>(result50, result50, result50);
var result51 = (d + n);
checkIntersectionType<double, T>(result51, result51, result51);
var result52 = (d - n);
checkIntersectionType<double, T>(result52, result52, result52);
var result53 = (d * n);
checkIntersectionType<double, T>(result53, result53, result53);
var result54 = (d % n);
checkIntersectionType<double, T>(result54, result54, result54);
var result55 = d.remainder(n);
checkIntersectionType<double, T>(result55, result55, result55);
var result56 = (d + dyn1);
checkIntersectionType<num, T>(result56, result56, result56);
var result57 = (d - dyn1);
checkIntersectionType<num, T>(result57, result57, result57);
var result58 = (d * dyn1);
checkIntersectionType<num, T>(result58, result58, result58);
var result59 = (d % dyn1);
checkIntersectionType<num, T>(result59, result59, result59);
var result60 = d.remainder(dyn1);
checkIntersectionType<num, T>(result60, result60, result60);
(n + d).expectStaticType<Exactly<double>>();
(n - d).expectStaticType<Exactly<double>>();
(n * d).expectStaticType<Exactly<double>>();
(n % d).expectStaticType<Exactly<double>>();
n.remainder(d).expectStaticType<Exactly<double>>();
num nn = n; // Actual num-typed value.
(nn + n).expectStaticType<Exactly<num>>();
(nn - n).expectStaticType<Exactly<num>>();
(nn * n).expectStaticType<Exactly<num>>();
(nn % n).expectStaticType<Exactly<num>>();
nn.remainder(n).expectStaticType<Exactly<num>>();
(nn + dyn1).expectStaticType<Exactly<num>>();
(nn - dyn1).expectStaticType<Exactly<num>>();
(nn * dyn1).expectStaticType<Exactly<num>>();
(nn % dyn1).expectStaticType<Exactly<num>>();
nn.remainder(dyn1).expectStaticType<Exactly<num>>();
(n + nn).expectStaticType<num>();
(n - nn).expectStaticType<num>();
(n * nn).expectStaticType<num>();
(n % nn).expectStaticType<num>();
n.remainder(nn).expectStaticType<num>();
var result71 = n + n;
checkIntersectionType<num, T>(result71, result71, result71);
var result72 = n - n;
checkIntersectionType<num, T>(result72, result72, result72);
var result73 = n * n;
checkIntersectionType<num, T>(result73, result73, result73);
var result74 = n % n;
checkIntersectionType<num, T>(result74, result74, result74);
var result75 = n.remainder(n);
checkIntersectionType<num, T>(result75, result75, result75);
if (false) {
(i + never).expectStaticType<Exactly<num>>();
(i - never).expectStaticType<Exactly<num>>();
(i * never).expectStaticType<Exactly<num>>();
(i % never).expectStaticType<Exactly<num>>();
i.remainder(never).expectStaticType<Exactly<num>>();
var result81 = d + never;
checkIntersectionType<double, T>(result81, result81, result81);
var result82 = d - never;
checkIntersectionType<double, T>(result82, result82, result82);
var result83 = d * never;
checkIntersectionType<double, T>(result83, result83, result83);
var result84 = d % never;
checkIntersectionType<double, T>(result84, result84, result84);
var result85 = d.remainder(never);
checkIntersectionType<double, T>(result85, result85, result85);
(n + never).expectStaticType<Exactly<num>>();
(n - never).expectStaticType<Exactly<num>>();
(n * never).expectStaticType<Exactly<num>>();
(n % never).expectStaticType<Exactly<num>>();
n.remainder(never).expectStaticType<Exactly<num>>();
(never + d).expectStaticType<Exactly<Never>>();
(never - d).expectStaticType<Exactly<Never>>();
(never * d).expectStaticType<Exactly<Never>>();
(never % d).expectStaticType<Exactly<Never>>();
never.remainder(d).expectStaticType<Exactly<Never>>();
}
var clamp01 = i.clamp(i, i);
checkIntersectionType<int, T>(clamp01, clamp01, clamp01);
i.clamp(i, ii).expectStaticType<Exactly<int>>();
i.clamp(ii, i).expectStaticType<Exactly<int>>();
ii.clamp(i, i).expectStaticType<Exactly<int>>();
var clamp05 = d.clamp(d, d);
checkIntersectionType<double, T>(clamp01, clamp01, clamp01);
d.clamp(d, dd).expectStaticType<Exactly<double>>();
d.clamp(dd, d).expectStaticType<Exactly<double>>();
dd.clamp(d, d).expectStaticType<Exactly<double>>();
var clamp09 = n.clamp(n, n);
checkIntersectionType<num, T>(clamp09, clamp09, clamp09);
n.clamp(n, nn).expectStaticType<Exactly<num>>();
n.clamp(nn, n).expectStaticType<Exactly<num>>();
nn.clamp(n, n).expectStaticType<Exactly<num>>();
i.clamp(i, d).expectStaticType<Exactly<num>>();
i.clamp(d, i).expectStaticType<Exactly<num>>();
d.clamp(i, i).expectStaticType<Exactly<num>>();
i.clamp(d, d).expectStaticType<Exactly<num>>();
d.clamp(i, d).expectStaticType<Exactly<num>>();
d.clamp(d, i).expectStaticType<Exactly<num>>();
i.clamp(i, dyn1).expectStaticType<Exactly<num>>();
i.clamp(dyn1, i).expectStaticType<Exactly<num>>();
d.clamp(d, dyn1).expectStaticType<Exactly<num>>();
d.clamp(dyn1, d).expectStaticType<Exactly<num>>();
n.clamp(n, dyn1).expectStaticType<Exactly<num>>();
n.clamp(dyn1, n).expectStaticType<Exactly<num>>();
// The type T&num is a supertype of T&int/T&double, so it is the result type.
var clamp19 = i.clamp(i, n);
checkIntersectionType<num, T>(clamp19, clamp19, clamp19);
var clamp20 = i.clamp(n, i);
checkIntersectionType<num, T>(clamp20, clamp20, clamp20);
var clamp26 = n.clamp(i, i);
checkIntersectionType<num, T>(clamp26, clamp26, clamp26);
var clamp27 = d.clamp(d, n);
checkIntersectionType<num, T>(clamp27, clamp27, clamp27);
var clamp28 = d.clamp(n, d);
checkIntersectionType<num, T>(clamp28, clamp28, clamp28);
var clamp29 = n.clamp(d, d);
checkIntersectionType<num, T>(clamp29, clamp29, clamp29);
var clamp30 = i.clamp(d, n);
checkIntersectionType<num, T>(clamp30, clamp30, clamp30);
var clamp31 = d.clamp(i, n);
checkIntersectionType<num, T>(clamp31, clamp31, clamp31);
var clamp32 = n.clamp(i, d);
checkIntersectionType<num, T>(clamp32, clamp32, clamp32);
if (false) {
var clamp33 = i.clamp(i, never);
checkIntersectionType<int, T>(clamp33, clamp33, clamp33);
var clamp34 = d.clamp(d, never);
checkIntersectionType<double, T>(clamp34, clamp34, clamp34);
var clamp35 = n.clamp(n, never);
checkIntersectionType<num, T>(clamp35, clamp35, clamp35);
never.clamp(i, i).expectStaticType<Exactly<Never>>();
}
;
i += 1;
checkIntersectionType<int, T>(i, i, i);
i += i;
checkIntersectionType<int, T>(i, i, i);
d += 1;
checkIntersectionType<double, T>(d, d, d);
d += 1.0;
checkIntersectionType<double, T>(d, d, d);
d += i;
checkIntersectionType<double, T>(d, d, d);
d += d;
checkIntersectionType<double, T>(d, d, d);
d += n;
checkIntersectionType<double, T>(d, d, d);
n += 1;
checkIntersectionType<num, T>(n, n, n);
n += i;
checkIntersectionType<num, T>(n, n, n);
}
/// Creative combinations of types.
void testComplex<I extends int, D extends double, N extends num,
O extends Object, NN extends N>(I i, D d, N n, O o, NN nn) {
O p = 1 as O;
if (p is! N) throw "promote to O&N";
if (p is! NN) throw "promote to O&N&NN";
checkIntersectionType<O, N>(p, p, p);
checkIntersectionType<N, NN>(p, p, p);
var result01 = p + p;
checkIntersectionType<O, N>(result01, result01, result01);
checkIntersectionType<N, NN>(result01, result01, result01);
var clamp01 = p.clamp(p, p);
checkIntersectionType<O, N>(clamp01, clamp01, clamp01);
checkIntersectionType<N, NN>(clamp01, clamp01, clamp01);
// Having different unrelated subtypes of int.
// Return the first operand's type.
N ni = n;
if (ni is! int) throw "promote ni to N&int";
(i + ni).expectStaticType<Exactly<I>>();
(i - ni).expectStaticType<Exactly<I>>();
(i * ni).expectStaticType<Exactly<I>>();
(i % ni).expectStaticType<Exactly<I>>();
i.remainder(ni).expectStaticType<Exactly<I>>();
// Use LUB for clamp.
i.clamp(ni, ni).expectStaticType<Exactly<int>>();
i.clamp(ni, i).expectStaticType<Exactly<int>>();
// Having different unrelated subtypes of double.
N nd = 1.0 as N;
if (nd is! double) throw "promote ni to N&double";
(d + nd).expectStaticType<Exactly<D>>();
(d - nd).expectStaticType<Exactly<D>>();
(d * nd).expectStaticType<Exactly<D>>();
(d % nd).expectStaticType<Exactly<D>>();
d.remainder(nd).expectStaticType<Exactly<D>>();
(d.clamp(nd, nd)).expectStaticType<Exactly<double>>();
(d.clamp(nd, d)).expectStaticType<Exactly<double>>();
(nd.clamp(d, d)).expectStaticType<Exactly<double>>();
}
/// Perform constant operations and check that they are still valid.
class TestConst<I extends int, D extends double, N extends num> {
static const dynamic dyn = 1;
final int int1;
final int int2;
final double dbl1;
final double dbl2;
final double dbl3;
final double dbl4;
final double dbl5;
final double dbl6;
final num num1;
final num num2;
final I i1;
final I i2;
final D d1;
final D d2;
final D d3;
final D d4;
final N n1;
final N n2;
const TestConst(I i, D d, N n)
: int1 = 1 + i,
int2 = i + 1,
i1 = i + 1,
i2 = i + i,
dbl1 = 1.0 + i,
dbl2 = 1.0 + d,
dbl3 = 1.0 + n,
dbl4 = 1.0 + dyn,
dbl5 = 1 + 1, // Checking context type of "double = int + _".
dbl6 = n + 1, // Checking context type of "double = num + _".
d1 = d + i,
d2 = d + d,
d3 = d + n,
d4 = d + dyn,
num1 = i + n,
num2 = n + d,
n1 = n + n,
n2 = n + i;
}