Skip to content

Commit

Permalink
dart-lang#2420. Add extension types exhaustiveness tests. Lists
Browse files Browse the repository at this point in the history
  • Loading branch information
sgrekhov committed Dec 12, 2023
1 parent 3734cda commit 03a2b9c
Show file tree
Hide file tree
Showing 11 changed files with 832 additions and 0 deletions.
84 changes: 84 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_list_A01_t01.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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.

/// @assertion Switch expression with a list as a matched type can be exhaustive
///
/// @description Check that it is no compile-time error if a matched type of a
/// switch expression is an extension type with a `List` as a representation
/// type and all cases are exhaustive. Test a rest element at the end of the
/// list pattern
/// @author sgrekhov22@gmail.com
// SharedOptions=--enable-experiment=inline-class

import "../../Utils/expect.dart";

extension type ET1<T>(List<T> _) {}
extension type ET2<T>(List<T> _) implements List<T> {}

String test1_1(ET1<int> l) =>
switch (l) {
<int?>[] => "0",
[_] => "1",
[_, _] => "2",
[_, _, ...] => "2+"
};

String test1_2(ET2<int> l) =>
switch (l) {
<int?>[] => "0",
[_] => "1",
[_, _] => "2",
[_, _, ...] => "2+"
};

String test2_1(ET1<bool> l) =>
switch (l) {
[] => "0",
[true] => "1_1",
[false] => "1_2",
[_, true] => "2_1",
[_, false] => "2_2",
[_, true, ...var r1] => "3_1",
[_, false, ...final r2] => "3_2"
};

String test2_2(ET2<bool> l) =>
switch (l) {
[] => "0",
[true] => "1_1",
[false] => "1_2",
[_, true] => "2_1",
[_, false] => "2_2",
[_, true, ...var r1] => "3_1",
[_, false, ...final r2] => "3_2"
};

main() {
Expect.equals("0", test1_1(ET1([])));
Expect.equals("1", test1_1(ET1([1])));
Expect.equals("2", test1_1(ET1<int>([1, 2])));
Expect.equals("2+", test1_1(ET1([1, 2, 3])));

Expect.equals("0", test1_2(ET2([])));
Expect.equals("1", test1_2(ET2([1])));
Expect.equals("2", test1_2(ET2<int>([1, 2])));
Expect.equals("2+", test1_2(ET2([1, 2, 3])));

Expect.equals("0", test2_1(ET1([])));
Expect.equals("1_1", test2_1(ET1([true])));
Expect.equals("1_2", test2_1(ET1([false])));
Expect.equals("2_1", test2_1(ET1([true, true])));
Expect.equals("2_2", test2_1(ET1([true, false])));
Expect.equals("3_1", test2_1(ET1([true, true, false])));
Expect.equals("3_2", test2_1(ET1([true, false, false])));

Expect.equals("0", test2_2(ET2([])));
Expect.equals("1_1", test2_2(ET2([true])));
Expect.equals("1_2", test2_2(ET2([false])));
Expect.equals("2_1", test2_2(ET2([true, true])));
Expect.equals("2_2", test2_2(ET2([true, false])));
Expect.equals("3_1", test2_2(ET2([true, true, false])));
Expect.equals("3_2", test2_2(ET2([true, false, false])));
}
84 changes: 84 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_list_A01_t02.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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.

/// @assertion Switch expression with a list as a matched type can be exhaustive
///
/// @description Check that it is no compile-time error if a matched type of a
/// switch expression is an extension type with a `List` as a representation
/// type and all cases are exhaustive. Test a rest element at the middle of the
/// list pattern
/// @author sgrekhov22@gmail.com
// SharedOptions=--enable-experiment=inline-class

import "../../Utils/expect.dart";

extension type ET1<T>(List<T> _) {}
extension type ET2<T>(List<T> _) implements List<T> {}

String test1_1(ET1<int> l) =>
switch (l) {
[] => "0",
<int?>[_] => "1",
[_, _] => "2",
[_, ..., _] => "2+"
};

