From b0bb07c2f9a453ffce478a59543aca5a0387fa51 Mon Sep 17 00:00:00 2001 From: sgrekhov Date: Tue, 22 Apr 2025 11:45:42 +0300 Subject: [PATCH 1/5] #3057. Add promotion tests for `if` and `break` statements --- .../reachability_break_A05_t01.dart | 85 +++++++++++++ .../reachability_break_A05_t02.dart | 100 +++++++++++++++ .../reachability_break_A05_t03.dart | 100 +++++++++++++++ .../reachability_break_A05_t04.dart | 116 ++++++++++++++++++ .../reachability_conditional_A05_t01.dart | 65 ++++++++++ .../reachability_conditional_A05_t02.dart | 60 +++++++++ .../reachability_conditional_A05_t03.dart | 68 ++++++++++ .../reachability_conditional_A05_t04.dart | 76 ++++++++++++ 8 files changed, 670 insertions(+) create mode 100644 TypeSystem/flow-analysis/reachability_break_A05_t01.dart create mode 100644 TypeSystem/flow-analysis/reachability_break_A05_t02.dart create mode 100644 TypeSystem/flow-analysis/reachability_break_A05_t03.dart create mode 100644 TypeSystem/flow-analysis/reachability_break_A05_t04.dart create mode 100644 TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart create mode 100644 TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart create mode 100644 TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart create mode 100644 TypeSystem/flow-analysis/reachability_conditional_A05_t04.dart diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t01.dart b/TypeSystem/flow-analysis/reachability_break_A05_t01.dart new file mode 100644 index 0000000000..29cce3bd9d --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_break_A05_t01.dart @@ -0,0 +1,85 @@ +// Copyright (c) 2025, 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 Break statement: If `N` is a statement of the form `break [L];`, +/// then: +/// - Let `S` be the statement targeted by the `break`. If `L` is not present, +/// this is the innermost `do`, `for`, `switch`, or `while` statement. +/// Otherwise it is the `do`, `for`, `switch`, or `while` statement with a +/// label matching L. +/// - Update `break(S) = join(break(S), before(N))`. +/// - Let `after(N) = unreachable(before(N))`. +/// +/// @description Checks that is some type `T` is made a type of interest +/// `before(N)` then some variable can be promoted to `T` in `after(N)`. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + for (int j = 0; j < 1; j++) { + if (s is T) {} // Make `T` a type of interest + break; + s = T(); + s.answer(); + } +} + +test2() { + S s = S(); + for (var j in []) { + if (s is T) {} + break; + s = T(); + s.answer(); + } +} + +test3() { + S s = S(); + do { + if (s is T) {} + break; + s = T(); + s.answer(); + } while (1 > 2); +} + +test4() { + S s = S(); + int i = 0; + while (i < 1) { + i++; + if (s is T) {} + break; + s = T(); + s.answer(); + } +} + +test5() { + S s = S(); + switch (42) { + case 1: + break; + case 42: + if (s is T) {} + break; + s = T(); + s.answer(); + } +} + +main() { + test1(); + test2(); + test3(); + test4(); + test5(); +} diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t02.dart b/TypeSystem/flow-analysis/reachability_break_A05_t02.dart new file mode 100644 index 0000000000..2561c3dcb5 --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_break_A05_t02.dart @@ -0,0 +1,100 @@ +// Copyright (c) 2025, 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 Break statement: If `N` is a statement of the form `break [L];`, +/// then: +/// - Let `S` be the statement targeted by the `break`. If `L` is not present, +/// this is the innermost `do`, `for`, `switch`, or `while` statement. +/// Otherwise it is the `do`, `for`, `switch`, or `while` statement with a +/// label matching L. +/// - Update `break(S) = join(break(S), before(N))`. +/// - Let `after(N) = unreachable(before(N))`. +/// +/// @description Checks that is some type `T` is made a type of interest +/// `before(N)` then some variable can be promoted to `T` in `after(N)`. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + L: + for (int j = 0; j < 1; j++) { + for (int j = 0; j < 1; j++) { + if (s is T) {} // Make `T` a type of interest + break L; + s = T(); + s.answer(); + } + } +} + +test2() { + S s = S(); + L: + for (var i in []) { + for (var j in []) { + if (s is T) {} + break L; + s = T(); + s.answer(); + } + } +} + +test3() { + S s = S(); + L: + do { + do { + if (s is T) {} + break L; + s = T(); + s.answer(); + } while (1 > 2); + } while (1 > 2); +} + +test4() { + S s = S(); + int i = 0; + L: + while (i < 1) { + while (i < 1) { + i++; + if (s is T) {} + break L; + s = T(); + s.answer(); + } + } +} + +test5() { + S s = S(); + L: + for (;;) { + switch (42) { + case 1: + break; + case 42: + if (s is T) {} + break L; + s = T(); + s.answer(); + } + } +} + +main() { + test1(); + test2(); + test3(); + test4(); + test5(); +} diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t03.dart b/TypeSystem/flow-analysis/reachability_break_A05_t03.dart new file mode 100644 index 0000000000..dc5a5d7905 --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_break_A05_t03.dart @@ -0,0 +1,100 @@ +// Copyright (c) 2025, 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 Break statement: If `N` is a statement of the form `break [L];`, +/// then: +/// - Let `S` be the statement targeted by the `break`. If `L` is not present, +/// this is the innermost `do`, `for`, `switch`, or `while` statement. +/// Otherwise it is the `do`, `for`, `switch`, or `while` statement with a +/// label matching L. +/// - Update `break(S) = join(break(S), before(N))`. +/// - Let `after(N) = unreachable(before(N))`. +/// +/// @description Checks that is some type `T` is made a type of interest +/// `after(N)` then some variable cannot be promoted to `T` in `before(N)`. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + for (int j = 0; j < 2; j++) { + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break; + if (s is T) {} // Make `T` a type of interest + } +} + +test2() { + S s = S(); + for (var j in []) { + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break; + if (s is T) {} + } +} + +test3() { + S s = S(); + do { + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break; + if (s is T) {} + } while (1 > 2); +} + +test4() { + S s = S(); + int i = 0; + while (i < 2) { + i++; + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break; + if (s is T) {} + } +} + +test5() { + S s = S(); + switch (42) { + case 1: + break; + case 42: + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break; + if (s is T) {} + } +} + +main() { + print(test1); + print(test2); + print(test5); + print(test4); + print(test5); +} diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t04.dart b/TypeSystem/flow-analysis/reachability_break_A05_t04.dart new file mode 100644 index 0000000000..5fba34f9b7 --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_break_A05_t04.dart @@ -0,0 +1,116 @@ +// Copyright (c) 2025, 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 Break statement: If `N` is a statement of the form `break [L];`, +/// then: +/// - Let `S` be the statement targeted by the `break`. If `L` is not present, +/// this is the innermost `do`, `for`, `switch`, or `while` statement. +/// Otherwise it is the `do`, `for`, `switch`, or `while` statement with a +/// label matching L. +/// - Update `break(S) = join(break(S), before(N))`. +/// - Let `after(N) = unreachable(before(N))`. +/// +/// @description Checks that is some type `T` is made a type of interest +/// `after(N)` then some variable cannot be promoted to `T` in `before(N)`. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + L: + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break L; + if (s is T) {} // Make `T` a type of interest + } + } +} + +test2() { + S s = S(); + L: + for (var i in []) { + for (var j in []) { + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break L; + if (s is T) {} + } + } +} + +test3() { + S s = S(); + L: + do{ + do { + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break L; + if (s is T) {} + } while (1 > 2); + } while (1 > 2); +} + +test4() { + S s = S(); + int i = 0; + L: + while (i < 2) { + while (i < 2) { + i++; + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break L; + if (s is T) {} + } + } +} + +test5() { + S s = S(); + L: + for (;;) { + switch (42) { + case 1: + break; + case 42: + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + break L; + if (s is T) {} + } + } +} + + +main() { + print(test1); + print(test2); + print(test3); + print(test4); + print(test5); +} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart new file mode 100644 index 0000000000..0c30a49ca0 --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart @@ -0,0 +1,65 @@ +// Copyright (c) 2025, 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 Conditional statement: If `N` is a conditional statement of the +/// form `if (E) S1 else S2` then: +/// - Let `before(E) = before(N)`. +/// - Let `before(S1) = split(true(E))`. +/// - Let `before(S2) = split(false(E))`. +/// - Let `after(N) = merge(after(S1), after(S2))`. +/// +/// @description Checks that if a type `T` is made a type of interest +/// `before(N)` then some variable can be promoted to `T` in `E`, `S1`, `S2` and +/// `after(N)`. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + s is T ? 1 : 2; // Make `T` a type of interest + if ([s = T(), s.answer()] == []) { + } +} + +test2() { + S s = S(); + s is T ? 1 : 2; + if (2 > 1) { + s = T(); + s.answer(); + } else { + } +} + +test3() { + S s = S(); + s is T ? 1 : 2; + if (1 > 2) { + } else { + s = T(); + s.answer(); + } +} + +test4() { + S s = S(); + s is T ? 1 : 2; + if (1 > 2) { + } else { + } + s = T(); + s.answer(); +} + +main() { + test1(); + test2(); + test3(); + test4(); +} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart new file mode 100644 index 0000000000..77e0549ac9 --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart @@ -0,0 +1,60 @@ +// Copyright (c) 2025, 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 Conditional statement: If `N` is a conditional statement of the +/// form `if (E) S1 else S2` then: +/// - Let `before(E) = before(N)`. +/// - Let `before(S1) = split(true(E))`. +/// - Let `before(S2) = split(false(E))`. +/// - Let `after(N) = merge(after(S1), after(S2))`. +/// +/// @description Checks that if a type `T` is made a type of interest in `E` +/// then some variable can be promoted to `T` in `E`, `S1`, `S2` and `after(N)`. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + if ([s is T ? 1 : 2, s = T(), s.answer()] == []) { + } +} + +test2() { + S s = S(); + if (s is T) { + s = T(); + s.answer(); + } else { + } +} + +test3() { + S s = S(); + if (s is T) { + } else { + s = T(); + s.answer(); + } +} + +test4() { + S s = S(); + if (s is T) { + } else { + } + s = T(); + s.answer(); +} + +main() { + test1(); + test2(); + test3(); + test4(); +} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart new file mode 100644 index 0000000000..dab6a93ea8 --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart @@ -0,0 +1,68 @@ +// Copyright (c) 2025, 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 Conditional statement: If `N` is a conditional statement of the +/// form `if (E) S1 else S2` then: +/// - Let `before(E) = before(N)`. +/// - Let `before(S1) = split(true(E))`. +/// - Let `before(S2) = split(false(E))`. +/// - Let `after(N) = merge(after(S1), after(S2))`. +/// +/// @description Checks that if a type `T` is made a type of interest in `S1` or +/// `S2` then some variable can be promoted to `T` in appropriate `S1` or `S2` +/// and `after(N)`. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + if (2 > 1) { + s is T ? 1 : 2; + s = T(); + s.answer(); + } else { + } +} + +test2() { + S s = S(); + if (1 > 2) { + } else { + s is T ? 1 : 2; + s = T(); + s.answer(); + } +} + +test3() { + S s = S(); + if (2 > 1) { + s is T ? 1 : 2; + } else { + } + s = T(); + s.answer(); +} + +test4() { + S s = S(); + if (1 > 2) { + } else { + s is T ? 1 : 2; + } + s = T(); + s.answer(); +} + +main() { + test1(); + test2(); + test3(); + test4(); +} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t04.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t04.dart new file mode 100644 index 0000000000..80e1f851e2 --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t04.dart @@ -0,0 +1,76 @@ +// Copyright (c) 2025, 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 Conditional statement: If `N` is a conditional statement of the +/// form `if (E) S1 else S2` then: +/// - Let `before(E) = before(N)`. +/// - Let `before(S1) = split(true(E))`. +/// - Let `before(S2) = split(false(E))`. +/// - Let `after(N) = merge(after(S1), after(S2))`. +/// +/// @description Checks that if a type `T` is made a type of interest in `S1` or +/// `S2` then some variable cannot be promoted to `T` in `E` and appropriate +/// `S2` or `S1`. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + if ([s = T(), s.answer()] == []) { +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + s is T ? 1 : 2; + } else { + } +} + +test2() { + S s = S(); + if ([s = T(), s.answer()] == []) { +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + } else { + s is T ? 1 : 2; + } +} + +test3() { + S s = S(); + if (2 > 1) { + s is T ? 1 : 2; + } else { + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + } +} + +test4() { + S s = S(); + if (2 > 1) { + s = T(); + s.answer(); +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + } else { + s is T ? 1 : 2; + } +} + +main() { + test1(); + test2(); + test3(); + test4(); +} From 493f35bf8b79c290c28352a2f4f519893d9cde49 Mon Sep 17 00:00:00 2001 From: sgrekhov Date: Wed, 23 Apr 2025 15:37:30 +0300 Subject: [PATCH 2/5] Add collection literals --- .../reachability_conditional_A05_t01.dart | 90 +++++++++++++-- .../reachability_conditional_A05_t02.dart | 99 ++++++++++++++-- .../reachability_conditional_A05_t03.dart | 106 +++++++++++++++++- .../reachability_conditional_A05_t05.dart | 78 +++++++++++++ .../reachability_conditional_A05_t06.dart | 79 +++++++++++++ .../reachability_conditional_A05_t07.dart | 79 +++++++++++++ 6 files changed, 509 insertions(+), 22 deletions(-) create mode 100644 TypeSystem/flow-analysis/reachability_conditional_A05_t05.dart create mode 100644 TypeSystem/flow-analysis/reachability_conditional_A05_t06.dart create mode 100644 TypeSystem/flow-analysis/reachability_conditional_A05_t07.dart diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart index 0c30a49ca0..1bd3a8e175 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart @@ -23,21 +23,65 @@ class T extends S { test1() { S s = S(); s is T ? 1 : 2; // Make `T` a type of interest - if ([s = T(), s.answer()] == []) { - } + if ([s = T(), s.answer()] == []) {} } test2() { + S s = S(); + s is T ? 1 : 2; + [ + if ([s = T(), s.answer()] == []) 0, + ]; +} + +test3() { + S s = S(); + s is T ? 1 : 2; + { + if ([s = T(), s.answer()] == []) 0, + }; +} + +test4() { + S s = S(); + s is T ? 1 : 2; + { + if ([s = T(), s.answer()] == []) 0: 0, + }; +} + +test5() { S s = S(); s is T ? 1 : 2; if (2 > 1) { s = T(); s.answer(); - } else { - } + } else {} } -test3() { +test6() { + S s = S(); + s is T ? 1 : 2; + [ + if (2 > 1) ...[s = T(), s.answer()] else 2, + ]; +} + +test7() { + S s = S(); + s is T ? 1 : 2; + { + if (2 > 1) ...[s = T(), s.answer()] else 2, + }; +} + +test8() { + S s = S(); + s is T ? 1 : 2; + {if (2 > 1) s = T(): s.answer() else 2: 2}; +} + +test9() { S s = S(); s is T ? 1 : 2; if (1 > 2) { @@ -47,12 +91,33 @@ test3() { } } -test4() { +test10() { + S s = S(); + s is T ? 1 : 2; + [ + if (1 > 2) 0 else ...[s = T(), s.answer()], + ]; +} + +test11() { + S s = S(); + s is T ? 1 : 2; + { + if (1 > 2) 0 else ...[s = T(), s.answer()], + }; +} + +test12() { + S s = S(); + s is T ? 1 : 2; + {if (1 > 2) 0: 0 else s = T(): s.answer()}; +} + +test13() { S s = S(); s is T ? 1 : 2; if (1 > 2) { - } else { - } + } else {} s = T(); s.answer(); } @@ -62,4 +127,13 @@ main() { test2(); test3(); test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test13(); } diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart index 77e0549ac9..bfcb632d57 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart @@ -21,20 +21,58 @@ class T extends S { test1() { S s = S(); - if ([s is T ? 1 : 2, s = T(), s.answer()] == []) { - } + if ([s is T ? 1 : 2, s = T(), s.answer()] == []) {} } test2() { + S s = S(); + [ + if ([s is T ? 1 : 2, s = T(), s.answer()] == []) 0, + ]; +} + +test3() { + S s = S(); + { + if ([s is T ? 1 : 2, s = T(), s.answer()] == []) 0, + }; +} + +test4() { + S s = S(); + { + if ([s is T ? 1 : 2, s = T(), s.answer()] == []) 0: 0, + }; +} + +test5() { S s = S(); if (s is T) { s = T(); s.answer(); - } else { - } + } else {} } -test3() { +test6() { + S s = S(); + [ + if (s is T) ...[s = T(), s.answer()] else 0, + ]; +} + +test7() { + S s = S(); + { + if (s is T) ...[s = T(), s.answer()] else 0, + }; +} + +test8() { + S s = S(); + {if (s is T) s = T(): s.answer() else 0: 0}; +} + +test9() { S s = S(); if (s is T) { } else { @@ -43,18 +81,63 @@ test3() { } } -test4() { +test10() { + S s = S(); + [ + if (s is T) 0 else ...[s = T(), s.answer()], + ]; +} + +test11() { + S s = S(); + { + if (s is T) 0 else ...[s = T(), s.answer()], + }; +} + +test12() { + S s = S(); + {if (s is T) 0: 0 else s = T(): s.answer()}; +} + +test13() { S s = S(); if (s is T) { - } else { - } + } else {} s = T(); s.answer(); } +test14() { + S s = S(); + [if (s is T) 0 else 1, s = T(), s.answer()]; +} + +test15() { + S s = S(); + {if (s is T) 0 else 1, s = T(), s.answer()}; +} + +test16() { + S s = S(); + {if (s is T) 0: 0 else 1: 1, s = T(): s.answer()}; +} + main() { test1(); test2(); test3(); test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test13(); + test14(); + test15(); + test16(); } diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart index dab6a93ea8..5fdae0ffc8 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart @@ -26,11 +26,31 @@ test1() { s is T ? 1 : 2; s = T(); s.answer(); - } else { - } + } else {} } test2() { + S s = S(); + [ + if (2 > 1) ...[s is T ? 1 : 2, s = T(), s.answer()] else 0, + ]; +} + +test3() { + S s = S(); + { + if (2 > 1) ...[s is T ? 1 : 2, s = T(), s.answer()] else 0, + }; +} + +test4() { + S s = S(); + { + if (2 > 1) [s is T ? 1 : 2, s = T()]: s.answer() else 0: 0, + }; +} + +test5() { S s = S(); if (1 > 2) { } else { @@ -40,17 +60,58 @@ test2() { } } -test3() { +test6() { + S s = S(); + [ + if (1 > 2) 0 else ...[s is T ? 1 : 2, s = T(), s.answer()], + ]; +} + +test7() { + S s = S(); + { + if (1 > 2) 0 else ...[s is T ? 1 : 2, s = T(), s.answer()], + }; +} + +test8() { + S s = S(); + { + if (1 > 2) 0: 0 else [s is T ? 1 : 2, s = T()]: s.answer(), + }; +} + +test9() { S s = S(); if (2 > 1) { s is T ? 1 : 2; - } else { - } + } else {} s = T(); s.answer(); } -test4() { +test10() { + S s = S(); + [if (2 > 1) s is T ? 1 : 2 else 0]; + s = T(); + s.answer(); +} + +test11() { + S s = S(); + {if (2 > 1) s is T ? 1 : 2 else 0}; + s = T(); + s.answer(); +} + +test12() { + S s = S(); + {if (2 > 1) s is T ? 1 : 2: 0 else 0: 0}; + s = T(); + s.answer(); +} + +test13() { S s = S(); if (1 > 2) { } else { @@ -60,9 +121,42 @@ test4() { s.answer(); } +test14() { + S s = S(); + [if (1 > 2) 0 else s is T ? 1 : 2]; + s = T(); + s.answer(); +} + +test15() { + S s = S(); + {if (1 > 2) 0 else s is T ? 1 : 2}; + s = T(); + s.answer(); +} + +test16() { + S s = S(); + {if (1 > 2) 0: 0 else 0: s is T ? 1 : 2}; + s = T(); + s.answer(); +} + main() { test1(); test2(); test3(); test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test13(); + test14(); + test15(); + test16(); } diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t05.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t05.dart new file mode 100644 index 0000000000..88c9634afd --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t05.dart @@ -0,0 +1,78 @@ +// Copyright (c) 2025, 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 Conditional statement: If `N` is a conditional statement of the +/// form `if (E) S1 else S2` then: +/// - Let `before(E) = before(N)`. +/// - Let `before(S1) = split(true(E))`. +/// - Let `before(S2) = split(false(E))`. +/// - Let `after(N) = merge(after(S1), after(S2))`. +/// +/// @description Checks that if a type `T` is made a type of interest in `S1` or +/// `S2` then some variable cannot be promoted to `T` in `E` and appropriate +/// `S2` or `S1`. Test a list literal. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + [ + if ([s = T(), s.answer()] == []) +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + s is T ? 1 : 2 + else 0 + ]; +} + +test2() { + S s = S(); + [ + if ([s = T(), s.answer()] == []) 0 +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + else + s is T ? 1 : 2 + ]; +} + +test3() { + S s = S(); + [ + if (2 > 1) + s is T ? 1 : 2 + else + ...[s = T(), s.answer()] +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + ]; +} + +test4() { + S s = S(); + [ + if (2 > 1) + ...[s = T(), s.answer()] +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + else + s is T ? 1 : 2 + ]; +} + +main() { + test1(); + test2(); + test3(); + test4(); +} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t06.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t06.dart new file mode 100644 index 0000000000..9ec531b4a1 --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t06.dart @@ -0,0 +1,79 @@ +// Copyright (c) 2025, 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 Conditional statement: If `N` is a conditional statement of the +/// form `if (E) S1 else S2` then: +/// - Let `before(E) = before(N)`. +/// - Let `before(S1) = split(true(E))`. +/// - Let `before(S2) = split(false(E))`. +/// - Let `after(N) = merge(after(S1), after(S2))`. +/// +/// @description Checks that if a type `T` is made a type of interest in `S1` or +/// `S2` then some variable cannot be promoted to `T` in `E` and appropriate +/// `S2` or `S1`. Test a set literal. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + { + if ([s = T(), s.answer()] == []) +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + s is T ? 1 : 2 + else + 0 + }; +} + +test2() { + S s = S(); + { + if ([s = T(), s.answer()] == []) 0 +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + else + s is T ? 1 : 2 + }; +} + +test3() { + S s = S(); + { + if (2 > 1) + s is T ? 1 : 2 + else + ...[s = T(), s.answer()] +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + }; +} + +test4() { + S s = S(); + { + if (2 > 1) + ...[s = T(), s.answer()] +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + else + s is T ? 1 : 2 + }; +} + +main() { + test1(); + test2(); + test3(); + test4(); +} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t07.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t07.dart new file mode 100644 index 0000000000..195bd0198c --- /dev/null +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t07.dart @@ -0,0 +1,79 @@ +// Copyright (c) 2025, 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 Conditional statement: If `N` is a conditional statement of the +/// form `if (E) S1 else S2` then: +/// - Let `before(E) = before(N)`. +/// - Let `before(S1) = split(true(E))`. +/// - Let `before(S2) = split(false(E))`. +/// - Let `after(N) = merge(after(S1), after(S2))`. +/// +/// @description Checks that if a type `T` is made a type of interest in `S1` or +/// `S2` then some variable cannot be promoted to `T` in `E` and appropriate +/// `S2` or `S1`. Test a map literal. +/// @author sgrekhov22@gmail.com + +class S {} + +class T extends S { + int answer() => 42; +} + +test1() { + S s = S(); + { + if ([s = T(), s.answer()] == []) +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + s is T ? 1 : 2 : 0 + else + 0: 0 + }; +} + +test2() { + S s = S(); + { + if ([s = T(), s.answer()] == []) 0: 0 +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + else + 0: s is T ? 1 : 2 + }; +} + +test3() { + S s = S(); + { + if (2 > 1) + s is T ? 1 : 2: 0 + else + s = T(): s.answer() +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + }; +} + +test4() { + S s = S(); + { + if (2 > 1) + s = T(): s.answer() +// ^^^^^^ +// [analyzer] unspecified +// [cfe] unspecified + else + 0: s is T ? 1 : 2 + }; +} + +main() { + test1(); + test2(); + test3(); + test4(); +} From 0ff5136e6106603c1684bde77cc67cfd46fda296 Mon Sep 17 00:00:00 2001 From: sgrekhov Date: Wed, 23 Apr 2025 17:19:45 +0300 Subject: [PATCH 3/5] Update descriptions --- .../flow-analysis/reachability_conditional_A05_t01.dart | 5 ++++- .../flow-analysis/reachability_conditional_A05_t02.dart | 5 ++++- .../flow-analysis/reachability_conditional_A05_t03.dart | 5 ++++- .../flow-analysis/reachability_conditional_A05_t04.dart | 2 +- .../flow-analysis/reachability_conditional_A05_t05.dart | 5 ++++- .../flow-analysis/reachability_conditional_A05_t06.dart | 5 ++++- .../flow-analysis/reachability_conditional_A05_t07.dart | 5 ++++- 7 files changed, 25 insertions(+), 7 deletions(-) diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart index 1bd3a8e175..3486507f73 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t01.dart @@ -10,8 +10,11 @@ /// - Let `after(N) = merge(after(S1), after(S2))`. /// /// @description Checks that if a type `T` is made a type of interest -/// `before(N)` then some variable can be promoted to `T` in `E`, `S1`, `S2` and +/// `before(N)` then the variable can be promoted to `T` in `E`, `S1`, `S2` and /// `after(N)`. +/// @note For now (April, 2025) the flow-analysis feature specification does not +/// specify the analysis of if elements, but we extrapolate from the treatment +/// of if statements. /// @author sgrekhov22@gmail.com class S {} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart index bfcb632d57..4b7be10cef 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t02.dart @@ -10,7 +10,10 @@ /// - Let `after(N) = merge(after(S1), after(S2))`. /// /// @description Checks that if a type `T` is made a type of interest in `E` -/// then some variable can be promoted to `T` in `E`, `S1`, `S2` and `after(N)`. +/// then the variable can be promoted to `T` in `E`, `S1`, `S2` and `after(N)`. +/// @note For now (April, 2025) the flow-analysis feature specification does not +/// specify the analysis of if elements, but we extrapolate from the treatment +/// of if statements. /// @author sgrekhov22@gmail.com class S {} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart index 5fdae0ffc8..8502499f0b 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart @@ -10,8 +10,11 @@ /// - Let `after(N) = merge(after(S1), after(S2))`. /// /// @description Checks that if a type `T` is made a type of interest in `S1` or -/// `S2` then some variable can be promoted to `T` in appropriate `S1` or `S2` +/// `S2` then the variable can be promoted to `T` in appropriate `S1` or `S2` /// and `after(N)`. +/// @note For now (April, 2025) the flow-analysis feature specification does not +/// specify the analysis of if elements, but we extrapolate from the treatment +/// of if statements. /// @author sgrekhov22@gmail.com class S {} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t04.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t04.dart index 80e1f851e2..6afffff173 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t04.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t04.dart @@ -10,7 +10,7 @@ /// - Let `after(N) = merge(after(S1), after(S2))`. /// /// @description Checks that if a type `T` is made a type of interest in `S1` or -/// `S2` then some variable cannot be promoted to `T` in `E` and appropriate +/// `S2` then the variable cannot be promoted to `T` in `E` and appropriate /// `S2` or `S1`. /// @author sgrekhov22@gmail.com diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t05.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t05.dart index 88c9634afd..f5dccdcc1e 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t05.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t05.dart @@ -10,8 +10,11 @@ /// - Let `after(N) = merge(after(S1), after(S2))`. /// /// @description Checks that if a type `T` is made a type of interest in `S1` or -/// `S2` then some variable cannot be promoted to `T` in `E` and appropriate +/// `S2` then the variable cannot be promoted to `T` in `E` and appropriate /// `S2` or `S1`. Test a list literal. +/// @note For now (April, 2025) the flow-analysis feature specification does not +/// specify the analysis of if elements, but we extrapolate from the treatment +/// of if statements. /// @author sgrekhov22@gmail.com class S {} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t06.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t06.dart index 9ec531b4a1..b61788d4c5 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t06.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t06.dart @@ -10,8 +10,11 @@ /// - Let `after(N) = merge(after(S1), after(S2))`. /// /// @description Checks that if a type `T` is made a type of interest in `S1` or -/// `S2` then some variable cannot be promoted to `T` in `E` and appropriate +/// `S2` then the variable cannot be promoted to `T` in `E` and appropriate /// `S2` or `S1`. Test a set literal. +/// @note For now (April, 2025) the flow-analysis feature specification does not +/// specify the analysis of if elements, but we extrapolate from the treatment +/// of if statements. /// @author sgrekhov22@gmail.com class S {} diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t07.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t07.dart index 195bd0198c..dfe8551e72 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t07.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t07.dart @@ -10,8 +10,11 @@ /// - Let `after(N) = merge(after(S1), after(S2))`. /// /// @description Checks that if a type `T` is made a type of interest in `S1` or -/// `S2` then some variable cannot be promoted to `T` in `E` and appropriate +/// `S2` then the variable cannot be promoted to `T` in `E` and appropriate /// `S2` or `S1`. Test a map literal. +/// @note For now (April, 2025) the flow-analysis feature specification does not +/// specify the analysis of if elements, but we extrapolate from the treatment +/// of if statements. /// @author sgrekhov22@gmail.com class S {} From 52f6675bf3ed40ad8d2ec170955932d4a08cf74b Mon Sep 17 00:00:00 2001 From: sgrekhov Date: Wed, 23 Apr 2025 17:20:31 +0300 Subject: [PATCH 4/5] Update descriptions 2 --- TypeSystem/flow-analysis/reachability_break_A05_t01.dart | 2 +- TypeSystem/flow-analysis/reachability_break_A05_t02.dart | 2 +- TypeSystem/flow-analysis/reachability_break_A05_t03.dart | 2 +- TypeSystem/flow-analysis/reachability_break_A05_t04.dart | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t01.dart b/TypeSystem/flow-analysis/reachability_break_A05_t01.dart index 29cce3bd9d..31a95dfd46 100644 --- a/TypeSystem/flow-analysis/reachability_break_A05_t01.dart +++ b/TypeSystem/flow-analysis/reachability_break_A05_t01.dart @@ -12,7 +12,7 @@ /// - Let `after(N) = unreachable(before(N))`. /// /// @description Checks that is some type `T` is made a type of interest -/// `before(N)` then some variable can be promoted to `T` in `after(N)`. +/// `before(N)` then the variable can be promoted to `T` in `after(N)`. /// @author sgrekhov22@gmail.com class S {} diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t02.dart b/TypeSystem/flow-analysis/reachability_break_A05_t02.dart index 2561c3dcb5..18981991f4 100644 --- a/TypeSystem/flow-analysis/reachability_break_A05_t02.dart +++ b/TypeSystem/flow-analysis/reachability_break_A05_t02.dart @@ -12,7 +12,7 @@ /// - Let `after(N) = unreachable(before(N))`. /// /// @description Checks that is some type `T` is made a type of interest -/// `before(N)` then some variable can be promoted to `T` in `after(N)`. +/// `before(N)` then the variable can be promoted to `T` in `after(N)`. /// @author sgrekhov22@gmail.com class S {} diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t03.dart b/TypeSystem/flow-analysis/reachability_break_A05_t03.dart index dc5a5d7905..7e9c1f027e 100644 --- a/TypeSystem/flow-analysis/reachability_break_A05_t03.dart +++ b/TypeSystem/flow-analysis/reachability_break_A05_t03.dart @@ -12,7 +12,7 @@ /// - Let `after(N) = unreachable(before(N))`. /// /// @description Checks that is some type `T` is made a type of interest -/// `after(N)` then some variable cannot be promoted to `T` in `before(N)`. +/// `after(N)` then the variable cannot be promoted to `T` in `before(N)`. /// @author sgrekhov22@gmail.com class S {} diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t04.dart b/TypeSystem/flow-analysis/reachability_break_A05_t04.dart index 5fba34f9b7..23e4c892c5 100644 --- a/TypeSystem/flow-analysis/reachability_break_A05_t04.dart +++ b/TypeSystem/flow-analysis/reachability_break_A05_t04.dart @@ -12,7 +12,7 @@ /// - Let `after(N) = unreachable(before(N))`. /// /// @description Checks that is some type `T` is made a type of interest -/// `after(N)` then some variable cannot be promoted to `T` in `before(N)`. +/// `after(N)` then the variable cannot be promoted to `T` in `before(N)`. /// @author sgrekhov22@gmail.com class S {} From 6f26f74141622dc2298b87f7eec7e2fb18082fce Mon Sep 17 00:00:00 2001 From: sgrekhov Date: Wed, 30 Apr 2025 10:18:27 +0300 Subject: [PATCH 5/5] Apply review suggestions --- .../flow-analysis/reachability_break_A05_t01.dart | 3 ++- .../flow-analysis/reachability_break_A05_t02.dart | 3 ++- .../flow-analysis/reachability_break_A05_t03.dart | 3 ++- .../flow-analysis/reachability_break_A05_t04.dart | 3 ++- .../reachability_conditional_A05_t03.dart | 15 ++++++--------- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t01.dart b/TypeSystem/flow-analysis/reachability_break_A05_t01.dart index 31a95dfd46..c36af77ff3 100644 --- a/TypeSystem/flow-analysis/reachability_break_A05_t01.dart +++ b/TypeSystem/flow-analysis/reachability_break_A05_t01.dart @@ -11,7 +11,7 @@ /// - Update `break(S) = join(break(S), before(N))`. /// - Let `after(N) = unreachable(before(N))`. /// -/// @description Checks that is some type `T` is made a type of interest +/// @description Checks that if some type `T` is made a type of interest /// `before(N)` then the variable can be promoted to `T` in `after(N)`. /// @author sgrekhov22@gmail.com @@ -26,6 +26,7 @@ test1() { for (int j = 0; j < 1; j++) { if (s is T) {} // Make `T` a type of interest break; + // Unreachable, but does support promotion. s = T(); s.answer(); } diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t02.dart b/TypeSystem/flow-analysis/reachability_break_A05_t02.dart index 18981991f4..a6e16c22ea 100644 --- a/TypeSystem/flow-analysis/reachability_break_A05_t02.dart +++ b/TypeSystem/flow-analysis/reachability_break_A05_t02.dart @@ -11,7 +11,7 @@ /// - Update `break(S) = join(break(S), before(N))`. /// - Let `after(N) = unreachable(before(N))`. /// -/// @description Checks that is some type `T` is made a type of interest +/// @description Checks that if some type `T` is made a type of interest /// `before(N)` then the variable can be promoted to `T` in `after(N)`. /// @author sgrekhov22@gmail.com @@ -28,6 +28,7 @@ test1() { for (int j = 0; j < 1; j++) { if (s is T) {} // Make `T` a type of interest break L; + // Unreachable, but does support promotion. s = T(); s.answer(); } diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t03.dart b/TypeSystem/flow-analysis/reachability_break_A05_t03.dart index 7e9c1f027e..755f7cc468 100644 --- a/TypeSystem/flow-analysis/reachability_break_A05_t03.dart +++ b/TypeSystem/flow-analysis/reachability_break_A05_t03.dart @@ -11,7 +11,7 @@ /// - Update `break(S) = join(break(S), before(N))`. /// - Let `after(N) = unreachable(before(N))`. /// -/// @description Checks that is some type `T` is made a type of interest +/// @description Checks that if some type `T` is made a type of interest /// `after(N)` then the variable cannot be promoted to `T` in `before(N)`. /// @author sgrekhov22@gmail.com @@ -30,6 +30,7 @@ test1() { // [analyzer] unspecified // [cfe] unspecified break; + // Unreachable, but does support promotion. if (s is T) {} // Make `T` a type of interest } } diff --git a/TypeSystem/flow-analysis/reachability_break_A05_t04.dart b/TypeSystem/flow-analysis/reachability_break_A05_t04.dart index 23e4c892c5..43dad6c181 100644 --- a/TypeSystem/flow-analysis/reachability_break_A05_t04.dart +++ b/TypeSystem/flow-analysis/reachability_break_A05_t04.dart @@ -11,7 +11,7 @@ /// - Update `break(S) = join(break(S), before(N))`. /// - Let `after(N) = unreachable(before(N))`. /// -/// @description Checks that is some type `T` is made a type of interest +/// @description Checks that if some type `T` is made a type of interest /// `after(N)` then the variable cannot be promoted to `T` in `before(N)`. /// @author sgrekhov22@gmail.com @@ -64,6 +64,7 @@ test3() { // [analyzer] unspecified // [cfe] unspecified break L; + // Unreachable, but does support promotion. if (s is T) {} } while (1 > 2); } while (1 > 2); diff --git a/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart b/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart index 8502499f0b..4fd293ebc9 100644 --- a/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart +++ b/TypeSystem/flow-analysis/reachability_conditional_A05_t03.dart @@ -126,23 +126,20 @@ test13() { test14() { S s = S(); - [if (1 > 2) 0 else s is T ? 1 : 2]; - s = T(); - s.answer(); + [if (1 > 2) 0 else s is T ? 1 : 2, s = T(), s.answer()]; } test15() { S s = S(); - {if (1 > 2) 0 else s is T ? 1 : 2}; - s = T(); - s.answer(); + {if (1 > 2) 0 else s is T ? 1 : 2, s = T(), s.answer()}; } test16() { S s = S(); - {if (1 > 2) 0: 0 else 0: s is T ? 1 : 2}; - s = T(); - s.answer(); + { + if (1 > 2) 0: 0 else 0: s is T ? 1 : 2, + s = T(): s.answer() + }; } main() {