Skip to content

Commit de58cf7

Browse files
stereotype441Commit Queue
authored and
Commit Queue
committed
[sound flow analysis] Implement behaviors for null check patterns.
This change updates the flow analysis logic for null check patterns, so that when the language feature `sound-flow-analysis` is enabled, the matched value type is checked for nullability. If it's non-nullable, then the null check pattern is known to succeed. There is no behavioral change if the feature `sound-flow-analysis` is disabled. Bug: #60438 Change-Id: Ie68d98d95e30053f992a3f8db6ccdd3978960eb7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/421583 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Chloe Stefantsova <cstefantsova@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
1 parent 2cc25a8 commit de58cf7

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart

+11-8
Original file line numberDiff line numberDiff line change
@@ -5219,14 +5219,17 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
52195219
bool nullCheckOrAssertPattern_begin(
52205220
{required bool isAssert, required Type matchedValueType}) {
52215221
if (!isAssert) {
5222-
// Account for the possibility that the pattern might not match. Note
5223-
// that it's tempting to skip this step if matchedValueType is
5224-
// non-nullable (based on the reasoning that a non-null value is
5225-
// guaranteed to satisfy a null check), but in weak mode that's not sound,
5226-
// because in weak mode even non-nullable values might be null. We don't
5227-
// want flow analysis behavior to depend on mode, so we conservatively
5228-
// assume the pattern might not match regardless of matchedValueType.
5229-
_unmatched = _join(_unmatched, _current);
5222+
if (typeAnalyzerOptions.soundFlowAnalysisEnabled &&
5223+
operations.classifyType(matchedValueType) ==
5224+
TypeClassification.nonNullable) {
5225+
// The pattern is guaranteed to match.
5226+
} else {
5227+
// The pattern might not match, either because matchedValueType is
5228+
// nullable, or because sound flow analysis is disabled (in which case
5229+
// we presume the user might be running under an older version of Dart
5230+
// that supported weak null safety mode).
5231+
_unmatched = _join(_unmatched, _current);
5232+
}
52305233
}
52315234
FlowModel<Type>? ifNotNull =
52325235
_nullCheckPattern(matchedValueType: matchedValueType);

pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart

+29
Original file line numberDiff line numberDiff line change
@@ -11022,6 +11022,35 @@ main() {
1102211022
]);
1102311023
});
1102411024
});
11025+
11026+
group('? pattern applied to non-nullable type', () {
11027+
test('When enabled, guaranteed to match', () {
11028+
h.run([
11029+
ifCase(expr('int'), wildcard().nullCheck..errorId = 'nullCheck', [
11030+
checkReachable(true),
11031+
], [
11032+
checkReachable(false),
11033+
]),
11034+
], expectedErrors: {
11035+
'matchedTypeIsStrictlyNonNullable(pattern: nullCheck, '
11036+
'matchedType: int)'
11037+
});
11038+
});
11039+
11040+
test('When disabled, not guaranteed to match', () {
11041+
h.disableSoundFlowAnalysis();
11042+
h.run([
11043+
ifCase(expr('int'), wildcard().nullCheck..errorId = 'nullCheck', [
11044+
checkReachable(true),
11045+
], [
11046+
checkReachable(true),
11047+
]),
11048+
], expectedErrors: {
11049+
'matchedTypeIsStrictlyNonNullable(pattern: nullCheck, '
11050+
'matchedType: int)'
11051+
});
11052+
});
11053+
});
1102511054
});
1102611055
}
1102711056

pkg/front_end/test/spell_checking_list_code.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,7 @@ presented
13471347
pressure
13481348
presubmit
13491349
presumably
1350+
presume
13501351
presuming
13511352
prev
13521353
primarily

0 commit comments

Comments
 (0)