Skip to content

Commit 3b5f2f5

Browse files
authored
#3057. Add tests for cascade method invocation (#3095)
Add tests for cascade method invocation
1 parent cc5f0e8 commit 3b5f2f5

9 files changed

+513
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) 2025, 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 - Method invocation: If `N` is an expression of the form
6+
/// `E1.m1(E2)`, then:
7+
/// - Let `before(E1) = before(N)`
8+
/// - Let `before(E2) = after(E1)`
9+
/// - Let `T` be the static return type of the invocation
10+
/// - If `T <: Never` then:
11+
/// - Let `after(N) = unreachable(after(E2))`.
12+
/// - Otherwise:
13+
/// - Let `after(N) = after(E2)`.
14+
///
15+
/// @description Checks that for an expression of the form `E1..m1(E2)`
16+
/// `before(E2) = after(E1)`. Test that if `after(E1)` is unreachable then
17+
/// `before(E2)` is also unreachable.
18+
/// @note As of now (March 2025), cascade method invocation is still a TODO item
19+
/// in the flow analysis specification. That's why cascaded invocation tests are
20+
/// covered by this assertion, which does not mention cascades.
21+
/// @author [email protected]
22+
23+
void test<T extends Never>(T n) {
24+
late int i;
25+
if (2 > 1) {
26+
n..foo(i = 42);
27+
}
28+
i; // Definitely unassigned
29+
//^
30+
// [analyzer] unspecified
31+
// [cfe] unspecified
32+
}
33+
34+
main() {
35+
print(test);
36+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) 2025, 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 - Method invocation: If `N` is an expression of the form
6+
/// `E1.m1(E2)`, then:
7+
/// - Let `before(E1) = before(N)`
8+
/// - Let `before(E2) = after(E1)`
9+
/// - Let `T` be the static return type of the invocation
10+
/// - If `T <: Never` then:
11+
/// - Let `after(N) = unreachable(after(E2))`.
12+
/// - Otherwise:
13+
/// - Let `after(N) = after(E2)`.
14+
///
15+
/// @description Checks that for an expression of the form `E1..m1(E2)`
16+
/// `before(E2) = after(E1)`. Test that if `after(E1)` is unreachable then
17+
/// `before(E2)` is also unreachable.
18+
/// @note As of now (March 2025), cascade method invocation is still a TODO item
19+
/// in the flow analysis specification. That's why cascaded invocation tests are
20+
/// covered by this assertion, which does not mention cascades.
21+
/// @author [email protected]
22+
23+
class C {
24+
C(int i);
25+
void foo(int j) {}
26+
}
27+
28+
void test<T extends Never>(T n) {
29+
late int i;
30+
if (2 > 1) {
31+
C(n)..foo(i = 42);
32+
}
33+
i; // Definitely unassigned
34+
//^
35+
// [analyzer] unspecified
36+
// [cfe] unspecified
37+
}
38+
39+
main() {
40+
print(test);
41+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2025, 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 - Method invocation: If `N` is an expression of the form
6+
/// `E1.m1(E2)`, then:
7+
/// - Let `before(E1) = before(N)`
8+
/// - Let `before(E2) = after(E1)`
9+
/// - Let `T` be the static return type of the invocation
10+
/// - If `T <: Never` then:
11+
/// - Let `after(N) = unreachable(after(E2))`.
12+
/// - Otherwise:
13+
/// - Let `after(N) = after(E2)`.
14+
///
15+
/// @description Checks that if in the expression of the form `E1..m1(E2)` the
16+
/// return type of `m1(...)` is `Never` then `after(N) = unreachable(after(E2))`
17+
/// @note As of now (March 2025), cascade method invocation is still a TODO item
18+
/// in the flow analysis specification. That's why cascaded invocation tests are
19+
/// covered by this assertion, which does not mention cascades.
20+
/// @author [email protected]
21+
22+
class C<T extends Never> {
23+
T foo() => throw "";
24+
Future<T> bar() async {
25+
throw "";
26+
}
27+
}
28+
29+
void test1() {
30+
late int i;
31+
if (2 > 1) {
32+
C()..foo();
33+
i = 42;
34+
}
35+
i; // Definitely unassigned
36+
//^
37+
// [analyzer] unspecified
38+
// [cfe] unspecified
39+
}
40+
41+
void test2() {
42+
late int i;
43+
if (2 > 1) {
44+
C()..bar(); // Return type is not `Never`
45+
i = 42;
46+
}
47+
i; // Not definitely unassigned
48+
}
49+
50+
void test3() async {
51+
late int i;
52+
if (2 > 1) {
53+
await C() // This should be parsed as (await C())
54+
..bar(); // Return type is not `Never`
55+
i = 42;
56+
}
57+
i; // Not definitely unassigned
58+
}
59+
60+
main() {
61+
print(test1);
62+
print(test2);
63+
print(test3);
64+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright (c) 2025, 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 - Method invocation: If `N` is an expression of the form
6+
/// `E1.m1(E2)`, then:
7+
/// - Let `before(E1) = before(N)`
8+
/// - Let `before(E2) = after(E1)`
9+
/// - Let `T` be the static return type of the invocation
10+
/// - If `T <: Never` then:
11+
/// - Let `after(N) = unreachable(after(E2))`.
12+
/// - Otherwise:
13+
/// - Let `after(N) = after(E2)`.
14+
///
15+
/// @description Checks that if in the expression of the form `E1..m1(E2)` the
16+
/// return type of `m1(...)` is `Never` then `after(N) = unreachable(after(E2))`
17+
/// @note As of now (March 2025), cascade method invocation is still a TODO item
18+
/// in the flow analysis specification. That's why cascaded invocation tests are
19+
/// covered by this assertion, which does not mention cascades.
20+
/// @author [email protected]
21+
22+
class C<T extends Never> {
23+
T foo() => throw "";
24+
Future<T> bar() async {
25+
throw "";
26+
}
27+
void qux(int _) {}
28+
}
29+
30+
void test1() {
31+
late int i;
32+
if (2 > 1) {
33+
C()
34+
..foo()
35+
..qux(i = 42);
36+
}
37+
i; // Definitely unassigned
38+
//^
39+
// [analyzer] unspecified
40+
// [cfe] unspecified
41+
}
42+
43+
void test2() {
44+
late int i;
45+
if (2 > 1) {
46+
C()
47+
..bar() // Return type is not `Never`
48+
..qux(i = 42);
49+
}
50+
i; // Not definitely unassigned
51+
}
52+
53+
void test3() async {
54+
late int i;
55+
if (2 > 1) {
56+
await C() // This should be parsed as (await C())
57+
..bar() // Return type is not `Never`
58+
..qux(i = 42);
59+
}
60+
i; // Not definitely unassigned
61+
}
62+
63+
main() {
64+
print(test1);
65+
print(test2);
66+
print(test3);
67+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright (c) 2025, 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 - Method invocation: If `N` is an expression of the form
6+
/// `E1.m1(E2)`, then:
7+
/// - Let `before(E1) = before(N)`
8+
/// - Let `before(E2) = after(E1)`
9+
/// - Let `T` be the static return type of the invocation
10+
/// - If `T <: Never` then:
11+
/// - Let `after(N) = unreachable(after(E2))`.
12+
/// - Otherwise:
13+
/// - Let `after(N) = after(E2)`.
14+
///
15+
/// @description Checks that if the static type of the expression of the form
16+
/// `E1..m1(E2)` is `Never` then `E2` is still reachable.
17+
/// @note As of now (March 2025), cascade method invocation is still a TODO item
18+
/// in the flow analysis specification. That's why cascaded invocation tests are
19+
/// covered by this assertion, which does not mention cascades.
20+
/// @author [email protected]
21+
22+
class C<T extends Never> {
23+
T foo(int x) => throw "foo";
24+
T bar([int x = 0]) => throw "bar";
25+
T baz({int x = 0}) => throw "baz";
26+
T qux({required int x}) => throw "qux";
27+
}
28+
29+
void test1() {
30+
late int i;
31+
try {
32+
C()..foo(i = 42);
33+
} catch (_) {}
34+
i; // Not definitely unassigned
35+
}
36+
37+
void test2() {
38+
late int i;
39+
try {
40+
C()..bar(i = 42);
41+
} catch (_) {}
42+
i;
43+
}
44+
45+
void test3() {
46+
late int i;
47+
try {
48+
C()..baz(x: i = 42);
49+
} catch (_) {}
50+
i;
51+
}
52+
53+
void test4() {
54+
late int i;
55+
try {
56+
C()..qux(x: i = 42);
57+
} catch (_) {}
58+
i;
59+
}
60+
61+
main() {
62+
test1();
63+
test2();
64+
test3();
65+
test4();
66+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2025, 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 - Method invocation: If `N` is an expression of the form
6+
/// `E1.m1(E2)`, then:
7+
/// - Let `before(E1) = before(N)`
8+
/// - Let `before(E2) = after(E1)`
9+
/// - Let `T` be the static return type of the invocation
10+
/// - If `T <: Never` then:
11+
/// - Let `after(N) = unreachable(after(E2))`.
12+
/// - Otherwise:
13+
/// - Let `after(N) = after(E2)`.
14+
///
15+
/// @description Checks that for an expression of the form `E1..m1(E2)`, if the
16+
/// static type of `E1` is not `Never` then `after(N) = after(E2)`. This is
17+
/// tested by detecting that `i = 42` is considered to be guaranteed to have
18+
/// been executed when `i;` is executed.
19+
/// @note As of now (March 2025), cascade method invocation is still a TODO item
20+
/// in the flow analysis specification. That's why cascaded invocation tests are
21+
/// covered by this assertion, which does not mention cascades.
22+
/// @author [email protected]
23+
24+
class C {
25+
void foo(int x) {}
26+
void bar([int x = 0]) {}
27+
void baz({int x = 0}) {}
28+
void qux({required int x}) {}
29+
}
30+
31+
void test1() {
32+
int i;
33+
C()..foo(i = 42);
34+
i; // Definitely assigned
35+
}
36+
37+
void test2() {
38+
int i;
39+
C()..bar(i = 42);
40+
i; // Definitely assigned
41+
}
42+
43+
void test3() {
44+
int i;
45+
C()..baz(x: i = 42);
46+
i; // Definitely assigned
47+
}
48+
49+
void test4() {
50+
int i;
51+
C()..qux(x: i = 42);
52+
i; // Definitely assigned
53+
}
54+
55+
main() {
56+
test1();
57+
test2();
58+
test3();
59+
test4();
60+
}

0 commit comments

Comments
 (0)