blob: 8a2ba86955995fae75925e0b5012172afb06a466 [file] [log] [blame]
// Copyright (c) 2023, 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.
import "package:expect/expect.dart";
/// Regression test for the issue discovered by
/// https://github.com/dart-lang/sdk/issues/52243.
///
/// In DDC the types [num], [int], [double], [String], and [bool] used in bounds
/// caused an "optimization" in type tests that was incorrect when passing a
/// subtype as the type argument.
bool isWithNumBound<T extends num>(x) => x is T;
T asWithNumBound<T extends num>(x) => x as T;
bool isWithNullableNumBound<T extends num?>(x) => x is T;
T asWithNullableNumBound<T extends num?>(x) => x as T;
bool isWithIntBound<T extends int>(x) => x is T;
T asWithIntBound<T extends int>(x) => x as T;
bool isWithNullableIntBound<T extends int?>(x) => x is T;
T asWithNullableIntBound<T extends int?>(x) => x as T;
bool isWithDoubleBound<T extends double>(x) => x is T;
T asWithDoubleBound<T extends double>(x) => x as T;
bool isWithNullableDoubleBound<T extends double?>(x) => x is T;
T asWithNullableDoubleBound<T extends double?>(x) => x as T;
bool isWithStringBound<T extends String>(x) => x is T;
T asWithStringBound<T extends String>(x) => x as T;
bool isWithNullableStringBound<T extends String?>(x) => x is T;
T asWithNullableStringBound<T extends String?>(x) => x as T;
bool isWithBoolBound<T extends bool>(x) => x is T;
T asWithBoolBound<T extends bool>(x) => x as T;
bool isWithNullableBoolBound<T extends bool?>(x) => x is T;
T asWithNullableBoolBound<T extends bool?>(x) => x as T;
expectTypeErrorWhenSoundOrValue<T>(T Function(T) computation, T value) {
hasSoundNullSafety
? Expect.throws<TypeError>(() => computation(value))
: Expect.equals(value, computation(value));
}
main() {
// NOTE: JavaScript platforms can't determine that 1 is not a double so any
// test combination that would exercise that pattern are excluded here.
Expect.isTrue(isWithNumBound<num>(1));
Expect.isTrue(isWithNumBound<int>(1));
Expect.isFalse(isWithNumBound<Never>(1));
Expect.isTrue(isWithNumBound<num>(1.2));
Expect.isFalse(isWithNumBound<int>(1.2));
Expect.isTrue(isWithNumBound<double>(1.2));
Expect.isFalse(isWithNumBound<Never>(1.2));
Expect.equals(1, asWithNumBound<num>(1));
Expect.equals(1, asWithNumBound<int>(1));
Expect.throws<TypeError>(() => asWithNumBound<Never>(1));
Expect.equals(1.2, asWithNumBound<num>(1.2));
Expect.throws<TypeError>(() => asWithNumBound<int>(1.2));
Expect.equals(1.2, asWithNumBound<double>(1.2));
Expect.throws<TypeError>(() => asWithNumBound<Never>(1.2));
Expect.isTrue(isWithNullableNumBound<num>(1));
Expect.isTrue(isWithNullableNumBound<int>(1));
Expect.isFalse(isWithNullableNumBound<Never>(1));
Expect.isTrue(isWithNullableNumBound<num?>(1));
Expect.isTrue(isWithNullableNumBound<int?>(1));
Expect.isFalse(isWithNullableNumBound<Null>(1));
Expect.isTrue(isWithNullableNumBound<num>(1.2));
Expect.isFalse(isWithNullableNumBound<int>(1.2));
Expect.isTrue(isWithNullableNumBound<double>(1.2));
Expect.isFalse(isWithNullableNumBound<Never>(1.2));
Expect.isTrue(isWithNullableNumBound<num?>(1.2));
Expect.isFalse(isWithNullableNumBound<int?>(1.2));
Expect.isTrue(isWithNullableNumBound<double?>(1.2));
Expect.isFalse(isWithNullableNumBound<Null>(1.2));
Expect.isFalse(isWithNullableNumBound<num>(null));
Expect.isFalse(isWithNullableNumBound<int>(null));
Expect.isFalse(isWithNullableNumBound<double>(null));
Expect.isFalse(isWithNullableNumBound<Never>(null));
Expect.isTrue(isWithNullableNumBound<num?>(null));
Expect.isTrue(isWithNullableNumBound<int?>(null));
Expect.isTrue(isWithNullableNumBound<double?>(null));
Expect.isTrue(isWithNullableNumBound<Null>(null));
Expect.equals(1, asWithNullableNumBound<num>(1));
Expect.equals(1, asWithNullableNumBound<int>(1));
Expect.throws<TypeError>(() => asWithNullableNumBound<Never>(1));
Expect.equals(1, asWithNullableNumBound<num?>(1));
Expect.equals(1, asWithNullableNumBound<int?>(1));
Expect.throws<TypeError>(() => asWithNullableNumBound<Null>(1));
Expect.equals(1.2, asWithNullableNumBound<num>(1.2));
Expect.throws<TypeError>(() => asWithNullableNumBound<int>(1.2));
Expect.equals(1.2, asWithNullableNumBound<double>(1.2));
Expect.throws<TypeError>(() => asWithNullableNumBound<Never>(1.2));
Expect.equals(1.2, asWithNullableNumBound<num?>(1.2));
Expect.throws<TypeError>(() => asWithNullableNumBound<int?>(1.2));
Expect.equals(1.2, asWithNullableNumBound<double?>(1.2));
Expect.throws<TypeError>(() => asWithNullableNumBound<Null>(1.2));
expectTypeErrorWhenSoundOrValue(asWithNullableNumBound<num>, null);
expectTypeErrorWhenSoundOrValue(asWithNullableNumBound<int>, null);
expectTypeErrorWhenSoundOrValue(asWithNullableNumBound<double>, null);
expectTypeErrorWhenSoundOrValue(asWithNullableNumBound<Never>, null);
Expect.equals(null, asWithNullableNumBound<num?>(null));
Expect.equals(null, asWithNullableNumBound<int?>(null));
Expect.equals(null, asWithNullableNumBound<double?>(null));
Expect.equals(null, asWithNullableNumBound<Null>(null));
Expect.isTrue(isWithIntBound<int>(1));
Expect.isFalse(isWithIntBound<Never>(1));
Expect.isFalse(isWithIntBound<int>(1.2));
Expect.isFalse(isWithIntBound<Never>(1.2));
Expect.equals(1, asWithIntBound<int>(1));
Expect.throws<TypeError>(() => asWithIntBound<Never>(1));
Expect.throws<TypeError>(() => asWithIntBound<int>(1.2));
Expect.throws<TypeError>(() => asWithIntBound<Never>(1.2));
Expect.isTrue(isWithNullableIntBound<int>(1));
Expect.isFalse(isWithNullableIntBound<Never>(1));
Expect.isTrue(isWithNullableIntBound<int?>(1));
Expect.isFalse(isWithNullableIntBound<Null>(1));
Expect.isFalse(isWithNullableIntBound<int>(1.2));
Expect.isFalse(isWithNullableIntBound<Never>(1.2));
Expect.isFalse(isWithNullableIntBound<int?>(1.2));
Expect.isFalse(isWithNullableIntBound<Null>(1.2));
Expect.isFalse(isWithNullableIntBound<int>(null));
Expect.isFalse(isWithNullableIntBound<Never>(null));
Expect.isTrue(isWithNullableIntBound<int?>(null));
Expect.isTrue(isWithNullableIntBound<Null>(null));
Expect.equals(1, asWithNullableIntBound<int>(1));
Expect.throws<TypeError>(() => asWithNullableIntBound<Never>(1));
Expect.equals(1, asWithNullableIntBound<int?>(1));
Expect.throws<TypeError>(() => asWithNullableIntBound<Null>(1));
Expect.throws<TypeError>(() => asWithNullableIntBound<int>(1.2));
Expect.throws<TypeError>(() => asWithNullableIntBound<Never>(1.2));
Expect.throws<TypeError>(() => asWithNullableIntBound<int?>(1.2));
Expect.throws<TypeError>(() => asWithNullableIntBound<Null>(1.2));
expectTypeErrorWhenSoundOrValue(asWithNullableIntBound<int>, null);
expectTypeErrorWhenSoundOrValue(asWithNullableIntBound<Never>, null);
Expect.equals(null, asWithNullableIntBound<int?>(null));
Expect.equals(null, asWithNullableIntBound<Null>(null));
Expect.isFalse(isWithDoubleBound<Never>(1));
Expect.isTrue(isWithDoubleBound<double>(1.2));
Expect.isFalse(isWithDoubleBound<Never>(1.2));
Expect.throws<TypeError>(() => asWithDoubleBound<Never>(1));
Expect.equals(1.2, asWithDoubleBound<double>(1.2));
Expect.throws<TypeError>(() => asWithDoubleBound<Never>(1.2));
Expect.isFalse(isWithNullableDoubleBound<Never>(1));
Expect.isFalse(isWithNullableDoubleBound<Null>(1));
Expect.isTrue(isWithNullableDoubleBound<double>(1.2));
Expect.isFalse(isWithNullableDoubleBound<Never>(1.2));
Expect.isTrue(isWithNullableDoubleBound<double?>(1.2));
Expect.isFalse(isWithNullableDoubleBound<Null>(1.2));
Expect.isFalse(isWithNullableDoubleBound<double>(null));
Expect.isFalse(isWithNullableDoubleBound<Never>(null));
Expect.isTrue(isWithNullableDoubleBound<double?>(null));
Expect.isTrue(isWithNullableDoubleBound<Null>(null));
Expect.throws<TypeError>(() => asWithNullableDoubleBound<Never>(1));
Expect.throws<TypeError>(() => asWithNullableDoubleBound<Null>(1));
Expect.equals(1.2, asWithNullableDoubleBound<double>(1.2));
Expect.throws<TypeError>(() => asWithNullableDoubleBound<Never>(1.2));
Expect.equals(1.2, asWithNullableDoubleBound<double?>(1.2));
Expect.throws<TypeError>(() => asWithNullableDoubleBound<Null>(1.2));
expectTypeErrorWhenSoundOrValue(asWithNullableDoubleBound<double>, null);
expectTypeErrorWhenSoundOrValue(asWithNullableDoubleBound<Never>, null);
Expect.equals(null, asWithNullableDoubleBound<double?>(null));
Expect.equals(null, asWithNullableDoubleBound<Null>(null));
Expect.isTrue(isWithStringBound<String>('hello'));
Expect.isFalse(isWithStringBound<Never>('hello'));
Expect.equals('hello', asWithStringBound<String>('hello'));
Expect.throws<TypeError>(() => asWithStringBound<Never>('hello'));
Expect.isTrue(isWithNullableStringBound<String>('hello'));
Expect.isFalse(isWithNullableStringBound<Never>('hello'));
Expect.isTrue(isWithNullableStringBound<String?>('hello'));
Expect.isFalse(isWithNullableStringBound<Null>('hello'));
Expect.isFalse(isWithNullableStringBound<String>(null));
Expect.isFalse(isWithNullableStringBound<Never>(null));
Expect.isTrue(isWithNullableStringBound<String?>(null));
Expect.isTrue(isWithNullableStringBound<Null>(null));
Expect.equals('hello', asWithNullableStringBound<String>('hello'));
Expect.throws<TypeError>(() => asWithNullableStringBound<Never>('hello'));
Expect.equals('hello', asWithNullableStringBound<String?>('hello'));
Expect.throws<TypeError>(() => asWithNullableStringBound<Null>('hello'));
expectTypeErrorWhenSoundOrValue(asWithNullableStringBound<String>, null);
expectTypeErrorWhenSoundOrValue(asWithNullableStringBound<Never>, null);
Expect.equals(null, asWithNullableStringBound<String?>(null));
Expect.equals(null, asWithNullableStringBound<Null>(null));
Expect.isTrue(isWithBoolBound<bool>(true));
Expect.isFalse(isWithBoolBound<Never>(true));
Expect.equals(true, asWithBoolBound<bool>(true));
Expect.throws<TypeError>(() => asWithBoolBound<Never>(true));
Expect.isTrue(isWithNullableBoolBound<bool>(true));
Expect.isFalse(isWithNullableBoolBound<Never>(true));
Expect.isTrue(isWithNullableBoolBound<bool?>(true));
Expect.isFalse(isWithNullableBoolBound<Null>(true));
Expect.isFalse(isWithNullableBoolBound<bool>(null));
Expect.isFalse(isWithNullableBoolBound<Never>(null));
Expect.isTrue(isWithNullableBoolBound<bool?>(null));
Expect.isTrue(isWithNullableBoolBound<Null>(null));
Expect.equals(true, asWithNullableBoolBound<bool>(true));
Expect.throws<TypeError>(() => asWithNullableBoolBound<Never>(true));
Expect.equals(true, asWithNullableBoolBound<bool?>(true));
Expect.throws<TypeError>(() => asWithNullableBoolBound<Null>(true));
expectTypeErrorWhenSoundOrValue(asWithNullableBoolBound<bool>, null);
expectTypeErrorWhenSoundOrValue(asWithNullableBoolBound<Never>, null);
Expect.equals(null, asWithNullableBoolBound<bool?>(null));
Expect.equals(null, asWithNullableBoolBound<Null>(null));
}