summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src/thir/pattern/check_match.rs')
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs58
1 files changed, 36 insertions, 22 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 383e80851..d440ca319 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -7,6 +7,7 @@ use crate::errors::*;
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
@@ -660,6 +661,17 @@ fn report_arm_reachability<'p, 'tcx>(
}
}
+fn collect_non_exhaustive_tys<'p, 'tcx>(
+ pat: &DeconstructedPat<'p, 'tcx>,
+ non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
+) {
+ if matches!(pat.ctor(), Constructor::NonExhaustive) {
+ non_exhaustive_tys.insert(pat.ty());
+ }
+ pat.iter_fields()
+ .for_each(|field_pat| collect_non_exhaustive_tys(field_pat, non_exhaustive_tys))
+}
+
/// Report that a match is not exhaustive.
fn non_exhaustive_match<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
@@ -708,31 +720,33 @@ 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 { "" }
- ));
- if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize)
- && !is_empty_match
- && witnesses.len() == 1
- && matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
- {
- err.note(format!(
- "`{scrut_ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
- exhaustively",
- ));
- if cx.tcx.sess.is_nightly_build() {
- err.help(format!(
- "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
- enable precise `{scrut_ty}` matching",
- ));
+ 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.is_ptr_sized_integral() {
+ err.note(format!(
+ "`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
+ 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",
+ ));
+ }
+ } else if ty == cx.tcx.types.str_ {
+ err.note("`&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"));
+ }
}
}
+
if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) {
err.note("references are always considered inhabited");