Skip to content

Commit 40ae4df

Browse files
authored
#1401. Patterns execution. Assignment and switch statement tests (#1857)
Add tests about pattern matching execution, using pattern assignments and switch statements.
1 parent aa2682f commit 40ae4df

8 files changed

+506
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion
6+
/// Pattern assignment
7+
/// 1. Evaluate the right-hand side expression to a value v.
8+
/// 2. Match v against the pattern on the left. When matching a variable pattern
9+
/// against a value o, record that o will be the new value for the
10+
/// corresponding variable, but do not store the variable.
11+
/// 3. Once all destructuring and matching is done, store all of the assigned
12+
/// variables with their corresponding values.
13+
///
14+
/// @description Check that if matching fails then no values are assigned
15+
/// @author [email protected]
16+
17+
// SharedOptions=--enable-experiment=patterns,records
18+
19+
import "../../Utils/expect.dart";
20+
import "patterns_lib.dart";
21+
22+
main() {
23+
int v1 = 42;
24+
Expect.throws(() {
25+
(v1) = (3.14) as dynamic;
26+
});
27+
Expect.equals(42, v1);
28+
29+
int l1 = 42;
30+
int l2 = 42;
31+
Expect.throws(() {
32+
dynamic pi = 3.14;
33+
[l1, l2] = [0, pi];
34+
});
35+
Expect.equals(42, l1);
36+
Expect.equals(42, l2);
37+
38+
int m1 = 42;
39+
int m2 = 42;
40+
Expect.throws(() {
41+
dynamic pi = 3.14;
42+
{"k1": m1, "k2": m2} = {"k1": 0, "k2": pi};
43+
});
44+
Expect.equals(42, m1);
45+
Expect.equals(42, m2);
46+
47+
int r1 = 42;
48+
int r2 = 42;
49+
Expect.throws(() {
50+
dynamic pi = 3.14;
51+
(r1, r2) = (0, pi);
52+
});
53+
Expect.equals(42, r1);
54+
Expect.equals(42, r2);
55+
56+
int o1 = 42;
57+
int o2 = 42;
58+
Expect.throws(() {
59+
Circle(sizeAsInt: o1, areaAsDynamicDouble: o2) = Circle(1);
60+
});
61+
Expect.equals(42, o1);
62+
Expect.equals(42, o2);
63+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion
6+
/// Switch statement
7+
/// 1. Evaluate the switch value producing v.
8+
/// 2. For each case:
9+
/// i. Match the case's pattern against v. If the match fails then continue to
10+
/// the next case (or default clause or exit the switch if there are no
11+
/// other cases).
12+
/// ii. If there is a guard clause, evaluate it. If it does not evaluate to a
13+
/// Boolean, throw a runtime error. This can happen if the guard
14+
/// expression's type is dynamic. If it evaluates to false, continue to the
15+
/// next case (or default or exit).
16+
/// iii. Find the nearest non-empty case body at or following this case.
17+
/// You're allowed to have multiple empty cases where all preceding ones
18+
/// share the same body with the last case.
19+
/// iv. If the enclosing scope for the body is a shared case scope, then
20+
/// initialize all shared variables the values of the corresponding
21+
/// variables from the case scope. There will be no shared case scope and
22+
/// nothing to copy if the body is only used by a single case.
23+
/// v. Execute the body statement.
24+
/// vi. If execution of the body statement continues with a label, and that
25+
/// label is labeling a switch case of this switch, go to step 3 and
26+
/// continue from that label.
27+
/// vii. Otherwise the switch statement completes normally. An explicit break
28+
/// is no longer required.
29+
/// 3. If no case pattern matched and there is a default clause, execute the
30+
/// statements after it.
31+
/// 4. If the static type of v is an always-exhaustive type, no case matches,
32+
/// and there is no default clause, then throw a runtime error.
33+
///
34+
/// @description Check that if matching fails then execution continues to the
35+
/// next case or default (if any)
36+
/// @author [email protected]
37+
38+
// SharedOptions=--enable-experiment=patterns
39+
40+
import "../../Utils/expect.dart";
41+
42+
main() {
43+
String log = "";
44+
var v = [42];
45+
switch (v) {
46+
case [String s]:
47+
log += "case-1;";
48+
case [bool b]:
49+
log += "case-2;";
50+
break;
51+
case [1, 2]:
52+
log += "case-3;";
53+
}
54+
Expect.equals("", log);
55+
56+
switch (v) {
57+
case [_, 2]:
58+
log += "case-1;";
59+
case [bool _]:
60+
log += "case-2;";
61+
break;
62+
case [1, _]:
63+
log += "case-3;";
64+
default:
65+
log += "default";
66+
}
67+
Expect.equals("default", log);
68+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion
6+
/// Switch statement
7+
/// 1. Evaluate the switch value producing v.
8+
/// 2. For each case:
9+
/// i. Match the case's pattern against v. If the match fails then continue to
10+
/// the next case (or default clause or exit the switch if there are no
11+
/// other cases).
12+
/// ii. If there is a guard clause, evaluate it. If it does not evaluate to a
13+
/// Boolean, throw a runtime error. This can happen if the guard
14+
/// expression's type is dynamic. If it evaluates to false, continue to the
15+
/// next case (or default or exit).
16+
/// iii. Find the nearest non-empty case body at or following this case.
17+
/// You're allowed to have multiple empty cases where all preceding ones
18+
/// share the same body with the last case.
19+
/// iv. If the enclosing scope for the body is a shared case scope, then
20+
/// initialize all shared variables the values of the corresponding
21+
/// variables from the case scope. There will be no shared case scope and
22+
/// nothing to copy if the body is only used by a single case.
23+
/// v. Execute the body statement.
24+
/// vi. If execution of the body statement continues with a label, and that
25+
/// label is labeling a switch case of this switch, go to step 3 and
26+
/// continue from that label.
27+
/// vii. Otherwise the switch statement completes normally. An explicit break
28+
/// is no longer required.
29+
/// 3. If no case pattern matched and there is a default clause, execute the
30+
/// statements after it.
31+
/// 4. If the static type of v is an always-exhaustive type, no case matches,
32+
/// and there is no default clause, then throw a runtime error.
33+
///
34+
/// @description Check that if there is a guard clause, it is evaluated if match
35+
/// success
36+
/// @author [email protected]
37+
38+
// SharedOptions=--enable-experiment=patterns
39+
40+
import "../../Utils/expect.dart";
41+
42+
String log = "";
43+
44+
bool guard(int v) {
45+
log += "guard($v);";
46+
return v == 42;
47+
}
48+
49+
main() {
50+
var v = [0, 42];
51+
switch (v) {
52+
case [int v1, var v2] when guard(v1):
53+
log += "case-1;";
54+
case [1, final v3] when guard(v3):
55+
log += "case-2";
56+
break;
57+
case [0, var v4] when guard(v4):
58+
log += "case-3;";
59+
default:
60+
log += "default";
61+
}
62+
Expect.equals("guard(0);guard(42);case-3;", log);
63+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion
6+
/// Switch statement
7+
/// 1. Evaluate the switch value producing v.
8+
/// 2. For each case:
9+
/// i. Match the case's pattern against v. If the match fails then continue to
10+
/// the next case (or default clause or exit the switch if there are no
11+
/// other cases).
12+
/// ii. If there is a guard clause, evaluate it. If it does not evaluate to a
13+
/// Boolean, throw a runtime error. This can happen if the guard
14+
/// expression's type is dynamic. If it evaluates to false, continue to the
15+
/// next case (or default or exit).
16+
/// iii. Find the nearest non-empty case body at or following this case.
17+
/// You're allowed to have multiple empty cases where all preceding ones
18+
/// share the same body with the last case.
19+
/// iv. If the enclosing scope for the body is a shared case scope, then
20+
/// initialize all shared variables the values of the corresponding
21+
/// variables from the case scope. There will be no shared case scope and
22+
/// nothing to copy if the body is only used by a single case.
23+
/// v. Execute the body statement.
24+
/// vi. If execution of the body statement continues with a label, and that
25+
/// label is labeling a switch case of this switch, go to step 3 and
26+
/// continue from that label.
27+
/// vii. Otherwise the switch statement completes normally. An explicit break
28+
/// is no longer required.
29+
/// 3. If no case pattern matched and there is a default clause, execute the
30+
/// statements after it.
31+
/// 4. If the static type of v is an always-exhaustive type, no case matches,
32+
/// and there is no default clause, then throw a runtime error.
33+
///
34+
/// @description Check that it is a runtime error if guard value is not
35+
/// assignable to bool
36+
/// @author [email protected]
37+
38+
// SharedOptions=--enable-experiment=patterns
39+
40+
import "../../Utils/expect.dart";
41+
42+
dynamic guard(v) => v;
43+
44+
String test(v) {
45+
switch(42) {
46+
case 42 when guard(v):
47+
return "Case body";
48+
default:
49+
return "default";
50+
}
51+
}
52+
53+
main() {
54+
Expect.equals("Case body", test(true));
55+
Expect.equals("default", test(false));
56+
Expect.throws(() {test(42);});
57+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion
6+
/// Switch statement
7+
/// 1. Evaluate the switch value producing v.
8+
/// 2. For each case:
9+
/// i. Match the case's pattern against v. If the match fails then continue to
10+
/// the next case (or default clause or exit the switch if there are no
11+
/// other cases).
12+
/// ii. If there is a guard clause, evaluate it. If it does not evaluate to a
13+
/// Boolean, throw a runtime error. This can happen if the guard
14+
/// expression's type is dynamic. If it evaluates to false, continue to the
15+
/// next case (or default or exit).
16+
/// iii. Find the nearest non-empty case body at or following this case.
17+
/// You're allowed to have multiple empty cases where all preceding ones
18+
/// share the same body with the last case.
19+
/// iv. If the enclosing scope for the body is a shared case scope, then
20+
/// initialize all shared variables the values of the corresponding
21+
/// variables from the case scope. There will be no shared case scope and
22+
/// nothing to copy if the body is only used by a single case.
23+
/// v. Execute the body statement.
24+
/// vi. If execution of the body statement continues with a label, and that
25+
/// label is labeling a switch case of this switch, go to step 3 and
26+
/// continue from that label.
27+
/// vii. Otherwise the switch statement completes normally. An explicit break
28+
/// is no longer required.
29+
/// 3. If no case pattern matched and there is a default clause, execute the
30+
/// statements after it.
31+
/// 4. If the static type of v is an always-exhaustive type, no case matches,
32+
/// and there is no default clause, then throw a runtime error.
33+
///
34+
/// @description Check that body of the matched case is executed
35+
/// @author [email protected]
36+
37+
// SharedOptions=--enable-experiment=patterns
38+
39+
import "../../Utils/expect.dart";
40+
41+
String log = "";
42+
43+
bool guard(int n, bool b) {
44+
log += "guard$n($b);";
45+
return b;
46+
}
47+
48+
void test(List<int> list) {
49+
log = "";
50+
switch (list) {
51+
case [1, var v1] when guard(1, v1 == 1):
52+
case [2, final v2] when guard(2, v2 == 2):
53+
case [3, var v3] when guard(3, v3 == 3):
54+
log += "shared body;";
55+
case [4, var v4] when guard(4, v4 == 4):
56+
log += "not shared body;";
57+
default:
58+
log += "default;";
59+
}
60+
}
61+
62+
main() {
63+
test([1, 1]);
64+
Expect.equals("guard1(true);shared body;", log);
65+
test([2, 2]);
66+
Expect.equals("guard2(true);shared body;", log);
67+
test([3, 3]);
68+
Expect.equals("guard3(true);shared body;", log);
69+
test([4, 4]);
70+
Expect.equals("guard4(true);not shared body;", log);
71+
test([1, 42]);
72+
Expect.equals("guard1(false);default;", log);
73+
test([2, 42]);
74+
Expect.equals("guard2(false);default;", log);
75+
test([3, 42]);
76+
Expect.equals("guard3(false);default;", log);
77+
test([4, 42]);
78+
Expect.equals("guard4(false);default;", log);
79+
test([]);
80+
Expect.equals("default;", log);
81+
}

0 commit comments

Comments
 (0)