String test1_2(ET2<int> l) =>
switch (l) {
[] => "0",
<int?>[_] => "1",
[_, _] => "2",
[_, ..., _] => "2+"
};

String test2_1(ET1<bool> l) =>
switch (l) {
[] => "0",
[true] => "1_1",
[false] => "1_2",
[_, true] => "2_1",
[_, false] => "2_2",
[_, ... var r1, true] => "3_1",
[_, ... final r2, false] => "3_2"
};

String test2_2(ET2<bool> l) =>
switch (l) {
[] => "0",
[true] => "1_1",
[false] => "1_2",
[_, true] => "2_1",
[_, false] => "2_2",
[_, ... var r1, true] => "3_1",
[_, ... final r2, false] => "3_2"
};

main() {
Expect.equals("0", test1_1(ET1([])));
Expect.equals("1", test1_1(ET1([1])));
Expect.equals("2", test1_1(ET1<int>([1, 2])));
Expect.equals("2+", test1_1(ET1([1, 2, 3])));

Expect.equals("0", test1_2(ET2([])));
Expect.equals("1", test1_2(ET2([1])));
Expect.equals("2", test1_2(ET2<int>([1, 2])));
Expect.equals("2+", test1_2(ET2([1, 2, 3])));

Expect.equals("0", test2_1(ET1([])));
Expect.equals("1_1", test2_1(ET1([true])));
Expect.equals("1_2", test2_1(ET1([false])));
Expect.equals("2_1", test2_1(ET1([true, true])));
Expect.equals("2_2", test2_1(ET1([true, false])));
Expect.equals("3_1", test2_1(ET1([true, true, true])));
Expect.equals("3_2", test2_1(ET1([true, false, false])));

Expect.equals("0", test2_2(ET2([])));
Expect.equals("1_1", test2_2(ET2([true])));
Expect.equals("1_2", test2_2(ET2([false])));
Expect.equals("2_1", test2_2(ET2([true, true])));
Expect.equals("2_2", test2_2(ET2([true, false])));
Expect.equals("3_1", test2_2(ET2([true, true, true])));
Expect.equals("3_2", test2_2(ET2([true, false, false])));
}
84 changes: 84 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_list_A01_t03.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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.

/// @assertion Switch expression with a list as a matched type can be exhaustive
///
/// @description Check that it is no compile-time error if a matched type of a
/// switch expression is an extension type with a `List` as a representation
/// type and all cases are exhaustive. Test rest element at the beginning of
/// the list pattern
/// @author sgrekhov22@gmail.com
// SharedOptions=--enable-experiment=inline-class

import "../../Utils/expect.dart";

extension type ET1<T>(List<T> _) {}
extension type ET2<T>(List<T> _) implements List<T> {}

String test1_1(ET1<int> l) =>
switch (l) {
[] => "0",
[_] => "1",
[_, _] => "2",
<int?>[..., _, _] => "2+"
};

String test1_2(ET2<int> l) =>
switch (l) {
[] => "0",
[_] => "1",
[_, _] => "2",
<int?>[..., _, _] => "2+"
};

String test2_1(ET1<bool> l) =>
switch (l) {
[] => "0",
[true] => "1_1",
[false] => "1_2",
[_, true] => "2_1",
[_, false] => "2_2",
[... var r1, true] => "3_1",
[... final r2, false] => "3_2"
};

String test2_2(ET2<bool> l) =>
switch (l) {
[] => "0",
[true] => "1_1",
[false] => "1_2",
[_, true] => "2_1",
[_, false] => "2_2",
[... var r1, true] => "3_1",
[... final r2, false] => "3_2"
};

