diff options
| author | TheOddGarlic <umutinanerdogan@pm.me> | 2022-08-26 16:38:21 +0300 |
|---|---|---|
| committer | mejrs <> | 2022-12-17 19:08:24 +0100 |
| commit | c7bfd007194a0f4062a8809996b60f2700dd4652 (patch) | |
| tree | 213451b2fa2b392ddd0621fbc4a9baa24ff71e6f | |
| parent | 71a9cb9b7ebc1a4d56f8d837ea8b4b696fae9e89 (diff) | |
| download | rust-c7bfd007194a0f4062a8809996b60f2700dd4652.tar.gz rust-c7bfd007194a0f4062a8809996b60f2700dd4652.zip | |
Migrate "non-exhaustive patterns: type is non-empty" diagnostic
4 files changed, 113 insertions, 7 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 9dab6f8e883..5fb89dcccae 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -175,3 +175,11 @@ mir_build_unused_unsafe = unnecessary `unsafe` block mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn + +mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty + .def_note = `{$peeled_ty}` defined here + .type_note = the matched value is of type `{$ty}` + .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive + .reference_note = references are always considered inhabited + .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index a3e87151226..9e63141d716 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,4 +1,8 @@ +use crate::thir::pattern::MatchCheckCtxt; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::{parse::ParseSess, SessionDiagnostic}; use rustc_span::Span; #[derive(LintDiagnostic)] @@ -336,3 +340,92 @@ pub enum UnusedUnsafeEnclosing { span: Span, }, } + +pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { + pub cx: &'m MatchCheckCtxt<'p, 'tcx>, + pub expr_span: Span, + pub span: Span, + pub ty: Ty<'tcx>, +} + +impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.span_diagnostic.struct_span_err_with_code( + self.span, + rustc_errors::fluent::mir_build::non_exhaustive_patterns_type_not_empty, + error_code!(E0004), + ); + + let peeled_ty = self.ty.peel_refs(); + diag.set_arg("ty", self.ty); + diag.set_arg("peeled_ty", peeled_ty); + + if let ty::Adt(def, _) = peeled_ty.kind() { + let def_span = self + .cx + .tcx + .hir() + .get_if_local(def.did()) + .and_then(|node| node.ident()) + .map(|ident| ident.span) + .unwrap_or_else(|| self.cx.tcx.def_span(def.did())); + + // workaround to make test pass + let mut span: MultiSpan = def_span.into(); + span.push_span_label(def_span, ""); + + diag.span_note(span, rustc_errors::fluent::mir_build::def_note); + } + + let is_variant_list_non_exhaustive = match self.ty.kind() { + ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => { + true + } + _ => false, + }; + + if is_variant_list_non_exhaustive { + diag.note(rustc_errors::fluent::mir_build::non_exhaustive_type_note); + } else { + diag.note(rustc_errors::fluent::mir_build::type_note); + } + + if let ty::Ref(_, sub_ty, _) = self.ty.kind() { + if self.cx.tcx.is_ty_uninhabited_from(self.cx.module, *sub_ty, self.cx.param_env) { + diag.note(rustc_errors::fluent::mir_build::reference_note); + } + } + + let mut suggestion = None; + let sm = self.cx.tcx.sess.source_map(); + if self.span.eq_ctxt(self.expr_span) { + // Get the span for the empty match body `{}`. + let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) { + (format!("\n{}", snippet), " ") + } else { + (" ".to_string(), "") + }; + suggestion = Some(( + self.span.shrink_to_hi().with_hi(self.expr_span.hi()), + format!( + " {{{indentation}{more}_ => todo!(),{indentation}}}", + indentation = indentation, + more = more, + ), + )); + } + + if let Some((span, sugg)) = suggestion { + diag.span_suggestion_verbose( + span, + rustc_errors::fluent::mir_build::suggestion, + sugg, + Applicability::HasPlaceholders, + ); + } else { + diag.help(rustc_errors::fluent::mir_build::help); + } + + diag + } +} 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 e369dba5524..c818a2a3a89 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -4,6 +4,8 @@ use super::usefulness::{ }; use super::{PatCtxt, PatternError}; +use crate::errors::NonExhaustivePatternsTypeNotEmpty; + use rustc_arena::TypedArena; use rustc_ast::Mutability; use rustc_errors::{ @@ -760,15 +762,17 @@ fn non_exhaustive_match<'p, 'tcx>( // informative. let mut err; let pattern; - let mut patterns_len = 0; + let patterns_len; if is_empty_match && !non_empty_enum { - err = create_e0004( - cx.tcx.sess, - sp, - format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty), - ); - pattern = "_".to_string(); + cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty { + cx, + expr_span, + span: sp, + ty: scrut_ty, + }); + return; } else { + // FIXME: migration of this diagnostic will require list support let joined_patterns = joined_uncovered_patterns(cx, &witnesses); err = create_e0004( cx.tcx.sess, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 48a231a6cd6..5aaf6c907e3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -6,6 +6,7 @@ mod deconstruct_pat; mod usefulness; pub(crate) use self::check_match::check_match; +pub(crate) use self::usefulness::MatchCheckCtxt; use crate::thir::util::UserAnnotatedTyHelpers; |
