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 aacaafeede695..a082c0b61fa7e 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -303,3 +303,64 @@ mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once a .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here .moved = also moved into `{$name_moved}` here + +mir_build_union_pattern = cannot use unions in constant patterns + +mir_build_type_not_structural = + to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + +mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns + +mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns + +mir_build_float_pattern = floating-point types cannot be used in patterns + +mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + +mir_build_indirect_structural_match = + to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + +mir_build_nontrivial_structural_match = + to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]` + +mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints + .range = ... with this range + .note = you likely meant to write mutually exclusive ranges + +mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly + .help = ensure that all variants are matched explicitly by adding the suggested match arms + .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found + +mir_build_uncovered = {$count -> + [1] pattern `{$witness_1}` + [2] patterns `{$witness_1}` and `{$witness_2}` + [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}` + *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more + } not covered + +mir_build_pattern_not_covered = refutable pattern in {$origin} + .pattern_ty = the matched value is of type `{$pattern_ty}` + +mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + +mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html + +mir_build_res_defined_here = {$res} defined here + +mir_build_adt_defined_here = `{$ty}` defined here + +mir_build_variant_defined_here = not covered + +mir_build_interpreted_as_const = introduce a variable instead + +mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable + +mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count -> + [one] variant that isn't + *[other] variants that aren't + } matched + +mir_build_suggest_let_else = you might want to use `let else` to handle the {$count -> + [one] variant that isn't + *[other] variants that aren't + } matched diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index ac903010c8d31..5f320708c8416 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -9,6 +9,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::RangeEnd; @@ -575,6 +576,12 @@ impl<'tcx> Pat<'tcx> { } } +impl<'tcx> IntoDiagnosticArg for Pat<'tcx> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + format!("{}", self).into_diagnostic_arg() + } +} + #[derive(Clone, Debug, HashStable)] pub struct Ascription<'tcx> { pub annotation: CanonicalUserTypeAnnotation<'tcx>, diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 233eecbd5b4ec..06523b0a1de84 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,9 +1,13 @@ +use crate::thir::pattern::deconstruct_pat::DeconstructedPat; use crate::thir::pattern::MatchCheckCtxt; use rustc_errors::Handler; use rustc_errors::{ - error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, + error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + IntoDiagnostic, MultiSpan, SubdiagnosticMessage, }; +use rustc_hir::def::Res; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_middle::thir::Pat; use rustc_middle::ty::{self, Ty}; use rustc_span::{symbol::Ident, Span}; @@ -624,3 +628,223 @@ pub enum MultipleMutBorrowOccurence { name_moved: Ident, }, } + +#[derive(Diagnostic)] +#[diag(mir_build_union_pattern)] +pub struct UnionPattern { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(mir_build_type_not_structural)] +pub struct TypeNotStructural<'tcx> { + #[primary_span] + pub span: Span, + pub non_sm_ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_invalid_pattern)] +pub struct InvalidPattern<'tcx> { + #[primary_span] + pub span: Span, + pub non_sm_ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(mir_build_unsized_pattern)] +pub struct UnsizedPattern<'tcx> { + #[primary_span] + pub span: Span, + pub non_sm_ty: Ty<'tcx>, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build_float_pattern)] +pub struct FloatPattern; + +#[derive(LintDiagnostic)] +#[diag(mir_build_pointer_pattern)] +pub struct PointerPattern; + +#[derive(LintDiagnostic)] +#[diag(mir_build_indirect_structural_match)] +pub struct IndirectStructuralMatch<'tcx> { + pub non_sm_ty: Ty<'tcx>, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build_nontrivial_structural_match)] +pub struct NontrivialStructuralMatch<'tcx> { + pub non_sm_ty: Ty<'tcx>, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build_overlapping_range_endpoints)] +#[note] +pub struct OverlappingRangeEndpoints<'tcx> { + #[label(range)] + pub range: Span, + #[subdiagnostic] + pub overlap: Vec>, +} + +pub struct Overlap<'tcx> { + pub span: Span, + pub range: Pat<'tcx>, +} + +impl<'tcx> AddToDiagnostic for Overlap<'tcx> { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + let Overlap { span, range } = self; + + // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]` + // does not support `#[subdiagnostic(eager)]`... + let message = format!("this range overlaps on `{range}`..."); + diag.span_label(span, message); + } +} + +#[derive(LintDiagnostic)] +#[diag(mir_build_non_exhaustive_omitted_pattern)] +#[help] +#[note] +pub(crate) struct NonExhaustiveOmittedPattern<'tcx> { + pub scrut_ty: Ty<'tcx>, + #[subdiagnostic] + pub uncovered: Uncovered<'tcx>, +} + +#[derive(Subdiagnostic)] +#[label(mir_build_uncovered)] +pub(crate) struct Uncovered<'tcx> { + #[primary_span] + span: Span, + count: usize, + witness_1: Pat<'tcx>, + witness_2: Pat<'tcx>, + witness_3: Pat<'tcx>, + remainder: usize, +} + +impl<'tcx> Uncovered<'tcx> { + pub fn new<'p>( + span: Span, + cx: &MatchCheckCtxt<'p, 'tcx>, + witnesses: Vec>, + ) -> Self { + let witness_1 = witnesses.get(0).unwrap().to_pat(cx); + Self { + span, + count: witnesses.len(), + // Substitute dummy values if witnesses is smaller than 3. These will never be read. + witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()), + witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()), + witness_1, + remainder: witnesses.len().saturating_sub(3), + } + } +} + +#[derive(Diagnostic)] +#[diag(mir_build_pattern_not_covered, code = "E0005")] +pub(crate) struct PatternNotCovered<'s, 'tcx> { + #[primary_span] + pub span: Span, + pub origin: &'s str, + #[subdiagnostic] + pub uncovered: Uncovered<'tcx>, + #[subdiagnostic] + pub inform: Option, + #[subdiagnostic] + pub interpreted_as_const: Option, + #[subdiagnostic] + pub adt_defined_here: Option>, + #[note(pattern_ty)] + pub _p: (), + pub pattern_ty: Ty<'tcx>, + #[subdiagnostic] + pub let_suggestion: Option, + #[subdiagnostic] + pub res_defined_here: Option, +} + +#[derive(Subdiagnostic)] +#[note(mir_build_inform_irrefutable)] +#[note(mir_build_more_information)] +pub struct Inform; + +pub struct AdtDefinedHere<'tcx> { + pub adt_def_span: Span, + pub ty: Ty<'tcx>, + pub variants: Vec, +} + +pub struct Variant { + pub span: Span, +} + +impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { + diag.set_arg("ty", self.ty); + let mut spans = MultiSpan::from(self.adt_def_span); + + for Variant { span } in self.variants { + spans.push_span_label(span, rustc_errors::fluent::mir_build_variant_defined_here); + } + + diag.span_note(spans, rustc_errors::fluent::mir_build_adt_defined_here); + } +} + +#[derive(Subdiagnostic)] +#[label(mir_build_res_defined_here)] +pub struct ResDefinedHere { + #[primary_span] + pub def_span: Span, + pub res: Res, +} + +#[derive(Subdiagnostic)] +#[suggestion( + mir_build_interpreted_as_const, + code = "{variable}_var", + applicability = "maybe-incorrect" +)] +#[label(mir_build_confused)] +pub struct InterpretedAsConst { + #[primary_span] + pub span: Span, + pub article: &'static str, + pub variable: String, + pub res: Res, +} + +#[derive(Subdiagnostic)] +pub enum SuggestLet { + #[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")] + If { + #[suggestion_part(code = "if ")] + start_span: Span, + #[suggestion_part(code = " {{ todo!() }}")] + semi_span: Span, + count: usize, + }, + #[suggestion( + mir_build_suggest_let_else, + code = " else {{ todo!() }}", + applicability = "has-placeholders" + )] + Else { + #[primary_span] + end_span: Span, + count: usize, + }, +} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 2b05e92fdcf20..fb7ae6f1d2424 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -10,6 +10,7 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(once_cell)] +#![feature(try_blocks)] #![recursion_limit = "256"] #[macro_use] 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 e7ee0d9e908e0..e13c0662ef85f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -9,8 +9,7 @@ use crate::errors::*; use rustc_arena::TypedArena; use rustc_ast::Mutability; use rustc_errors::{ - pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, + struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::*; @@ -378,8 +377,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let pattern = self.lower_pattern(&mut cx, pat, &mut false); let pattern_ty = pattern.ty(); - let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }]; - let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty); + let arm = MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }; + let report = compute_match_usefulness(&cx, &[arm], pat.hir_id, pattern_ty); // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We // only care about exhaustiveness here. @@ -390,145 +389,73 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { return; } - let joined_patterns = joined_uncovered_patterns(&cx, &witnesses); - - let mut bindings = vec![]; - - let mut err = struct_span_err!( - self.tcx.sess, - pat.span, - E0005, - "refutable pattern in {}: {} not covered", - origin, - joined_patterns - ); - let suggest_if_let = match &pat.kind { - hir::PatKind::Path(hir::QPath::Resolved(None, path)) - if path.segments.len() == 1 && path.segments[0].args.is_none() => + let (inform, interpreted_as_const, res_defined_here,let_suggestion) = + if let hir::PatKind::Path(hir::QPath::Resolved( + None, + hir::Path { + segments: &[hir::PathSegment { args: None, res, ident, .. }], + .. + }, + )) = &pat.kind { - const_not_var(&mut err, cx.tcx, pat, path); - false - } - _ => { - pat.walk(&mut |pat: &hir::Pat<'_>| { - match pat.kind { - hir::PatKind::Binding(_, _, ident, _) => { - bindings.push(ident); + ( + None, + Some(InterpretedAsConst { + span: pat.span, + article: res.article(), + variable: ident.to_string().to_lowercase(), + res, + }), + try { + ResDefinedHere { + def_span: cx.tcx.hir().res_span(res)?, + res, } - _ => {} + }, + None, + ) + } else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) { + let mut bindings = vec![]; + pat.walk_always(&mut |pat: &hir::Pat<'_>| { + if let hir::PatKind::Binding(_, _, ident, _) = pat.kind { + bindings.push(ident); } - true }); - - err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns)); - true - } - }; - - if let (Some(span), true) = (sp, suggest_if_let) { - err.note( - "`let` bindings require an \"irrefutable pattern\", like a `struct` or \ - an `enum` with only one variant", - ); - if self.tcx.sess.source_map().is_span_accessible(span) { let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1)); let start_span = span.shrink_to_lo(); let end_span = semi_span.shrink_to_lo(); - err.multipart_suggestion( - &format!( - "you might want to use `if let` to ignore the variant{} that {} matched", - pluralize!(witnesses.len()), - match witnesses.len() { - 1 => "isn't", - _ => "aren't", - }, - ), - vec![ - match &bindings[..] { - [] => (start_span, "if ".to_string()), - [binding] => (start_span, format!("let {} = if ", binding)), - bindings => ( - start_span, - format!( - "let ({}) = if ", - bindings - .iter() - .map(|ident| ident.to_string()) - .collect::>() - .join(", ") - ), - ), - }, - match &bindings[..] { - [] => (semi_span, " { todo!() }".to_string()), - [binding] => { - (end_span, format!(" {{ {} }} else {{ todo!() }}", binding)) - } - bindings => ( - end_span, - format!( - " {{ ({}) }} else {{ todo!() }}", - bindings - .iter() - .map(|ident| ident.to_string()) - .collect::>() - .join(", ") - ), - ), - }, - ], - Applicability::HasPlaceholders, - ); - if !bindings.is_empty() { - err.span_suggestion_verbose( - semi_span.shrink_to_lo(), - &format!( - "alternatively, you might want to use \ - let else to handle the variant{} that {} matched", - pluralize!(witnesses.len()), - match witnesses.len() { - 1 => "isn't", - _ => "aren't", - }, - ), - " else { todo!() }", - Applicability::HasPlaceholders, - ); - } - } - err.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch18-02-refutability.html", - ); - } + let count = witnesses.len(); - adt_defined_here(&cx, &mut err, pattern_ty, &witnesses); - err.note(&format!("the matched value is of type `{}`", pattern_ty)); - err.emit(); - } -} + let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }}; + (sp.map(|_|Inform), None, None, Some(let_suggestion)) + } else{ + (sp.map(|_|Inform), None, None, None) + }; -/// A path pattern was interpreted as a constant, not a new variable. -/// This caused an irrefutable match failure in e.g. `let`. -fn const_not_var(err: &mut Diagnostic, tcx: TyCtxt<'_>, pat: &Pat<'_>, path: &hir::Path<'_>) { - let descr = path.res.descr(); - err.span_label( - pat.span, - format!("interpreted as {} {} pattern, not a new variable", path.res.article(), descr,), - ); + let adt_defined_here = try { + let ty = pattern_ty.peel_refs(); + let ty::Adt(def, _) = ty.kind() else { None? }; + let adt_def_span = cx.tcx.hir().get_if_local(def.did())?.ident()?.span; + let mut variants = vec![]; - err.span_suggestion( - pat.span, - "introduce a variable instead", - format!("{}_var", path.segments[0].ident).to_lowercase(), - // Cannot use `MachineApplicable` as it's not really *always* correct - // because there may be such an identifier in scope or the user maybe - // really wanted to match against the constant. This is quite unlikely however. - Applicability::MaybeIncorrect, - ); + for span in maybe_point_at_variant(&cx, *def, witnesses.iter().take(5)) { + variants.push(Variant { span }); + } + AdtDefinedHere { adt_def_span, ty, variants } + }; - if let Some(span) = tcx.hir().res_span(path.res) { - err.span_label(span, format!("{} defined here", descr)); + self.tcx.sess.emit_err(PatternNotCovered { + span: pat.span, + origin, + uncovered: Uncovered::new(pat.span, &cx, witnesses), + inform, + interpreted_as_const, + _p: (), + pattern_ty, + let_suggestion, + res_defined_here, + adt_defined_here, + }); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6470efab2e93c..7f3519945c3fe 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -1,11 +1,9 @@ -use rustc_errors::DelayDm; use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::{self, Field}; use rustc_middle::thir::{FieldPat, Pat, PatKind}; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::Span; use rustc_trait_selection::traits::predicate_for_trait_def; @@ -15,6 +13,10 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; use std::cell::Cell; use super::PatCtxt; +use crate::errors::{ + FloatPattern, IndirectStructuralMatch, InvalidPattern, NontrivialStructuralMatch, + PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern, +}; impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts an evaluated constant to a pattern (if possible). @@ -105,47 +107,6 @@ impl<'tcx> ConstToPat<'tcx> { self.infcx.tcx } - fn adt_derive_msg(&self, adt_def: AdtDef<'tcx>) -> String { - let path = self.tcx().def_path_str(adt_def.did()); - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ) - } - - fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { - traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| { - with_no_trimmed_paths!(match non_sm_ty.kind() { - ty::Adt(adt, _) => self.adt_derive_msg(*adt), - ty::Dynamic(..) => { - "trait objects cannot be used in patterns".to_string() - } - ty::Alias(ty::Opaque, ..) => { - "opaque types cannot be used in patterns".to_string() - } - ty::Closure(..) => { - "closures cannot be used in patterns".to_string() - } - ty::Generator(..) | ty::GeneratorWitness(..) => { - "generators cannot be used in patterns".to_string() - } - ty::Float(..) => { - "floating-point numbers cannot be used in patterns".to_string() - } - ty::FnPtr(..) => { - "function pointers cannot be used in patterns".to_string() - } - ty::RawPtr(..) => { - "raw pointers cannot be used in patterns".to_string() - } - _ => { - bug!("use of a value of `{non_sm_ty}` inside a pattern") - } - }) - }) - } - fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { ty.is_structural_eq_shallow(self.infcx.tcx) } @@ -176,7 +137,8 @@ impl<'tcx> ConstToPat<'tcx> { // If we were able to successfully convert the const to some pat, // double-check that all types in the const implement `Structural`. - let structural = self.search_for_structural_match_violation(cv.ty()); + let structural = + traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty()); debug!( "search_for_structural_match_violation cv.ty: {:?} returned: {:?}", cv.ty(), @@ -194,17 +156,18 @@ impl<'tcx> ConstToPat<'tcx> { return inlined_const_as_pat; } - if let Some(msg) = structural { + if let Some(non_sm_ty) = structural { if !self.type_may_have_partial_eq_impl(cv.ty()) { - // span_fatal avoids ICE from resolution of non-existent method (rare case). - self.tcx().sess.span_fatal(self.span, &msg); + // fatal avoids ICE from resolution of non-existent method (rare case). + self.tcx() + .sess + .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty: non_sm_ty }); } else if mir_structural_match_violation && !self.saw_const_match_lint.get() { - self.tcx().struct_span_lint_hir( + self.tcx().emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, self.span, - msg, - |lint| lint, + IndirectStructuralMatch { non_sm_ty }, ); } else { debug!( @@ -278,12 +241,11 @@ impl<'tcx> ConstToPat<'tcx> { let kind = match cv.ty().kind() { ty::Float(_) => { if self.include_lint_checks { - tcx.struct_span_lint_hir( + tcx.emit_spanned_lint( lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, id, span, - "floating-point types cannot be used in patterns", - |lint| lint, + FloatPattern, ); } PatKind::Constant { value: cv } @@ -291,29 +253,22 @@ impl<'tcx> ConstToPat<'tcx> { ty::Adt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants self.saw_const_match_error.set(true); - let msg = "cannot use unions in constant patterns"; - if self.include_lint_checks { - tcx.sess.span_err(span, msg); - } else { - tcx.sess.delay_span_bug(span, msg); - } + let err = UnionPattern { span }; + tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); PatKind::Wild } ty::Adt(..) if !self.type_may_have_partial_eq_impl(cv.ty()) // FIXME(#73448): Find a way to bring const qualification into parity with // `search_for_structural_match_violation` and then remove this condition. - && self.search_for_structural_match_violation(cv.ty()).is_some() => + + // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we + // could get `Option`, even though `Option` is annotated with derive. + && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty()) => { - // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we - // could get `Option`, even though `Option` is annotated with derive. - let msg = self.search_for_structural_match_violation(cv.ty()).unwrap(); self.saw_const_match_error.set(true); - if self.include_lint_checks { - tcx.sess.span_err(self.span, &msg); - } else { - tcx.sess.delay_span_bug(self.span, &msg); - } + let err = TypeNotStructural { span, non_sm_ty }; + tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); PatKind::Wild } // If the type is not structurally comparable, just emit the constant directly, @@ -331,19 +286,11 @@ impl<'tcx> ConstToPat<'tcx> { && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); - tcx.struct_span_lint_hir( + tcx.emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, id, span, - DelayDm(|| { - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - cv.ty(), - cv.ty(), - ) - }), - |lint| lint, + IndirectStructuralMatch { non_sm_ty: cv.ty() }, ); } // Since we are behind a reference, we can just bubble the error up so we get a @@ -357,18 +304,9 @@ impl<'tcx> ConstToPat<'tcx> { adt_def, cv.ty() ); - let path = tcx.def_path_str(adt_def.did()); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); self.saw_const_match_error.set(true); - if self.include_lint_checks { - tcx.sess.span_err(span, &msg); - } else { - tcx.sess.delay_span_bug(span, &msg); - } + let err = TypeNotStructural { span, non_sm_ty: cv.ty() }; + tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); PatKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { @@ -401,12 +339,8 @@ impl<'tcx> ConstToPat<'tcx> { // These are not allowed and will error elsewhere anyway. ty::Dynamic(..) => { self.saw_const_match_error.set(true); - let msg = format!("`{}` cannot be used in patterns", cv.ty()); - if self.include_lint_checks { - tcx.sess.span_err(span, &msg); - } else { - tcx.sess.delay_span_bug(span, &msg); - } + let err = InvalidPattern { span, non_sm_ty: cv.ty() }; + tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); PatKind::Wild } // `&str` is represented as `ConstValue::Slice`, let's keep using this @@ -471,32 +405,26 @@ impl<'tcx> ConstToPat<'tcx> { // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a // reference. This makes the rest of the matching logic simpler as it doesn't have // to figure out how to get a reference again. - ty::Adt(adt_def, _) if !self.type_marked_structural(*pointee_ty) => { + ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { if self.include_lint_checks && !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { - self.saw_const_match_lint.set(true); - let msg = self.adt_derive_msg(adt_def); - self.tcx().struct_span_lint_hir( + self.saw_const_match_lint.set(true); + tcx.emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, - self.span, - msg, - |lint| lint, + span, + IndirectStructuralMatch { non_sm_ty: *pointee_ty }, ); } PatKind::Constant { value: cv } } else { if !self.saw_const_match_error.get() { self.saw_const_match_error.set(true); - let msg = self.adt_derive_msg(adt_def); - if self.include_lint_checks { - tcx.sess.span_err(span, &msg); - } else { - tcx.sess.delay_span_bug(span, &msg); - } + let err = TypeNotStructural { span, non_sm_ty: *pointee_ty }; + tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); } PatKind::Wild } @@ -508,12 +436,10 @@ impl<'tcx> ConstToPat<'tcx> { if !pointee_ty.is_sized(tcx, param_env) { // `tcx.deref_mir_constant()` below will ICE with an unsized type // (except slices, which are handled in a separate arm above). - let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty); - if self.include_lint_checks { - tcx.sess.span_err(span, &msg); - } else { - tcx.sess.delay_span_bug(span, &msg); - } + + let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; + tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); + PatKind::Wild } else { let old = self.behind_reference.replace(true); @@ -545,27 +471,19 @@ impl<'tcx> ConstToPat<'tcx> { && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); - let msg = "function pointers and unsized pointers in patterns behave \ - unpredictably and should not be relied upon. \ - See https://github.com/rust-lang/rust/issues/70861 for details."; - tcx.struct_span_lint_hir( + tcx.emit_spanned_lint( lint::builtin::POINTER_STRUCTURAL_MATCH, id, span, - msg, - |lint| lint, + PointerPattern ); } PatKind::Constant { value: cv } } _ => { self.saw_const_match_error.set(true); - let msg = format!("`{}` cannot be used in patterns", cv.ty()); - if self.include_lint_checks { - tcx.sess.span_err(span, &msg); - } else { - tcx.sess.delay_span_bug(span, &msg); - } + let err = InvalidPattern { span, non_sm_ty: cv.ty() }; + tcx.sess.create_err(err).emit_unless(!self.include_lint_checks); PatKind::Wild } }; @@ -576,21 +494,17 @@ impl<'tcx> ConstToPat<'tcx> { && mir_structural_match_violation // FIXME(#73448): Find a way to bring const qualification into parity with // `search_for_structural_match_violation` and then remove this condition. - && self.search_for_structural_match_violation(cv.ty()).is_some() - { - self.saw_const_match_lint.set(true); + // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we // could get `Option`, even though `Option` is annotated with derive. - let msg = self.search_for_structural_match_violation(cv.ty()).unwrap().replace( - "in a pattern,", - "in a pattern, the constant's initializer must be trivial or", - ); - tcx.struct_span_lint_hir( + && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty()) + { + self.saw_const_match_lint.set(true); + tcx.emit_spanned_lint( lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, id, span, - msg, - |lint| lint, + NontrivialStructuralMatch {non_sm_ty} ); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index a95349d767098..17b3c475f83c7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -67,6 +67,7 @@ use self::SliceKind::*; use super::compare_const_vals; use super::usefulness::{MatchCheckCtxt, PatCtxt}; +use crate::errors::{Overlap, OverlappingRangeEndpoints}; /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { @@ -96,7 +97,7 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { /// `IntRange` is never used to encode an empty range or a "range" that wraps /// around the (offset) space: i.e., `range.lo <= range.hi`. #[derive(Clone, PartialEq, Eq)] -pub(super) struct IntRange { +pub(crate) struct IntRange { range: RangeInclusive, /// Keeps the bias used for encoding the range. It depends on the type of the range and /// possibly the pointer size of the current architecture. The algorithm ensures we never @@ -284,32 +285,21 @@ impl IntRange { return; } - let overlaps: Vec<_> = pats + let overlap: Vec<_> = pats .filter_map(|pat| Some((pat.ctor().as_int_range()?, pat.span()))) .filter(|(range, _)| self.suspicious_intersection(range)) - .map(|(range, span)| (self.intersection(&range).unwrap(), span)) + .map(|(range, span)| Overlap { + range: self.intersection(&range).unwrap().to_pat(pcx.cx.tcx, pcx.ty), + span, + }) .collect(); - if !overlaps.is_empty() { - pcx.cx.tcx.struct_span_lint_hir( + if !overlap.is_empty() { + pcx.cx.tcx.emit_spanned_lint( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, hir_id, pcx.span, - "multiple patterns overlap on their endpoints", - |lint| { - for (int_range, span) in overlaps { - lint.span_label( - span, - &format!( - "this range overlaps on `{}`...", - int_range.to_pat(pcx.cx.tcx, pcx.ty) - ), - ); - } - lint.span_label(pcx.span, "... with this range"); - lint.note("you likely meant to write mutually exclusive ranges"); - lint - }, + OverlappingRangeEndpoints { overlap, range: pcx.span }, ); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 7d4353c52926d..3a6ef87c9c662 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -2,7 +2,7 @@ mod check_match; mod const_to_pat; -mod deconstruct_pat; +pub(crate) mod deconstruct_pat; mod usefulness; pub(crate) use self::check_match::check_match; diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 8f80cb95e58e7..be66d0d476513 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -291,9 +291,8 @@ use self::ArmType::*; use self::Usefulness::*; - -use super::check_match::{joined_uncovered_patterns, pattern_not_covered_label}; use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; +use crate::errors::{NonExhaustiveOmittedPattern, Uncovered}; use rustc_data_structures::captures::Captures; @@ -743,31 +742,6 @@ impl<'p, 'tcx> Witness<'p, 'tcx> { } } -/// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` -/// is not exhaustive enough. -/// -/// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. -fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( - cx: &MatchCheckCtxt<'p, 'tcx>, - scrut_ty: Ty<'tcx>, - sp: Span, - hir_id: HirId, - witnesses: Vec>, -) { - cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| { - let joined_patterns = joined_uncovered_patterns(cx, &witnesses); - lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); - lint.help( - "ensure that all variants are matched explicitly by adding the suggested match arms", - ); - lint.note(&format!( - "the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found", - scrut_ty, - )); - lint - }); -} - /// Algorithm from . /// The algorithm from the paper has been modified to correctly handle empty /// types. The changes are: @@ -913,7 +887,19 @@ fn is_useful<'p, 'tcx>( .collect::>() }; - lint_non_exhaustive_omitted_patterns(pcx.cx, pcx.ty, pcx.span, hir_id, patterns); + // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` + // is not exhaustive enough. + // + // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. + cx.tcx.emit_spanned_lint( + NON_EXHAUSTIVE_OMITTED_PATTERNS, + hir_id, + pcx.span, + NonExhaustiveOmittedPattern { + scrut_ty: pcx.ty, + uncovered: Uncovered::new(pcx.span, pcx.cx, patterns), + }, + ); } ret.extend(usefulness); diff --git a/tests/ui/consts/const-match-check.eval1.stderr b/tests/ui/consts/const-match-check.eval1.stderr index 6e61dbbd8eee3..1caf1617e213c 100644 --- a/tests/ui/consts/const-match-check.eval1.stderr +++ b/tests/ui/consts/const-match-check.eval1.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:25:15 | LL | A = { let 0 = 0; 0 }, diff --git a/tests/ui/consts/const-match-check.eval2.stderr b/tests/ui/consts/const-match-check.eval2.stderr index 1b3b6e06c3df6..f038ba1c8ed85 100644 --- a/tests/ui/consts/const-match-check.eval2.stderr +++ b/tests/ui/consts/const-match-check.eval2.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:31:24 | LL | let x: [i32; { let 0 = 0; 0 }] = []; diff --git a/tests/ui/consts/const-match-check.matchck.stderr b/tests/ui/consts/const-match-check.matchck.stderr index bc8edfa7af9f4..b1921f8a41e48 100644 --- a/tests/ui/consts/const-match-check.matchck.stderr +++ b/tests/ui/consts/const-match-check.matchck.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:4:22 | LL | const X: i32 = { let 0 = 0; 0 }; @@ -12,7 +12,7 @@ help: you might want to use `if let` to ignore the variants that aren't matched LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:8:23 | LL | static Y: i32 = { let 0 = 0; 0 }; @@ -26,7 +26,7 @@ help: you might want to use `if let` to ignore the variants that aren't matched LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:13:26 | LL | const X: i32 = { let 0 = 0; 0 }; @@ -40,7 +40,7 @@ help: you might want to use `if let` to ignore the variants that aren't matched LL | const X: i32 = { if let 0 = 0 { todo!() } 0 }; | ++ ~~~~~~~~~~~ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/const-match-check.rs:19:26 | LL | const X: i32 = { let 0 = 0; 0 }; diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs index 2105c12a1680a..61bdf57ffdb94 100644 --- a/tests/ui/consts/const-pattern-irrefutable.rs +++ b/tests/ui/consts/const-pattern-irrefutable.rs @@ -9,8 +9,20 @@ use foo::d; const a: u8 = 2; fn main() { - let a = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX - let c = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX - let d = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX + let a = 4; + //~^ ERROR refutable pattern in local binding + //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead + let c = 4; + //~^ ERROR refutable pattern in local binding + //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead + let d = 4; + //~^ ERROR refutable pattern in local binding + //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable + //~| HELP introduce a variable instead fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr index a2b8f072c6ea7..c156ea1610c4f 100644 --- a/tests/ui/consts/const-pattern-irrefutable.stderr +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/const-pattern-irrefutable.rs:12:9 | LL | const a: u8 = 2; @@ -7,13 +7,14 @@ LL | const a: u8 = 2; LL | let a = 4; | ^ | | - | interpreted as a constant pattern, not a new variable + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `a_var` | = note: the matched value is of type `u8` -error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - --> $DIR/const-pattern-irrefutable.rs:13:9 +error[E0005]: refutable pattern in local binding + --> $DIR/const-pattern-irrefutable.rs:17:9 | LL | pub const b: u8 = 2; | --------------- constant defined here @@ -21,13 +22,14 @@ LL | pub const b: u8 = 2; LL | let c = 4; | ^ | | - | interpreted as a constant pattern, not a new variable + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `c_var` | = note: the matched value is of type `u8` -error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - --> $DIR/const-pattern-irrefutable.rs:14:9 +error[E0005]: refutable pattern in local binding + --> $DIR/const-pattern-irrefutable.rs:22:9 | LL | pub const d: u8 = 2; | --------------- constant defined here @@ -35,7 +37,8 @@ LL | pub const d: u8 = 2; LL | let d = 4; | ^ | | - | interpreted as a constant pattern, not a new variable + | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `d_var` | = note: the matched value is of type `u8` diff --git a/tests/ui/consts/const_let_refutable.stderr b/tests/ui/consts/const_let_refutable.stderr index d7e8c048f7dcc..d6119028f5b59 100644 --- a/tests/ui/consts/const_let_refutable.stderr +++ b/tests/ui/consts/const_let_refutable.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _, ..]` not covered +error[E0005]: refutable pattern in function argument --> $DIR/const_let_refutable.rs:3:16 | LL | const fn slice(&[a, b]: &[i32]) -> i32 { diff --git a/tests/ui/empty/empty-never-array.rs b/tests/ui/empty/empty-never-array.rs index 3de2b1a78a3da..fd93346101d84 100644 --- a/tests/ui/empty/empty-never-array.rs +++ b/tests/ui/empty/empty-never-array.rs @@ -8,7 +8,8 @@ enum Helper { fn transmute(t: T) -> U { let Helper::U(u) = Helper::T(t, []); - //~^ ERROR refutable pattern in local binding: `Helper::T(_, _)` not covered + //~^ ERROR refutable pattern in local binding + //~| `Helper::T(_, _)` not covered u } diff --git a/tests/ui/empty/empty-never-array.stderr b/tests/ui/empty/empty-never-array.stderr index adf7827436805..a488e484b2bf8 100644 --- a/tests/ui/empty/empty-never-array.stderr +++ b/tests/ui/empty/empty-never-array.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `Helper::T(_, _)` not covered +error[E0005]: refutable pattern in local binding --> $DIR/empty-never-array.rs:10:9 | LL | let Helper::U(u) = Helper::T(t, []); @@ -7,18 +7,14 @@ LL | let Helper::U(u) = Helper::T(t, []); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Helper` defined here - --> $DIR/empty-never-array.rs:4:5 + --> $DIR/empty-never-array.rs:3:6 | LL | enum Helper { - | ------ + | ^^^^^^ LL | T(T, [!; 0]), - | ^ not covered + | - not covered = note: the matched value is of type `Helper` -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() }; - | ++++++++++ ++++++++++++++++++++++ -help: alternatively, you might want to use let else to handle the variant that isn't matched +help: you might want to use `let else` to handle the variant that isn't matched | LL | let Helper::U(u) = Helper::T(t, []) else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/error-codes/E0005.stderr b/tests/ui/error-codes/E0005.stderr index 0f179259356d5..4692b66413dff 100644 --- a/tests/ui/error-codes/E0005.stderr +++ b/tests/ui/error-codes/E0005.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `None` not covered +error[E0005]: refutable pattern in local binding --> $DIR/E0005.rs:3:9 | LL | let Some(y) = x; @@ -6,17 +6,8 @@ LL | let Some(y) = x; | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -note: `Option` defined here - --> $SRC_DIR/core/src/option.rs:LL:COL - ::: $SRC_DIR/core/src/option.rs:LL:COL - | - = note: not covered = note: the matched value is of type `Option` -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | let y = if let Some(y) = x { y } else { todo!() }; - | ++++++++++ ++++++++++++++++++++++ -help: alternatively, you might want to use let else to handle the variant that isn't matched +help: you might want to use `let else` to handle the variant that isn't matched | LL | let Some(y) = x else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/error-codes/E0297.stderr b/tests/ui/error-codes/E0297.stderr index 903422f3b9b8a..293028f5f68b1 100644 --- a/tests/ui/error-codes/E0297.stderr +++ b/tests/ui/error-codes/E0297.stderr @@ -1,14 +1,9 @@ -error[E0005]: refutable pattern in `for` loop binding: `None` not covered +error[E0005]: refutable pattern in `for` loop binding --> $DIR/E0297.rs:4:9 | LL | for Some(x) in xs {} | ^^^^^^^ pattern `None` not covered | -note: `Option` defined here - --> $SRC_DIR/core/src/option.rs:LL:COL - ::: $SRC_DIR/core/src/option.rs:LL:COL - | - = note: not covered = note: the matched value is of type `Option` error: aborting due to previous error diff --git a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr index e253e4791e8bd..49e7ab6082c82 100644 --- a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr +++ b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `Err(_)` not covered +error[E0005]: refutable pattern in local binding --> $DIR/feature-gate-exhaustive-patterns.rs:8:9 | LL | let Ok(_x) = foo(); @@ -6,17 +6,8 @@ LL | let Ok(_x) = foo(); | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -note: `Result` defined here - --> $SRC_DIR/core/src/result.rs:LL:COL - ::: $SRC_DIR/core/src/result.rs:LL:COL - | - = note: not covered = note: the matched value is of type `Result` -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | let _x = if let Ok(_x) = foo() { _x } else { todo!() }; - | +++++++++++ +++++++++++++++++++++++ -help: alternatively, you might want to use let else to handle the variant that isn't matched +help: you might want to use `let else` to handle the variant that isn't matched | LL | let Ok(_x) = foo() else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/for/for-loop-refutable-pattern-error-message.stderr b/tests/ui/for/for-loop-refutable-pattern-error-message.stderr index 20b689aa5e0af..49a82a6769dce 100644 --- a/tests/ui/for/for-loop-refutable-pattern-error-message.stderr +++ b/tests/ui/for/for-loop-refutable-pattern-error-message.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in `for` loop binding --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9 | LL | for &1 in [1].iter() {} diff --git a/tests/ui/issues/issue-15381.rs b/tests/ui/issues/issue-15381.rs index 392fb1b24ddc4..23b266bef1d91 100644 --- a/tests/ui/issues/issue-15381.rs +++ b/tests/ui/issues/issue-15381.rs @@ -2,7 +2,8 @@ fn main() { let values: Vec = vec![1,2,3,4,5,6,7,8]; for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { - //~^ ERROR refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not + //~^ ERROR refutable pattern in `for` loop binding + //~| patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered println!("y={}", y); } } diff --git a/tests/ui/issues/issue-15381.stderr b/tests/ui/issues/issue-15381.stderr index c4667ce1c8ba1..085958411ccb9 100644 --- a/tests/ui/issues/issue-15381.stderr +++ b/tests/ui/issues/issue-15381.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered +error[E0005]: refutable pattern in `for` loop binding --> $DIR/issue-15381.rs:4:9 | LL | for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { diff --git a/tests/ui/never_type/exhaustive_patterns.stderr b/tests/ui/never_type/exhaustive_patterns.stderr index e41baf862180d..40c7c1d1067ff 100644 --- a/tests/ui/never_type/exhaustive_patterns.stderr +++ b/tests/ui/never_type/exhaustive_patterns.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `Either::B(_)` not covered +error[E0005]: refutable pattern in local binding --> $DIR/exhaustive_patterns.rs:20:9 | LL | let Either::A(()) = foo(); @@ -7,13 +7,13 @@ LL | let Either::A(()) = foo(); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Either<(), !>` defined here - --> $DIR/exhaustive_patterns.rs:12:5 + --> $DIR/exhaustive_patterns.rs:10:6 | LL | enum Either { - | ------ + | ^^^^^^ LL | A(A), LL | B(inner::Wrapper), - | ^ not covered + | - not covered = note: the matched value is of type `Either<(), !>` help: you might want to use `if let` to ignore the variant that isn't matched | diff --git a/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr index 95b22ac059482..4adcf4feee90d 100644 --- a/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr +++ b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:2:10 | LL | let (0 | (1 | 2)) = 0; diff --git a/tests/ui/pattern/usefulness/issue-31561.rs b/tests/ui/pattern/usefulness/issue-31561.rs index 5b878851a3144..82414f0418bb2 100644 --- a/tests/ui/pattern/usefulness/issue-31561.rs +++ b/tests/ui/pattern/usefulness/issue-31561.rs @@ -6,5 +6,6 @@ enum Thing { fn main() { let Thing::Foo(y) = Thing::Foo(1); - //~^ ERROR refutable pattern in local binding: `Thing::Bar` and `Thing::Baz` not covered + //~^ ERROR refutable pattern in local binding + //~| `Thing::Bar` and `Thing::Baz` not covered } diff --git a/tests/ui/pattern/usefulness/issue-31561.stderr b/tests/ui/pattern/usefulness/issue-31561.stderr index 20f2f09500aa2..5367de5e513c7 100644 --- a/tests/ui/pattern/usefulness/issue-31561.stderr +++ b/tests/ui/pattern/usefulness/issue-31561.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `Thing::Bar` and `Thing::Baz` not covered +error[E0005]: refutable pattern in local binding --> $DIR/issue-31561.rs:8:9 | LL | let Thing::Foo(y) = Thing::Foo(1); @@ -7,21 +7,17 @@ LL | let Thing::Foo(y) = Thing::Foo(1); = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Thing` defined here - --> $DIR/issue-31561.rs:3:5 + --> $DIR/issue-31561.rs:1:6 | LL | enum Thing { - | ----- + | ^^^^^ LL | Foo(u8), LL | Bar, - | ^^^ not covered + | --- not covered LL | Baz - | ^^^ not covered + | --- not covered = note: the matched value is of type `Thing` -help: you might want to use `if let` to ignore the variants that aren't matched - | -LL | let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() }; - | ++++++++++ ++++++++++++++++++++++ -help: alternatively, you might want to use let else to handle the variants that aren't matched +help: you might want to use `let else` to handle the variants that aren't matched | LL | let Thing::Foo(y) = Thing::Foo(1) else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs index af42fc1aeb463..5145f769075d9 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs @@ -15,9 +15,6 @@ enum E { //~^ NOTE `E` defined here //~| NOTE `E` defined here //~| NOTE `E` defined here - //~| NOTE `E` defined here - //~| NOTE `E` defined here - //~| NOTE `E` defined here //~| NOTE not covered //~| NOTE not covered //~| NOTE not covered @@ -41,37 +38,41 @@ fn by_val(e: E) { E::A => {} } - let E::A = e; //~ ERROR refutable pattern in local binding: `E::B` and `E::C` not covered - //~^ NOTE patterns `E::B` and `E::C` not covered + let E::A = e; + //~^ ERROR refutable pattern in local binding + //~| patterns `E::B` and `E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html //~| NOTE the matched value is of type `E` } fn by_ref_once(e: &E) { - match e { //~ ERROR non-exhaustive patterns: `&E::B` and `&E::C` not covered - //~^ NOTE patterns `&E::B` and `&E::C` not covered + match e { + //~^ ERROR non-exhaustive patterns + //~| patterns `&E::B` and `&E::C` not covered //~| NOTE the matched value is of type `&E` E::A => {} } - let E::A = e; //~ ERROR refutable pattern in local binding: `&E::B` and `&E::C` not covered - //~^ NOTE patterns `&E::B` and `&E::C` not covered + let E::A = e; + //~^ ERROR refutable pattern in local binding + //~| patterns `&E::B` and `&E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html //~| NOTE the matched value is of type `&E` } fn by_ref_thrice(e: & &mut &E) { - match e { //~ ERROR non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered - //~^ NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered + match e { + //~^ ERROR non-exhaustive patterns + //~| patterns `&&mut &E::B` and `&&mut &E::C` not covered //~| NOTE the matched value is of type `&&mut &E` E::A => {} } let E::A = e; - //~^ ERROR refutable pattern in local binding: `&&mut &E::B` and `&&mut &E::C` not covered - //~| NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered + //~^ ERROR refutable pattern in local binding + //~| patterns `&&mut &E::B` and `&&mut &E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html //~| NOTE the matched value is of type `&&mut &E` @@ -83,20 +84,21 @@ enum Opt { Some(u8), None, //~^ NOTE `Opt` defined here - //~| NOTE `Opt` defined here //~| NOTE not covered //~| NOTE not covered } fn ref_pat(e: Opt) { - match e {//~ ERROR non-exhaustive patterns: `Opt::None` not covered - //~^ NOTE pattern `Opt::None` not covered + match e { + //~^ ERROR non-exhaustive patterns + //~| pattern `Opt::None` not covered //~| NOTE the matched value is of type `Opt` Opt::Some(ref _x) => {} } - let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `Opt::None` not covered - //~^ NOTE the matched value is of type `Opt` + let Opt::Some(ref _x) = e; + //~^ ERROR refutable pattern in local binding + //~| NOTE the matched value is of type `Opt` //~| NOTE pattern `Opt::None` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr index 678c9b2ab58c3..769d4070fb587 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `E::B` and `E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:38:11 + --> $DIR/non-exhaustive-defined-here.rs:35:11 | LL | match e1 { | ^^ patterns `E::B` and `E::C` not covered @@ -22,8 +22,8 @@ LL ~ E::A => {} LL + E::B | E::C => todo!() | -error[E0005]: refutable pattern in local binding: `E::B` and `E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:44:9 +error[E0005]: refutable pattern in local binding + --> $DIR/non-exhaustive-defined-here.rs:41:9 | LL | let E::A = e; | ^^^^ patterns `E::B` and `E::C` not covered @@ -31,16 +31,16 @@ LL | let E::A = e; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:6:6 | LL | enum E { - | - + | ^ ... LL | B, - | ^ not covered + | - not covered ... LL | C - | ^ not covered + | - not covered = note: the matched value is of type `E` help: you might want to use `if let` to ignore the variants that aren't matched | @@ -48,7 +48,7 @@ LL | if let E::A = e { todo!() } | ++ ~~~~~~~~~~~ error[E0004]: non-exhaustive patterns: `&E::B` and `&E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:52:11 + --> $DIR/non-exhaustive-defined-here.rs:50:11 | LL | match e { | ^ patterns `&E::B` and `&E::C` not covered @@ -71,8 +71,8 @@ LL ~ E::A => {} LL + &E::B | &E::C => todo!() | -error[E0005]: refutable pattern in local binding: `&E::B` and `&E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:58:9 +error[E0005]: refutable pattern in local binding + --> $DIR/non-exhaustive-defined-here.rs:57:9 | LL | let E::A = e; | ^^^^ patterns `&E::B` and `&E::C` not covered @@ -80,16 +80,16 @@ LL | let E::A = e; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:6:6 | LL | enum E { - | - + | ^ ... LL | B, - | ^ not covered + | - not covered ... LL | C - | ^ not covered + | - not covered = note: the matched value is of type `&E` help: you might want to use `if let` to ignore the variants that aren't matched | @@ -120,8 +120,8 @@ LL ~ E::A => {} LL + &&mut &E::B | &&mut &E::C => todo!() | -error[E0005]: refutable pattern in local binding: `&&mut &E::B` and `&&mut &E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:72:9 +error[E0005]: refutable pattern in local binding + --> $DIR/non-exhaustive-defined-here.rs:73:9 | LL | let E::A = e; | ^^^^ patterns `&&mut &E::B` and `&&mut &E::C` not covered @@ -129,16 +129,16 @@ LL | let E::A = e; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:6:6 | LL | enum E { - | - + | ^ ... LL | B, - | ^ not covered + | - not covered ... LL | C - | ^ not covered + | - not covered = note: the matched value is of type `&&mut &E` help: you might want to use `if let` to ignore the variants that aren't matched | @@ -152,7 +152,7 @@ LL | match e { | ^ pattern `Opt::None` not covered | note: `Opt` defined here - --> $DIR/non-exhaustive-defined-here.rs:84:5 + --> $DIR/non-exhaustive-defined-here.rs:85:5 | LL | enum Opt { | --- @@ -166,8 +166,8 @@ LL ~ Opt::Some(ref _x) => {} LL + Opt::None => todo!() | -error[E0005]: refutable pattern in local binding: `Opt::None` not covered - --> $DIR/non-exhaustive-defined-here.rs:98:9 +error[E0005]: refutable pattern in local binding + --> $DIR/non-exhaustive-defined-here.rs:99:9 | LL | let Opt::Some(ref _x) = e; | ^^^^^^^^^^^^^^^^^ pattern `Opt::None` not covered @@ -175,19 +175,15 @@ LL | let Opt::Some(ref _x) = e; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Opt` defined here - --> $DIR/non-exhaustive-defined-here.rs:84:5 + --> $DIR/non-exhaustive-defined-here.rs:81:6 | LL | enum Opt { - | --- + | ^^^ ... LL | None, - | ^^^^ not covered + | ---- not covered = note: the matched value is of type `Opt` -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() }; - | +++++++++++ +++++++++++++++++++++++ -help: alternatively, you might want to use let else to handle the variant that isn't matched +help: you might want to use `let else` to handle the variant that isn't matched | LL | let Opt::Some(ref _x) = e else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.rs b/tests/ui/pattern/usefulness/refutable-pattern-errors.rs index 7c9aa51e7484c..7a3e991d59317 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-errors.rs +++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.rs @@ -1,7 +1,9 @@ fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } -//~^ ERROR refutable pattern in function argument: `(_, _)` not covered +//~^ ERROR refutable pattern in function argument +//~| `(_, _)` not covered fn main() { let (1, (Some(1), 2..=3)) = (1, (None, 2)); - //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered + //~^ ERROR refutable pattern in local binding + //~| `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered } diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr index d1dacc822e942..c518de47740dd 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr +++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in function argument: `(_, _)` not covered +error[E0005]: refutable pattern in function argument --> $DIR/refutable-pattern-errors.rs:1:9 | LL | fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } @@ -6,8 +6,8 @@ LL | fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } | = note: the matched value is of type `(isize, (Option, isize))` -error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered - --> $DIR/refutable-pattern-errors.rs:5:9 +error[E0005]: refutable pattern in local binding + --> $DIR/refutable-pattern-errors.rs:6:9 | LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); | ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs index a2d9e1935de74..17dc38ab25d92 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs +++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs @@ -1,5 +1,6 @@ fn main() { let f = |3: isize| println!("hello"); - //~^ ERROR refutable pattern in function argument: `_` not covered + //~^ ERROR refutable pattern in function argument + //~| `_` not covered f(4); } diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr index c9d8cf43f95fd..55f0b2319fb7f 100644 --- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr +++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in function argument: `_` not covered +error[E0005]: refutable pattern in function argument --> $DIR/refutable-pattern-in-fn-arg.rs:2:14 | LL | let f = |3: isize| println!("hello"); diff --git a/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr b/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr index 86ad6aa847c9f..1b4d80d90571c 100644 --- a/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr +++ b/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `Err(_)` not covered +error[E0005]: refutable pattern in local binding --> $DIR/recursive-types-are-not-uninhabited.rs:6:9 | LL | let Ok(x) = res; @@ -6,17 +6,8 @@ LL | let Ok(x) = res; | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -note: `Result>` defined here - --> $SRC_DIR/core/src/result.rs:LL:COL - ::: $SRC_DIR/core/src/result.rs:LL:COL - | - = note: not covered = note: the matched value is of type `Result>` -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | let x = if let Ok(x) = res { x } else { todo!() }; - | ++++++++++ ++++++++++++++++++++++ -help: alternatively, you might want to use let else to handle the variant that isn't matched +help: you might want to use `let else` to handle the variant that isn't matched | LL | let Ok(x) = res else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs index ac819dce6db2b..15f08486f0f0e 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs @@ -1,7 +1,8 @@ fn main() { let A = 3; - //~^ ERROR refutable pattern in local binding: `i32::MIN..=1_i32` and - //~| interpreted as a constant pattern, not a new variable + //~^ ERROR refutable pattern in local binding + //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered + //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead //~| SUGGESTION a_var diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index 618bcaca14c4d..1c1cab25fbfaf 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -1,10 +1,11 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9 | LL | let A = 3; | ^ | | - | interpreted as a constant pattern, not a new variable + | patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered + | missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `a_var` ... LL | const A: i32 = 2; diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.rs b/tests/ui/uninhabited/uninhabited-irrefutable.rs index 1a0f3c5e5504a..4b001aca2d1c7 100644 --- a/tests/ui/uninhabited/uninhabited-irrefutable.rs +++ b/tests/ui/uninhabited/uninhabited-irrefutable.rs @@ -24,5 +24,7 @@ enum Foo { fn main() { let x: Foo = Foo::D(123, 456); - let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `Foo::A(_)` not covered + let Foo::D(_y, _z) = x; + //~^ ERROR refutable pattern in local binding + //~| `Foo::A(_)` not covered } diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.stderr b/tests/ui/uninhabited/uninhabited-irrefutable.stderr index 32f287a18188c..8cafea555c172 100644 --- a/tests/ui/uninhabited/uninhabited-irrefutable.stderr +++ b/tests/ui/uninhabited/uninhabited-irrefutable.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `Foo::A(_)` not covered +error[E0005]: refutable pattern in local binding --> $DIR/uninhabited-irrefutable.rs:27:9 | LL | let Foo::D(_y, _z) = x; @@ -7,18 +7,14 @@ LL | let Foo::D(_y, _z) = x; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Foo` defined here - --> $DIR/uninhabited-irrefutable.rs:19:5 + --> $DIR/uninhabited-irrefutable.rs:18:6 | LL | enum Foo { - | --- + | ^^^ LL | A(foo::SecretlyEmpty), - | ^ not covered + | - not covered = note: the matched value is of type `Foo` -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() }; - | +++++++++++++++++ +++++++++++++++++++++++++++++ -help: alternatively, you might want to use let else to handle the variant that isn't matched +help: you might want to use `let else` to handle the variant that isn't matched | LL | let Foo::D(_y, _z) = x else { todo!() }; | ++++++++++++++++ diff --git a/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr index d33a61ca8485c..466d7f2eadb92 100644 --- a/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr +++ b/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr @@ -95,7 +95,7 @@ LL ~ Ok(x) => x, LL ~ Err(_) => todo!(), | -error[E0005]: refutable pattern in local binding: `Err(_)` not covered +error[E0005]: refutable pattern in local binding --> $DIR/uninhabited-matches-feature-gated.rs:37:9 | LL | let Ok(x) = x; @@ -103,17 +103,8 @@ LL | let Ok(x) = x; | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html -note: `Result` defined here - --> $SRC_DIR/core/src/result.rs:LL:COL - ::: $SRC_DIR/core/src/result.rs:LL:COL - | - = note: not covered = note: the matched value is of type `Result` -help: you might want to use `if let` to ignore the variant that isn't matched - | -LL | let x = if let Ok(x) = x { x } else { todo!() }; - | ++++++++++ ++++++++++++++++++++++ -help: alternatively, you might want to use let else to handle the variant that isn't matched +help: you might want to use `let else` to handle the variant that isn't matched | LL | let Ok(x) = x else { todo!() }; | ++++++++++++++++