7134a451f3
A lot of files in this one, but nothing interesting in any of the tests. Change-Id: I69c705bfd2c2b2f9711b393e4ac78c357336e1a7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/407660 Commit-Queue: Lasse Nielsen <lrn@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Auto-Submit: Bob Nystrom <rnystrom@google.com>
240 lines
6.4 KiB
Dart
240 lines
6.4 KiB
Dart
// Copyright (c) 2024, 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.
|
|
|
|
// Tests the functionality proposed in
|
|
// https://github.com/dart-lang/language/issues/1618#issuecomment-1507241494,
|
|
// using switch expressions.
|
|
|
|
import 'package:expect/static_type_helper.dart';
|
|
|
|
/// Ensures a context type of `Iterable<T>` for the operand, or `Iterable<_>` if
|
|
/// no type argument is supplied.
|
|
Object? contextIterable<T>(Iterable<T> x) => x;
|
|
|
|
class A {}
|
|
|
|
class B1<T> implements A {}
|
|
|
|
class B2<T> implements A {}
|
|
|
|
class C1<T> implements B1<T>, B2<T> {}
|
|
|
|
class C2<T> implements B1<T>, B2<T> {}
|
|
|
|
/// Ensures a context type of `B1<T>` for the operand, or `B1<_>` if no type
|
|
/// argument is supplied.
|
|
Object? contextB1<T>(B1<T> x) => x;
|
|
|
|
test(int i) {
|
|
// The static type of a switch expression `e` of the form `switch (e0) { p1 =>
|
|
// e1, p2 => e2, ... pn => en }` with context type K is computed as follows:
|
|
//
|
|
// - The scrutinee (`e0`) is first analyzed with context type `_`.
|
|
// - If the switch expression has no cases, its static type is `Never`.
|
|
// - Otherwise, for each case `pi => ei`, let Ti be the type of `ei` inferred
|
|
// with context type K.
|
|
{
|
|
// Check the context type of each `ei`:
|
|
// - Where the context is established using a function call argument.
|
|
context<String>(switch (i) {
|
|
0 => (contextType('')..expectStaticType<Exactly<String>>()),
|
|
1 => (contextType('')..expectStaticType<Exactly<String>>()),
|
|
_ => (contextType('')..expectStaticType<Exactly<String>>()),
|
|
});
|
|
|
|
// - Where the context is established using local variable promotion.
|
|
Object? o;
|
|
o = '' as Object?;
|
|
if (o is String) {
|
|
o = switch (i) {
|
|
0 => (contextType('')..expectStaticType<Exactly<String>>()),
|
|
1 => (contextType('')..expectStaticType<Exactly<String>>()),
|
|
_ => (contextType('')..expectStaticType<Exactly<String>>()),
|
|
};
|
|
}
|
|
}
|
|
|
|
// - Let T be the least upper bound of the static types of all the case
|
|
// expressions.
|
|
// - Let S be the greatest closure of K.
|
|
// - If T <: S, then the type of `e` is T.
|
|
{
|
|
// This example has:
|
|
// - K = Object
|
|
// - T1 = int
|
|
// - T2 = double
|
|
// Which implies:
|
|
// - T = num
|
|
// - S = Object
|
|
// We have:
|
|
// - T <: S
|
|
// Therefore the type of `e` is T = num.
|
|
var d = 2.0;
|
|
context<Object>(
|
|
(switch (i) {
|
|
0 => i,
|
|
_ => d,
|
|
})..expectStaticType<Exactly<num>>(),
|
|
);
|
|
|
|
// This example has:
|
|
// - K = Iterable<_>
|
|
// - T1 = Iterable<int>
|
|
// - T2 = Iterable<double>
|
|
// Which implies:
|
|
// - T = Iterable<num>
|
|
// - S = Iterable<Object?>
|
|
// We have:
|
|
// - T <: S
|
|
// Therefore the type of `e` is T = Iterable<num>.
|
|
var iterableInt = <int>[] as Iterable<int>;
|
|
var iterableDouble = <double>[] as Iterable<double>;
|
|
contextIterable(
|
|
(switch (i) {
|
|
0 => iterableInt,
|
|
_ => iterableDouble,
|
|
})..expectStaticType<Exactly<Iterable<num>>>(),
|
|
);
|
|
}
|
|
|
|
// - Otherwise, if Ti <: S for all i, then the type of `e` is S.
|
|
{
|
|
// This example has:
|
|
// - K = B1<_>
|
|
// - T1 = C1<int>
|
|
// - T2 = C2<double>
|
|
// Which implies:
|
|
// - T = A
|
|
// - S = B1<Object?>
|
|
// We have:
|
|
// - T <!: S
|
|
// - T1 <: S
|
|
// - T2 <: S
|
|
// Therefore the type of `e` is S = B1<Object?>.
|
|
var c1Int = C1<int>();
|
|
var c2Double = C2<double>();
|
|
contextB1(
|
|
(switch (i) {
|
|
0 => c1Int,
|
|
_ => c2Double,
|
|
})..expectStaticType<Exactly<B1<Object?>>>(),
|
|
);
|
|
|
|
// This example has:
|
|
// - K = B1<Object>
|
|
// - T1 = C1<int>
|
|
// - T2 = C2<double>
|
|
// Which implies:
|
|
// - T = A
|
|
// - S = B1<Object>
|
|
// We have:
|
|
// - T <!: S
|
|
// - T1 <: S
|
|
// - T2 <: S
|
|
// Therefore the type of `e` is S = B1<Object>.
|
|
contextB1<Object>(
|
|
(switch (i) {
|
|
0 => c1Int,
|
|
_ => c2Double,
|
|
})..expectStaticType<Exactly<B1<Object>>>(),
|
|
);
|
|
|
|
// This example has:
|
|
// - K = Iterable<num>
|
|
// - T1 = Iterable<int>
|
|
// - T2 = List<num>
|
|
// Which implies:
|
|
// - T = Object
|
|
// - S = Iterable<num>
|
|
// We have:
|
|
// - T <!: S
|
|
// - T1 <: S
|
|
// - T2 <: S
|
|
// Therefore the type of `e` is S = Iterable<num>.
|
|
var iterableInt = <int>[] as Iterable<int>;
|
|
var listNum = <num>[];
|
|
context<Iterable<num>>(
|
|
(switch (i) {
|
|
0 => iterableInt,
|
|
_ => listNum,
|
|
})..expectStaticType<Exactly<Iterable<num>>>(),
|
|
);
|
|
}
|
|
|
|
// - Otherwise, the type of `e` is T.
|
|
{
|
|
Object? o;
|
|
var d = 2.0;
|
|
o = '' as Object?;
|
|
if (o is String?) {
|
|
// This example has:
|
|
// - K = String?
|
|
// - T1 = Null
|
|
// - T2 = int
|
|
// Which implies:
|
|
// - T = int?
|
|
// - S = String?
|
|
// We have:
|
|
// - T <!: S
|
|
// - T1 <: S
|
|
// - T2 <!: S
|
|
// The fact that T2 <!: S precludes using S as static type.
|
|
// Therefore the type of `e` is T = int?.
|
|
// We avoid having a compile-time error because `o` can be demoted.
|
|
o = (switch (i) {
|
|
0 => null,
|
|
_ => i,
|
|
})..expectStaticType<Exactly<int?>>();
|
|
}
|
|
o = '' as Object?;
|
|
if (o is String?) {
|
|
// This example has:
|
|
// - K = String?
|
|
// - T1 = int
|
|
// - T2 = Null
|
|
// Which implies:
|
|
// - T = int?
|
|
// - S = String?
|
|
// We have:
|
|
// - T <!: S
|
|
// - T1 <!: S
|
|
// - T2 <: S
|
|
// The fact that T1 <!: S precludes using S as static type.
|
|
// Therefore the type of `e` is T = int?.
|
|
// We avoid having a compile-time error because `o` can be demoted.
|
|
o = (switch (i) {
|
|
0 => i,
|
|
_ => null,
|
|
})..expectStaticType<Exactly<int?>>();
|
|
}
|
|
o = '' as Object?;
|
|
if (o is String?) {
|
|
// This example has:
|
|
// - K = String?
|
|
// - T1 = int
|
|
// - T2 = double
|
|
// Which implies:
|
|
// - T = num
|
|
// - S = String?
|
|
// We have:
|
|
// - T <!: S
|
|
// - T1 <!: S
|
|
// - T2 <!: S
|
|
// The fact that T1 <!: S and T2 <!: S precludes using S as static type.
|
|
// Therefore the type of `e` is T = num.
|
|
// We avoid having a compile-time error because `o` can be demoted.
|
|
o = (switch (i) {
|
|
0 => i,
|
|
_ => d,
|
|
})..expectStaticType<Exactly<num>>();
|
|
}
|
|
}
|
|
}
|
|
|
|
main() {
|
|
test(0);
|
|
test(1);
|
|
test(2);
|
|
}
|