Skip to content

Commit 24c50fb

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Issue 35710. Test switch exhaustiveness, improve for null.
Bug: #35710 Change-Id: I6f17db1a9b2c01ec4b97538e224146fd3cec9002 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/149606 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 4074283 commit 24c50fb

File tree

2 files changed

+100
-6
lines changed

2 files changed

+100
-6
lines changed

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2901,10 +2901,15 @@ class VariableResolverVisitor extends ScopedVisitor {
29012901
/// Tracker for whether a `switch` statement has `default` or is on an
29022902
/// enumeration, and all the enum constants are covered.
29032903
class _SwitchExhaustiveness {
2904-
/// If the switch is on an enumeration, the set of all enum constants.
2904+
/// If the switch is on an enumeration, the set of enum constants to cover.
29052905
/// Otherwise `null`.
29062906
final Set<FieldElement> _enumConstants;
29072907

2908+
/// If the switch is on an enumeration, is `true` if the null value is
2909+
/// covered, because the switch expression type is non-nullable, or `null`
2910+
/// was covered explicitly.
2911+
bool _isNullEnumValueCovered = false;
2912+
29082913
bool isExhaustive = false;
29092914

29102915
factory _SwitchExhaustiveness(DartType expressionType) {
@@ -2913,22 +2918,28 @@ class _SwitchExhaustiveness {
29132918
if (enum_ is EnumElementImpl) {
29142919
return _SwitchExhaustiveness._(
29152920
enum_.constants.toSet(),
2921+
expressionType.nullabilitySuffix == NullabilitySuffix.none,
29162922
);
29172923
}
29182924
}
2919-
return _SwitchExhaustiveness._(null);
2925+
return _SwitchExhaustiveness._(null, false);
29202926
}
29212927

2922-
_SwitchExhaustiveness._(this._enumConstants);
2928+
_SwitchExhaustiveness._(this._enumConstants, this._isNullEnumValueCovered);
29232929

29242930
void visitSwitchMember(SwitchMember node) {
29252931
if (_enumConstants != null && node is SwitchCase) {
29262932
var element = _referencedElement(node.expression);
29272933
if (element is PropertyAccessorElement) {
29282934
_enumConstants.remove(element.variable);
2929-
if (_enumConstants.isEmpty) {
2930-
isExhaustive = true;
2931-
}
2935+
}
2936+
2937+
if (node.expression is NullLiteral) {
2938+
_isNullEnumValueCovered = true;
2939+
}
2940+
2941+
if (_enumConstants.isEmpty && _isNullEnumValueCovered) {
2942+
isExhaustive = true;
29322943
}
29332944
} else if (node is SwitchDefault) {
29342945
isExhaustive = true;

pkg/analyzer/test/src/diagnostics/body_might_complete_normally_test.dart

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,89 @@ Iterable<int> foo() sync* {}
6464
''');
6565
}
6666

67+
test_function_nonNullable_blockBody_switchStatement_notNullable_exhaustive() async {
68+
await assertNoErrorsInCode(r'''
69+
enum Foo { a, b }
70+
71+
int f(Foo foo) {
72+
switch (foo) {
73+
case Foo.a:
74+
return 0;
75+
case Foo.b:
76+
return 1;
77+
}
78+
}
79+
''');
80+
}
81+
82+
test_function_nonNullable_blockBody_switchStatement_notNullable_notExhaustive() async {
83+
await assertErrorsInCode(r'''
84+
enum Foo { a, b }
85+
86+
int f(Foo foo) {
87+
switch (foo) {
88+
case Foo.a:
89+
return 0;
90+
}
91+
}
92+
''', [
93+
error(CompileTimeErrorCode.BODY_MIGHT_COMPLETE_NORMALLY, 23, 1),
94+
error(StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH, 38, 12),
95+
]);
96+
}
97+
98+
test_function_nonNullable_blockBody_switchStatement_nullable_exhaustive_default() async {
99+
await assertNoErrorsInCode(r'''
100+
enum Foo { a, b }
101+
102+
int f(Foo? foo) {
103+
switch (foo) {
104+
case Foo.a:
105+
return 0;
106+
case Foo.b:
107+
return 1;
108+
default:
109+
return 2;
110+
}
111+
}
112+
''');
113+
}
114+
115+
test_function_nonNullable_blockBody_switchStatement_nullable_exhaustive_null() async {
116+
await assertNoErrorsInCode(r'''
117+
enum Foo { a, b }
118+
119+
int f(Foo? foo) {
120+
switch (foo) {
121+
case null:
122+
return 0;
123+
case Foo.a:
124+
return 1;
125+
case Foo.b:
126+
return 2;
127+
}
128+
}
129+
''');
130+
}
131+
132+
test_function_nonNullable_blockBody_switchStatement_nullable_notExhaustive_null() async {
133+
await assertErrorsInCode(r'''
134+
enum Foo { a, b }
135+
136+
int f(Foo? foo) {
137+
switch (foo) {
138+
case Foo.a:
139+
return 0;
140+
case Foo.b:
141+
return 1;
142+
}
143+
}
144+
''', [
145+
error(CompileTimeErrorCode.BODY_MIGHT_COMPLETE_NORMALLY, 23, 1),
146+
error(StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH, 39, 12),
147+
]);
148+
}
149+
67150
test_function_nullable_blockBody() async {
68151
await assertNoErrorsInCode(r'''
69152
int foo() {

0 commit comments

Comments
 (0)