Auto merge of #115270 - sebastiantoh:issue-105479, r=Nadrieril
Add note on non-exhaustiveness when matching on str and nested non-exhaustive enums Fixes https://github.com/rust-lang/rust/issues/105479 r? `@Nadrieril`
This commit is contained in:
commit
21305f4d5f
11 changed files with 119 additions and 41 deletions
|
@ -720,32 +720,31 @@ fn non_exhaustive_match<'p, 'tcx>(
|
|||
};
|
||||
};
|
||||
|
||||
let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(),
|
||||
ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
|
||||
|
||||
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
|
||||
err.note(format!(
|
||||
"the matched value is of type `{}`{}",
|
||||
scrut_ty,
|
||||
if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
|
||||
));
|
||||
err.note(format!("the matched value is of type `{}`", scrut_ty));
|
||||
|
||||
if !is_empty_match && witnesses.len() == 1 {
|
||||
let mut non_exhaustive_tys = FxHashSet::default();
|
||||
collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
|
||||
|
||||
for ty in non_exhaustive_tys {
|
||||
if ty == cx.tcx.types.usize || ty == cx.tcx.types.isize {
|
||||
if ty.is_ptr_sized_integral() {
|
||||
err.note(format!(
|
||||
"`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
|
||||
exhaustively",
|
||||
));
|
||||
exhaustively",
|
||||
));
|
||||
if cx.tcx.sess.is_nightly_build() {
|
||||
err.help(format!(
|
||||
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
|
||||
enable precise `{ty}` matching",
|
||||
));
|
||||
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
|
||||
enable precise `{ty}` matching",
|
||||
));
|
||||
}
|
||||
} else if ty == cx.tcx.types.str_ {
|
||||
err.note(format!(
|
||||
"`&str` cannot be matched exhaustively, so a wildcard `_` is necessary",
|
||||
));
|
||||
} else if cx.is_foreign_non_exhaustive_enum(ty) {
|
||||
err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -618,10 +618,15 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
|
|||
let new_witnesses = if let Constructor::Missing { .. } = ctor {
|
||||
// We got the special `Missing` constructor, so each of the missing constructors
|
||||
// gives a new pattern that is not caught by the match. We list those patterns.
|
||||
let new_patterns = if pcx.is_non_exhaustive {
|
||||
// Here we don't want the user to try to list all variants, we want them to add
|
||||
// a wildcard, so we only suggest that.
|
||||
vec![DeconstructedPat::wildcard(pcx.ty, pcx.span)]
|
||||
if pcx.is_non_exhaustive {
|
||||
witnesses
|
||||
.into_iter()
|
||||
// Here we don't want the user to try to list all variants, we want them to add
|
||||
// a wildcard, so we only suggest that.
|
||||
.map(|witness| {
|
||||
witness.apply_constructor(pcx, &Constructor::NonExhaustive)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
let mut split_wildcard = SplitWildcard::new(pcx);
|
||||
split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
|
||||
|
@ -633,7 +638,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
|
|||
// constructor, that matches everything that can be built with
|
||||
// it. For example, if `ctor` is a `Constructor::Variant` for
|
||||
// `Option::Some`, we get the pattern `Some(_)`.
|
||||
let mut new: Vec<DeconstructedPat<'_, '_>> = split_wildcard
|
||||
let mut new_patterns: Vec<DeconstructedPat<'_, '_>> = split_wildcard
|
||||
.iter_missing(pcx)
|
||||
.filter_map(|missing_ctor| {
|
||||
// Check if this variant is marked `doc(hidden)`
|
||||
|
@ -648,27 +653,25 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
|
|||
.collect();
|
||||
|
||||
if hide_variant_show_wild {
|
||||
new.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
|
||||
new_patterns.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
|
||||
}
|
||||
|
||||
new
|
||||
};
|
||||
|
||||
witnesses
|
||||
.into_iter()
|
||||
.flat_map(|witness| {
|
||||
new_patterns.iter().map(move |pat| {
|
||||
Witness(
|
||||
witness
|
||||
.0
|
||||
.iter()
|
||||
.chain(once(pat))
|
||||
.map(DeconstructedPat::clone_and_forget_reachability)
|
||||
.collect(),
|
||||
)
|
||||
witnesses
|
||||
.into_iter()
|
||||
.flat_map(|witness| {
|
||||
new_patterns.iter().map(move |pat| {
|
||||
Witness(
|
||||
witness
|
||||
.0
|
||||
.iter()
|
||||
.chain(once(pat))
|
||||
.map(DeconstructedPat::clone_and_forget_reachability)
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
.collect()
|
||||
}
|
||||
} else {
|
||||
witnesses
|
||||
.into_iter()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue