Skip to content

Commit ef3403e

Browse files
committed
Simplify empty pattern logic
This is logically equivalent to what was done previously; I derived it pretty mechanically.
1 parent e8f7451 commit ef3403e

File tree

3 files changed

+17
-25
lines changed

3 files changed

+17
-25
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
287287
fn is_known_valid_scrutinee(&self, scrutinee: &Expr<'tcx>) -> bool {
288288
use ExprKind::*;
289289
match &scrutinee.kind {
290-
// Both pointers and references can validly point to a place with invalid data.
290+
// Pointers can validly point to a place with invalid data. It is undecided whether
291+
// references can too, so we conservatively assume they can.
291292
Deref { .. } => false,
292293
// Inherit validity of the parent place, unless the parent is an union.
293294
Field { lhs, .. } => {

compiler/rustc_pattern_analysis/src/constructor.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,17 +1003,6 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
10031003
}
10041004
}
10051005

1006-
// We have now grouped all the constructors into 3 buckets: present, missing, missing_empty.
1007-
// In the absence of the `exhaustive_patterns` feature however, we don't count nested empty
1008-
// types as empty. Only non-nested `!` or `enum Foo {}` are considered empty.
1009-
if !pcx.mcx.tycx.is_exhaustive_patterns_feature_on()
1010-
&& !(pcx.is_scrutinee && matches!(self, Self::NoConstructors))
1011-
{
1012-
// Treat all missing constructors as nonempty.
1013-
// This clears `missing_empty`.
1014-
missing.append(&mut missing_empty);
1015-
}
1016-
10171006
SplitConstructorSet { present, missing, missing_empty }
10181007
}
10191008
}

compiler/rustc_pattern_analysis/src/usefulness.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,39 +1375,41 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
13751375

13761376
debug!("ty: {ty:?}");
13771377
let pcx = &PlaceCtxt { mcx, ty, is_scrutinee: is_top_level };
1378-
1378+
let ctors_for_ty = pcx.ctors_for_ty();
13791379
// Whether the place/column we are inspecting is known to contain valid data.
13801380
let place_validity = matrix.place_validity[0];
1381-
// For backwards compability we allow omitting some empty arms that we ideally shouldn't.
1382-
let place_validity = place_validity.allow_omitting_side_effecting_arms();
1381+
1382+
// For backwards-compatibility we treat match scrutinees of type `!` or `EmptyEnum` differently.
1383+
let is_toplevel_exception =
1384+
is_top_level && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
1385+
// Whether empty patterns are counted as useful or not.
1386+
let empty_arms_are_unreachable = place_validity.is_known_valid()
1387+
&& (is_toplevel_exception || mcx.tycx.is_exhaustive_patterns_feature_on());
1388+
// Whether empty patterns can be omitted for exhaustiveness.
1389+
let can_omit_empty_arms = is_toplevel_exception || mcx.tycx.is_exhaustive_patterns_feature_on();
13831390

13841391
// Analyze the constructors present in this column.
13851392
let ctors = matrix.heads().map(|p| p.ctor());
1386-
let ctors_for_ty = pcx.ctors_for_ty();
1387-
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
13881393
let split_set = ctors_for_ty.split(pcx, ctors);
13891394
let all_missing = split_set.present.is_empty();
1390-
13911395
// Build the set of constructors we will specialize with. It must cover the whole type.
13921396
let mut split_ctors = split_set.present;
1393-
if !split_set.missing.is_empty() {
1394-
// We need to iterate over a full set of constructors, so we add `Missing` to represent the
1395-
// missing ones. This is explained under "Constructor Splitting" at the top of this file.
1396-
split_ctors.push(Constructor::Missing);
1397-
} else if !split_set.missing_empty.is_empty() && !place_validity.is_known_valid() {
1398-
// The missing empty constructors are reachable if the place can contain invalid data.
1397+
if !split_set.missing.is_empty()
1398+
|| (!split_set.missing_empty.is_empty() && !empty_arms_are_unreachable)
1399+
{
13991400
split_ctors.push(Constructor::Missing);
14001401
}
14011402

14021403
// Decide what constructors to report.
1404+
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. });
14031405
let always_report_all = is_top_level && !is_integers;
14041406
// Whether we should report "Enum::A and Enum::C are missing" or "_ is missing".
14051407
let report_individual_missing_ctors = always_report_all || !all_missing;
14061408
// Which constructors are considered missing. We ensure that `!missing_ctors.is_empty() =>
14071409
// split_ctors.contains(Missing)`. The converse usually holds except in the
14081410
// `MaybeInvalidButAllowOmittingArms` backwards-compatibility case.
14091411
let mut missing_ctors = split_set.missing;
1410-
if !place_validity.allows_omitting_empty_arms() {
1412+
if !can_omit_empty_arms {
14111413
missing_ctors.extend(split_set.missing_empty);
14121414
}
14131415

0 commit comments

Comments
 (0)