Skip to content

Commit 53e03fb

Browse files
committed
Make the special "missing patterns" constructor real
1 parent 2a541ce commit 53e03fb

File tree

2 files changed

+57
-64
lines changed

2 files changed

+57
-64
lines changed

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

+46-62
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,9 @@ pub(super) enum Constructor<'tcx> {
607607
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used
608608
/// for those types for which we cannot list constructors explicitly, like `f64` and `str`.
609609
NonExhaustive,
610+
/// Stands for constructors that are not seen in the matrix, as explained in the documentation
611+
/// for [`SplitWildcard`].
612+
Missing,
610613
/// Wildcard pattern.
611614
Wildcard,
612615
}
@@ -758,8 +761,8 @@ impl<'tcx> Constructor<'tcx> {
758761
match (self, other) {
759762
// Wildcards cover anything
760763
(_, Wildcard) => true,
761-
// Wildcards are only covered by wildcards
762-
(Wildcard, _) => false,
764+
// The missing ctors are not covered by anything in the matrix except wildcards.
765+
(Missing | Wildcard, _) => false,
763766

764767
(Single, Single) => true,
765768
(Variant(self_id), Variant(other_id)) => self_id == other_id,
@@ -832,7 +835,7 @@ impl<'tcx> Constructor<'tcx> {
832835
.any(|other| slice.is_covered_by(other)),
833836
// This constructor is never covered by anything else
834837
NonExhaustive => false,
835-
Str(..) | FloatRange(..) | Opaque | Wildcard => {
838+
Str(..) | FloatRange(..) | Opaque | Missing | Wildcard => {
836839
span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
837840
}
838841
}
@@ -1002,7 +1005,7 @@ impl<'tcx> SplitWildcard<'tcx> {
10021005
}
10031006

10041007
/// Iterate over the constructors for this type that are not present in the matrix.
1005-
fn iter_missing<'a, 'p>(
1008+
pub(super) fn iter_missing<'a, 'p>(
10061009
&'a self,
10071010
pcx: PatCtxt<'a, 'p, 'tcx>,
10081011
) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
@@ -1013,64 +1016,45 @@ impl<'tcx> SplitWildcard<'tcx> {
10131016
/// top of the file, if any constructors are missing we can ignore the present ones.
10141017
fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
10151018
if self.any_missing(pcx) {
1016-
// Some constructors are missing, thus we can specialize with the wildcard constructor,
1017-
// which will stand for those constructors that are missing, and matches the same rows
1018-
// as any of them (namely the wildcard rows).
1019-
return smallvec![Wildcard];
1019+
// Some constructors are missing, thus we can specialize with the special `Missing`
1020+
// constructor, which stands for those constructors that are not seen in the matrix,
1021+
// and matches the same rows as any of them (namely the wildcard rows). See the top of
1022+
// the file for details.
1023+
// However, when all constructors are missing we can also specialize with the full
1024+
// `Wildcard` constructor. The difference will depend on what we want in diagnostics.
1025+
1026+
// If some constructors are missing, we typically want to report those constructors,
1027+
// e.g.:
1028+
// ```
1029+
// enum Direction { N, S, E, W }
1030+
// let Direction::N = ...;
1031+
// ```
1032+
// we can report 3 witnesses: `S`, `E`, and `W`.
1033+
//
1034+
// However, if the user didn't actually specify a constructor
1035+
// in this arm, e.g., in
1036+
// ```
1037+
// let x: (Direction, Direction, bool) = ...;
1038+
// let (_, _, false) = x;
1039+
// ```
1040+
// we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>,
1041+
// true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we
1042+
// prefer to report just a wildcard `_`.
1043+
//
1044+
// The exception is: if we are at the top-level, for example in an empty match, we
1045+
// sometimes prefer reporting the list of constructors instead of just `_`.
1046+
let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
1047+
let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing {
1048+
Missing
1049+
} else {
1050+
Wildcard
1051+
};
1052+
return smallvec![ctor];
10201053
}
10211054

10221055
// All the constructors are present in the matrix, so we just go through them all.
10231056
self.all_ctors
10241057
}
1025-
1026-
/// List the patterns corresponding to the missing constructors. In some cases, instead of
1027-
/// listing all constructors of a given type, we prefer to simply report a wildcard.
1028-
pub(super) fn report_missing_patterns<'p>(
1029-
&self,
1030-
pcx: PatCtxt<'_, 'p, 'tcx>,
1031-
) -> SmallVec<[Pat<'tcx>; 1]> {
1032-
// There are 2 ways we can report a witness here.
1033-
// Commonly, we can report all the "free"
1034-
// constructors as witnesses, e.g., if we have:
1035-
//
1036-
// ```
1037-
// enum Direction { N, S, E, W }
1038-
// let Direction::N = ...;
1039-
// ```
1040-
//
1041-
// we can report 3 witnesses: `S`, `E`, and `W`.
1042-
//
1043-
// However, there is a case where we don't want
1044-
// to do this and instead report a single `_` witness:
1045-
// if the user didn't actually specify a constructor
1046-
// in this arm, e.g., in
1047-
//
1048-
// ```
1049-
// let x: (Direction, Direction, bool) = ...;
1050-
// let (_, _, false) = x;
1051-
// ```
1052-
//
1053-
// we don't want to show all 16 possible witnesses
1054-
// `(<direction-1>, <direction-2>, true)` - we are
1055-
// satisfied with `(_, _, true)`. In this case,
1056-
// `used_ctors` is empty.
1057-
// The exception is: if we are at the top-level, for example in an empty match, we
1058-
// sometimes prefer reporting the list of constructors instead of just `_`.
1059-
let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty);
1060-
if self.matrix_ctors.is_empty() && !report_when_all_missing {
1061-
// All constructors are unused. Report only a wildcard
1062-
// rather than each individual constructor.
1063-
smallvec![Pat::wildcard_from_ty(pcx.ty)]
1064-
} else {
1065-
// Construct for each missing constructor a "wild" version of this
1066-
// constructor, that matches everything that can be built with
1067-
// it. For example, if `ctor` is a `Constructor::Variant` for
1068-
// `Option::Some`, we get the pattern `Some(_)`.
1069-
self.iter_missing(pcx)
1070-
.map(|missing_ctor| Fields::wildcards(pcx, &missing_ctor).apply(pcx, missing_ctor))
1071-
.collect()
1072-
}
1073-
}
10741058
}
10751059

10761060
/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
@@ -1211,9 +1195,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12111195
}
12121196
_ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
12131197
},
1214-
Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Wildcard => {
1215-
Fields::empty()
1216-
}
1198+
Str(..) | FloatRange(..) | IntRange(..) | NonExhaustive | Opaque | Missing
1199+
| Wildcard => Fields::empty(),
12171200
};
12181201
debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
12191202
ret
@@ -1297,9 +1280,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12971280
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
12981281
IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty),
12991282
NonExhaustive => PatKind::Wild,
1283+
Wildcard => return Pat::wildcard_from_ty(pcx.ty),
13001284
Opaque => bug!("we should not try to apply an opaque constructor"),
1301-
Wildcard => bug!(
1302-
"trying to apply a wildcard constructor; this should have been done in `apply_constructors`"
1285+
Missing => bug!(
1286+
"trying to apply the `Missing` constructor; this should have been done in `apply_constructors`"
13031287
),
13041288
};
13051289

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

+11-2
Original file line numberDiff line numberDiff line change
@@ -784,10 +784,19 @@ impl<'tcx> Usefulness<'tcx> {
784784
) -> Self {
785785
match self {
786786
UsefulWithWitness(witnesses) => {
787-
let new_witnesses = if ctor.is_wildcard() {
787+
let new_witnesses = if matches!(ctor, Constructor::Missing) {
788788
let mut split_wildcard = SplitWildcard::new(pcx);
789789
split_wildcard.split(pcx, matrix.head_ctors(pcx.cx));
790-
let new_patterns = split_wildcard.report_missing_patterns(pcx);
790+
// Construct for each missing constructor a "wild" version of this
791+
// constructor, that matches everything that can be built with
792+
// it. For example, if `ctor` is a `Constructor::Variant` for
793+
// `Option::Some`, we get the pattern `Some(_)`.
794+
let new_patterns: Vec<_> = split_wildcard
795+
.iter_missing(pcx)
796+
.map(|missing_ctor| {
797+
Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor)
798+
})
799+
.collect();
791800
witnesses
792801
.into_iter()
793802
.flat_map(|witness| {

0 commit comments

Comments
 (0)