Skip to content

Commit 12a32f4

Browse files
stereotype441Commit Queue
authored andcommitted
[sound flow analysis] Implement promoteForPattern behaviors.
This change updates the logic in the flow analysis method `promoteForPattern`, so that when the language feature `sound-flow-analysis` is enabled, the following additional behaviors are added: - If the matched value type is non-nullable, and the pattern implicitly performs an `is Null` test, then the pattern is known not to match. - If the matched value type is `Null`, and the pattern implicitly performs an `is T` test, where `T` is a non-nullable type, then the pattern is known not to match. Note that this reasoning step is sound regardless of whether the program is running with sound null safety enabled, but since it is a new reasoning step, it only takes place if the `sound-flow-analysis` feature is enabled. There is no behavioral change if the feature `sound-flow-analysis` is disabled. Bug: #60438 Change-Id: I5a6e8def050c95b6c1ad01d37584d17a0cd590c8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/421900 Commit-Queue: Paul Berry <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent f5a77ab commit 12a32f4

File tree

3 files changed

+554
-6
lines changed

3 files changed

+554
-6
lines changed

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

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5341,12 +5341,33 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
53415341
return false;
53425342
}
53435343

5344-
if (operations.classifyType(matchedType) ==
5345-
TypeClassification.nonNullable) {
5346-
// The matched type is non-nullable, so promote to a non-nullable type.
5347-
// This allows for code like `case int? x?` to promote `x` to
5348-
// non-nullable.
5349-
knownType = operations.promoteToNonNull(knownType);
5344+
bool cannotMatch = false;
5345+
switch (operations.classifyType(matchedType)) {
5346+
case TypeClassification.nonNullable:
5347+
if (typeAnalyzerOptions.soundFlowAnalysisEnabled &&
5348+
operations.classifyType(knownType) ==
5349+
TypeClassification.nullOrEquivalent) {
5350+
// `Null()` cannot match a non-nullable matched value, assuming sound
5351+
// null safety.
5352+
cannotMatch = true;
5353+
}
5354+
// The matched type is non-nullable, so promote to a non-nullable type.
5355+
// This allows for code like `case int? x?` to promote `x` to
5356+
// non-nullable.
5357+
knownType = operations.promoteToNonNull(knownType);
5358+
case TypeClassification.nullOrEquivalent:
5359+
if (typeAnalyzerOptions.soundFlowAnalysisEnabled &&
5360+
operations.classifyType(knownType) ==
5361+
TypeClassification.nonNullable) {
5362+
// If `T` is a non-nullable type, `T()` cannot match a matched value
5363+
// of type `Null`. This reasoning step is sound regardless of whether
5364+
// sound null safety, but it is a new reasoning step that was added to
5365+
// flow analysis as part of the `sound-flow-analysis` feature.
5366+
cannotMatch = true;
5367+
}
5368+
case TypeClassification.potentiallyNullable:
5369+
// No conclusions can be drawn about `cannotMatch` or `knownType`.
5370+
break;
53505371
}
53515372
_PatternContext<Type> context = _stack.last as _PatternContext<Type>;
53525373
_Reference<Type> matchedValueReference =
@@ -5384,6 +5405,9 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
53845405
.ifFalse;
53855406
}
53865407
_current = ifTrue;
5408+
if (cannotMatch) {
5409+
_current = _current.setUnreachable();
5410+
}
53875411
if (matchFailsIfWrongType && !coversMatchedType) {
53885412
// There's a reachable control flow path where the match might fail due to
53895413
// a type mismatch. Therefore, we must update the `_unmatched` flow state

0 commit comments

Comments
 (0)