Skip to content

Commit 9169abc

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
Add SwitchStatementTypeAnalysisResult.requiresExhaustivenessValidation.
This boolean tells the analyzer and front end whether it is required to run the exhaustiness algorithm on the switch statement (and to report an error if the switch isn't exhaustive). Bug: #50585 Change-Id: I8c95e563bd59a83cf5e1b94170af5c4f8b5c6496 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/274925 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent a29cd03 commit 9169abc

File tree

4 files changed

+87
-1
lines changed

4 files changed

+87
-1
lines changed

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analysis_result.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,22 @@ class SwitchStatementTypeAnalysisResult<Type> {
125125
/// Whether the last case body in the switch statement terminated.
126126
final bool lastCaseTerminates;
127127

128+
/// If `true`, patterns support is enabled, there is no default clause, and
129+
/// the static type of the scrutinee expression is an "always exhaustive"
130+
/// type. Therefore, flow analysis has assumed (without checking) that the
131+
/// switch statement is exhaustive. So at a later stage of compilation, the
132+
/// exhaustiveness checking algorithm should check whether this switch
133+
/// statement was exhaustive, and report a compile-time error if it wasn't.
134+
final bool requiresExhaustivenessValidation;
135+
128136
/// The static type of the scrutinee expression.
129137
final Type scrutineeType;
130138

131139
SwitchStatementTypeAnalysisResult({
132140
required this.hasDefault,
133141
required this.isExhaustive,
134142
required this.lastCaseTerminates,
143+
required this.requiresExhaustivenessValidation,
135144
required this.scrutineeType,
136145
});
137146
}

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1352,18 +1352,23 @@ mixin TypeAnalyzer<
13521352
}
13531353
// Stack: (Expression, numExecutionPaths * StatementCase)
13541354
bool isExhaustive;
1355+
bool requiresExhaustivenessValidation;
13551356
if (hasDefault) {
13561357
isExhaustive = true;
1358+
requiresExhaustivenessValidation = false;
13571359
} else if (options.patternsEnabled) {
1358-
isExhaustive = isAlwaysExhaustiveType(scrutineeType);
1360+
requiresExhaustivenessValidation =
1361+
isExhaustive = isAlwaysExhaustiveType(scrutineeType);
13591362
} else {
13601363
isExhaustive = isLegacySwitchExhaustive(node, scrutineeType);
1364+
requiresExhaustivenessValidation = false;
13611365
}
13621366
flow.switchStatement_end(isExhaustive);
13631367
return new SwitchStatementTypeAnalysisResult<Type>(
13641368
hasDefault: hasDefault,
13651369
isExhaustive: isExhaustive,
13661370
lastCaseTerminates: lastCaseTerminates,
1371+
requiresExhaustivenessValidation: requiresExhaustivenessValidation,
13671372
scrutineeType: scrutineeType,
13681373
);
13691374
}

pkg/_fe_analyzer_shared/test/mini_ast.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,12 +327,15 @@ Statement switch_(Expression expression, List<_SwitchStatementMember> cases,
327327
bool? expectHasDefault,
328328
bool? expectIsExhaustive,
329329
bool? expectLastCaseTerminates,
330+
bool? expectRequiresExhaustivenessValidation,
330331
String? expectScrutineeType}) =>
331332
new _SwitchStatement(expression, cases, isLegacyExhaustive,
332333
location: computeLocation(),
333334
expectHasDefault: expectHasDefault,
334335
expectIsExhaustive: expectIsExhaustive,
335336
expectLastCaseTerminates: expectLastCaseTerminates,
337+
expectRequiresExhaustivenessValidation:
338+
expectRequiresExhaustivenessValidation,
336339
expectScrutineeType: expectScrutineeType);
337340

338341
Expression switchExpr(Expression expression, List<ExpressionCase> cases) =>
@@ -4288,13 +4291,16 @@ class _SwitchStatement extends Statement {
42884291

42894292
final bool? expectLastCaseTerminates;
42904293

4294+
final bool? expectRequiresExhaustivenessValidation;
4295+
42914296
final String? expectScrutineeType;
42924297

42934298
_SwitchStatement(this.scrutinee, this.cases, this.isLegacyExhaustive,
42944299
{required super.location,
42954300
required this.expectHasDefault,
42964301
required this.expectIsExhaustive,
42974302
required this.expectLastCaseTerminates,
4303+
required this.expectRequiresExhaustivenessValidation,
42984304
required this.expectScrutineeType});
42994305

43004306
@override
@@ -4344,6 +4350,8 @@ class _SwitchStatement extends Statement {
43444350
expect(analysisResult.isExhaustive, expectIsExhaustive ?? anything);
43454351
expect(analysisResult.lastCaseTerminates,
43464352
expectLastCaseTerminates ?? anything);
4353+
expect(analysisResult.requiresExhaustivenessValidation,
4354+
expectRequiresExhaustivenessValidation ?? anything);
43474355
expect(analysisResult.scrutineeType.type, expectScrutineeType ?? anything);
43484356
h.irBuilder.apply(
43494357
'switch',

pkg/_fe_analyzer_shared/test/type_inference/type_inference_test.dart

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,70 @@ main() {
13141314
], expectedErrors: {});
13151315
});
13161316
});
1317+
1318+
group('requiresExhaustivenessValidation:', () {
1319+
test('When a `default` clause is present', () {
1320+
h.addExhaustiveness('E', true);
1321+
h.run([
1322+
switch_(
1323+
expr('E'),
1324+
[
1325+
default_.then([
1326+
break_(),
1327+
]),
1328+
],
1329+
expectRequiresExhaustivenessValidation: false,
1330+
),
1331+
]);
1332+
});
1333+
1334+
test('When the scrutinee is an always-exhaustive type', () {
1335+
h.addExhaustiveness('E', true);
1336+
h.run([
1337+
switch_(
1338+
expr('E'),
1339+
[
1340+
expr('E').pattern.then([
1341+
break_(),
1342+
]),
1343+
],
1344+
expectRequiresExhaustivenessValidation: true,
1345+
),
1346+
]);
1347+
});
1348+
1349+
test('When the scrutinee is not an always-exhaustive type', () {
1350+
h.addExhaustiveness('C', false);
1351+
h.run([
1352+
switch_(
1353+
expr('C'),
1354+
[
1355+
expr('C').pattern.then([
1356+
break_(),
1357+
]),
1358+
],
1359+
expectRequiresExhaustivenessValidation: false,
1360+
),
1361+
]);
1362+
});
1363+
1364+
test('When pattern support is disabled', () {
1365+
h.patternsEnabled = false;
1366+
h.addExhaustiveness('E', true);
1367+
h.run([
1368+
switch_(
1369+
expr('E'),
1370+
[
1371+
expr('E').pattern.then([
1372+
break_(),
1373+
]),
1374+
],
1375+
isLegacyExhaustive: true,
1376+
expectRequiresExhaustivenessValidation: false,
1377+
),
1378+
]);
1379+
});
1380+
});
13171381
});
13181382

13191383
group('Variable declaration:', () {

0 commit comments

Comments
 (0)