blob: a6fcd7dbc220755836f4f6c9c4cd2a8198eab621 [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` and *S* is assignable to `num`.
//
// * If *T* <: `double` then the static type of `e` is `double`.
// * Otherwise, if *S* <: `double` and not *S* <: `Never`,
// then the static type of `e` is `double`.
// * Otherwise, if *T* <: `int`, *S* <: `int` and not *S* <: `Never`,
// then the static type of `e` is `int`.
// * Otherwise the static type of *e* is `num`.
//
// For `e1.clamp(e2, e3)` where
// *T1* is the static type of `e1`, *T1* a non-`Never` subtype of `num`,
// *T2* is the static type of `e2`, and
// *T3* is the static type of `e3`:
//
// * If all of *T1*, *T2* and *T3* are non-`Never` subtypes of `int`,
// then the static type of `e` is `int`.
// * If all of *T1*, *T2* and *T3* are non-`Never` subtypes of `double`,
// then the static type of `e` is `double`.
// * Otherwise the static type of `e` is 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);
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>>();
(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>>();
(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>>();
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 + 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>>();
(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>>();
if (false) {
(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 + 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>>();
(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) {
(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>>();
}
var dyn1a = dyn1 + d;
if (false) {
// Check that the static type of [dyn1a] is dynamic:
Never n = dyn1a;
dyn1a = 0;
dyn1a = false;
}
var dyn1b = dyn1 - d;
if (false) {
// Check that the static type of [dyn1b] is dynamic:
Never n = dyn1b;
dyn1b = 0;
dyn1b = false;
}
var dyn1c = dyn1 * d;
if (false) {
// Check that the static type of [dyn1c] is dynamic:
Never n = dyn1c;
dyn1c = 0;
dyn1c = false;
}
var dyn1d = dyn1 % d;
if (false) {
// Check that the static type of [dyn1d] is dynamic:
Never n = dyn1d;
dyn1d = 0;
dyn1d = false;
}
var dyn1e = dyn1.remainder(d);
if (false) {
// Check that the static type of [dyn1e] is dynamic:
Never n = dyn1a;
dyn1a = 0;
dyn1a = false;
}
if (false) {
(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<num>>();
d.clamp(d, never).expectStaticType<Exactly<num>>();
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>>();
(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>>();
(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>>();
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 + 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>>();
(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>>();
if (false) {
(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 + 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>>();
(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) {
(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>>();
}
var dyn1a = dyn1 + d;
if (false) {
// Check that the static type of [dyn1a] is dynamic:
Never n = dyn1a;
dyn1a = 0;
dyn1a = false;
}
var dyn1b = dyn1 - d;
if (false) {
// Check that the static type of [dyn1b] is dynamic:
Never n = dyn1b;
dyn1b = 0;
dyn1b = false;
}
var dyn1c = dyn1 * d;
if (false) {
// Check that the static type of [dyn1c] is dynamic:
Never n = dyn1c;
dyn1c = 0;
dyn1c = false;
}
var dyn1d = dyn1 % d;
if (false) {
// Check that the static type of [dyn1d] is dynamic:
Never n = dyn1d;
dyn1d = 0;
dyn1d = false;
}
var dyn1e = dyn1.remainder(d);
if (false) {
// Check that the static type of [dyn1e] is dynamic:
Never n = dyn1a;
dyn1a = 0;
dyn1a = false;
}
if (false) {
(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<num>>();
d.clamp(d, never).expectStaticType<Exactly<num>>();
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<int>>();
(i - ii).expectStaticType<Exactly<int>>();
(i * ii).expectStaticType<Exactly<int>>();
(i % ii).expectStaticType<Exactly<int>>();
i.remainder(ii).expectStaticType<Exactly<int>>();
(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>>();
(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>>();
(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>>();
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 + 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>>();
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<double>>();
(d - dd).expectStaticType<Exactly<double>>();
(d * dd).expectStaticType<Exactly<double>>();
(d % dd).expectStaticType<Exactly<double>>();
d.remainder(dd).expectStaticType<Exactly<double>>();
(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>>();
if (false) {
(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 + 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>>();
(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<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) {
(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>>();
}
var dyn1a = dyn1 + d;
if (false) {
// Check that the static type of [dyn1a] is dynamic:
Never n = dyn1a;
dyn1a = 0;
dyn1a = false;
}
var dyn1b = dyn1 - d;
if (false) {
// Check that the static type of [dyn1b] is dynamic:
Never n = dyn1b;
dyn1b = 0;
dyn1b = false;
}
var dyn1c = dyn1 * d;
if (false) {
// Check that the static type of [dyn1c] is dynamic:
Never n = dyn1c;
dyn1c = 0;
dyn1c = false;
}
var dyn1d = dyn1 % d;
if (false) {
// Check that the static type of [dyn1d] is dynamic:
Never n = dyn1d;
dyn1d = 0;
dyn1d = false;
}
var dyn1e = dyn1.remainder(d);
if (false) {
// Check that the static type of [dyn1e] is dynamic:
Never n = dyn1a;
dyn1a = 0;
dyn1a = false;
}
if (false) {
(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>>();
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<double>>();
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<num>>();
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<num>>();
d.clamp(d, never).expectStaticType<Exactly<num>>();
n.clamp(n, never).expectStaticType<Exactly<num>>();
never.clamp(i, i).expectStaticType<Exactly<Never>>();
}
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 num.
n.clamp(on, onn).expectStaticType<Exactly<num>>();
on.clamp(n, onn).expectStaticType<Exactly<num>>();
onn.clamp(on, n).expectStaticType<Exactly<num>>();
}
// 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>>();
(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>>();
(i + ii).expectStaticType<Exactly<int>>();
(i - ii).expectStaticType<Exactly<int>>();
(i * ii).expectStaticType<Exactly<int>>();
(i % ii).expectStaticType<Exactly<int>>();
i.remainder(ii).expectStaticType<Exactly<int>>();
(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>>();
(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>>();
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 + 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>>();
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;
(d + dd).expectStaticType<Exactly<double>>();
(d - dd).expectStaticType<Exactly<double>>();
(d * dd).expectStaticType<Exactly<double>>();
(d % dd).expectStaticType<Exactly<double>>();
d.remainder(dd).expectStaticType<Exactly<double>>();
(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>>();
if (false) {
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 + 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>>();
(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<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<num>>();
(n - n).expectStaticType<Exactly<num>>();
(n * n).expectStaticType<Exactly<num>>();
(n % n).expectStaticType<Exactly<num>>();
n.remainder(n).expectStaticType<Exactly<num>>();
if (false) {
(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>>();
}
var dyn1a = dyn1 + d;
if (false) {
// Check that the static type of [dyn1a] is dynamic:
Never n = dyn1a;
dyn1a = 0;
dyn1a = false;
}
var dyn1b = dyn1 - d;
if (false) {
// Check that the static type of [dyn1b] is dynamic:
Never n = dyn1b;
dyn1b = 0;
dyn1b = false;
}
var dyn1c = dyn1 * d;
if (false) {
// Check that the static type of [dyn1c] is dynamic:
Never n = dyn1c;
dyn1c = 0;
dyn1c = false;
}
var dyn1d = dyn1 % d;
if (false) {
// Check that the static type of [dyn1d] is dynamic:
Never n = dyn1d;
dyn1d = 0;
dyn1d = false;
}
var dyn1e = dyn1.remainder(d);
if (false) {
// Check that the static type of [dyn1e] is dynamic:
Never n = dyn1a;
dyn1a = 0;
dyn1a = false;
}
if (false) {
(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>>();
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<double>>();
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<num>>();
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.
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(d, n).expectStaticType<Exactly<num>>();
d.clamp(i, n).expectStaticType<Exactly<num>>();
n.clamp(i, d).expectStaticType<Exactly<num>>();
if (false) {
i.clamp(i, never).expectStaticType<Exactly<num>>();
d.clamp(d, never).expectStaticType<Exactly<num>>();
n.clamp(n, never).expectStaticType<Exactly<num>>();
never.clamp(i, i).expectStaticType<Exactly<Never>>();
}
}
/// 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 int int3;
final int int4;
final double dbl1;
final double dbl2;
final double dbl3;
final double dbl4;
final double dbl5;
final double dbl6;
final double dbl7;
final double dbl8;
final double dbl9;
final double dbl10;
final num num1;
final num num2;
final num num3;
final num num4;
final num num5;
const TestConst(I i, D d, N n)
: int1 = 1 + i,
int2 = i + 1,
int3 = i + 1,
int4 = 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 + _".
dbl7 = d + i,
dbl8 = d + d,
dbl9 = d + n,
dbl10 = d + dyn,
num1 = i + n,
num2 = n + d,
num3 = n + n,
num4 = n + i,
num5 = n + dyn;
}