main() {
Expect.equals("0", test1_1(ET1([])));
Expect.equals("1", test1_1(ET1([1])));
Expect.equals("2", test1_1(ET1([1, 2])));
Expect.equals("2+", test1_1(ET1([1, 2, 3])));

Expect.equals("0", test1_2(ET2([])));
Expect.equals("1", test1_2(ET2([1])));
Expect.equals("2", test1_2(ET2([1, 2])));
Expect.equals("2+", test1_2(ET2([1, 2, 3])));

Expect.equals("0", test2_1(ET1([])));
Expect.equals("1_1", test2_1(ET1([true])));
Expect.equals("1_2", test2_1(ET1([false])));
Expect.equals("2_1", test2_1(ET1([true, true])));
Expect.equals("2_2", test2_1(ET1([true, false])));
Expect.equals("3_1", test2_1(ET1([true, true, true])));
Expect.equals("3_2", test2_1(ET1([true, false, false])));

Expect.equals("0", test2_2(ET2([])));
Expect.equals("1_1", test2_2(ET2([true])));
Expect.equals("1_2", test2_2(ET2([false])));
Expect.equals("2_1", test2_2(ET2([true, true])));
Expect.equals("2_2", test2_2(ET2([true, false])));
Expect.equals("3_1", test2_2(ET2([true, true, true])));
Expect.equals("3_2", test2_2(ET2([true, false, false])));
}
47 changes: 47 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_list_A02_t01.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// 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.

/// @assertion Switch statements with a list as a matched type can never be
/// exhaustive
///
/// @description Check that exhaustiveness check is not performed for a switch
/// statement with a list as a matched type
/// @author sgrekhov22@gmail.com
extension type ET1<T>(List<T> _) {}
extension type ET2<T>(List<T> _) implements List<T> {}

String test1(ET1<bool> l) {
// ^^^^^
// [analyzer] unspecified
// [cfe] unspecified
switch (l) {
case []:
case [_]:
case [_, _]:
case [_, _, ...]:
return "ok";
}
// There is no return statement here, and static analysis doesn't know if the
// switch statement exhaustive or not, so an error above occurs because function
// return type cannot be null
}

String test2(ET2<bool> l) {
// ^^^^^
// [analyzer] unspecified
// [cfe] unspecified
switch (l) {
case []:
case [_]:
case [_, _]:
case [_, _, ...]:
return "ok";
}
}

main() {
test1(ET1([]));
test2(ET2([]));
}
87 changes: 87 additions & 0 deletions LanguageFeatures/Extension-types/exhaustiveness_list_A03_t01.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// 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.

/// @assertion Switch expression with a list as a matched type can be exhaustive
///
/// @description Check that it is a compile-time error if a matched type of a
/// switch expression is a list and cases are not exhaustive.
/// @author sgrekhov22@gmail.com
extension type ET1<T>(List<T> _) {}
extension type ET2<T>(List<T> _) implements List<T> {}

String test1_1(ET1<int> l) =>
switch (l) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
<String>[] => "0",
[_] => "1",
[_, _] => "2",
[_, _, ...] => "2+"
};

String test1_2(ET2<int> l) =>
switch (l) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
<String>[] => "0",
[_] => "1",
[_, _] => "2",
[_, _, ...] => "2+"
};

String test2_1(ET1<int> l) =>
switch (l) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
[] => "0",
<String>[_] => "1",
[_, _] => "2",
[_, ..., _] => "2+"
};

String test2_2(ET2<int> l) =>
switch (l) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
[] => "0",
<String>[_] => "1",
[_, _] => "2",
[_, ..., _] => "2+"
};

String test3_1(ET1<int> l) =>
switch (l) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
[] => "0",
[_] => "1",
[_, _] => "2",
<String>[..., _, _] => "2+"
};

String test3_2(ET2<int> l) =>
switch (l) {
//^^^^^^
// [analyzer] unspecified
// [cfe] unspecified
[] => "0",
[_] => "1",
[_, _] => "2",
<String>[..., _, _] => "2+"
};

main() {
test1_1(ET1([]));
test1_2(ET2([]));
test2_1(ET1([]));
test2_2(ET2([]));
test3_1(ET1([]));
test3_2(ET2([]));
}
Loading

0 comments on commit 03a2b9c

Please sign in to comment.