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 933653e708e94..165d3f37111e9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -9,9 +9,7 @@ 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, -}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; @@ -44,7 +42,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err for param in thir.params.iter() { if let Some(box ref pattern) = param.pat { - visitor.check_irrefutable(pattern, "function argument", None); + visitor.check_binding_is_irrefutable(pattern, "function argument", None); } } visitor.error @@ -58,7 +56,7 @@ fn create_e0004( struct_span_err!(sess, sp, E0004, "{}", &error_message) } -#[derive(PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] enum RefutableFlag { Irrefutable, Refutable, @@ -68,24 +66,30 @@ use RefutableFlag::*; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum LetSource { None, + PlainLet, IfLet, IfLetGuard, LetElse, WhileLet, } -struct MatchVisitor<'a, 'p, 'tcx> { +struct MatchVisitor<'thir, 'p, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - thir: &'a Thir<'tcx>, + thir: &'thir Thir<'tcx>, lint_level: HirId, let_source: LetSource, pattern_arena: &'p TypedArena>, + /// Tracks if we encountered an error while checking this body. That the first function to + /// report it stores it here. Some functions return `Result` to allow callers to short-circuit + /// on error, but callers don't need to store it here again. error: Result<(), ErrorGuaranteed>, } -impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { - fn thir(&self) -> &'a Thir<'tcx> { +// Visitor for a thir body. This calls `check_match`, `check_let` and `check_let_chain` as +// appropriate. +impl<'thir, 'tcx> Visitor<'thir, 'tcx> for MatchVisitor<'thir, '_, 'tcx> { + fn thir(&self) -> &'thir Thir<'tcx> { self.thir } @@ -100,7 +104,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { } Some(Guard::IfLet(ref pat, expr)) => { this.with_let_source(LetSource::IfLetGuard, |this| { - this.check_let(pat, expr, LetSource::IfLetGuard, pat.span); + this.check_let(pat, Some(expr), pat.span); this.visit_pat(pat); this.visit_expr(&this.thir[expr]); }); @@ -148,10 +152,18 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { self.check_match(scrutinee, arms, source, ex.span); } ExprKind::Let { box ref pat, expr } => { - self.check_let(pat, expr, self.let_source, ex.span); + self.check_let(pat, Some(expr), ex.span); } - ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { - self.check_let_chain(self.let_source, ex.span, lhs, rhs); + ExprKind::LogicalOp { op: LogicalOp::And, .. } + if !matches!(self.let_source, LetSource::None) => + { + let mut chain_refutabilities = Vec::new(); + let Ok(()) = self.visit_land(ex, &mut chain_refutabilities) else { return }; + // If at least one of the operands is a `let ... = ...`. + if chain_refutabilities.iter().any(|x| x.is_some()) { + self.check_let_chain(chain_refutabilities, ex.span); + } + return; } _ => {} }; @@ -159,33 +171,27 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { } fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { - let old_lint_level = self.lint_level; match stmt.kind { StmtKind::Let { box ref pattern, initializer, else_block, lint_level, span, .. } => { - if let LintLevel::Explicit(lint_level) = lint_level { - self.lint_level = lint_level; - } - - if let Some(initializer) = initializer - && else_block.is_some() - { - self.check_let(pattern, initializer, LetSource::LetElse, span); - } - - if else_block.is_none() { - self.check_irrefutable(pattern, "local binding", Some(span)); - } + self.with_lint_level(lint_level, |this| { + let let_source = + if else_block.is_some() { LetSource::LetElse } else { LetSource::PlainLet }; + this.with_let_source(let_source, |this| { + this.check_let(pattern, initializer, span) + }); + visit::walk_stmt(this, stmt); + }); + } + StmtKind::Expr { .. } => { + visit::walk_stmt(self, stmt); } - _ => {} } - visit::walk_stmt(self, stmt); - self.lint_level = old_lint_level; } } -impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { +impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> { #[instrument(level = "trace", skip(self, f))] fn with_let_source(&mut self, let_source: LetSource, f: impl FnOnce(&mut Self)) { let old_let_source = self.let_source; @@ -194,53 +200,122 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { self.let_source = old_let_source; } - fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) { + fn with_lint_level( + &mut self, + new_lint_level: LintLevel, + f: impl FnOnce(&mut Self) -> T, + ) -> T { if let LintLevel::Explicit(hir_id) = new_lint_level { let old_lint_level = self.lint_level; self.lint_level = hir_id; - f(self); + let ret = f(self); self.lint_level = old_lint_level; + ret } else { - f(self); + f(self) } } - fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) { - pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); - check_for_bindings_named_same_as_variants(self, pat, rf); + /// Visit a nested chain of `&&`. Used for if-let chains. This must call `visit_expr` on the + /// subexpressions we are not handling ourselves. + fn visit_land( + &mut self, + ex: &Expr<'tcx>, + accumulator: &mut Vec>, + ) -> Result<(), ErrorGuaranteed> { + match ex.kind { + ExprKind::Scope { value, lint_level, .. } => self.with_lint_level(lint_level, |this| { + this.visit_land(&this.thir[value], accumulator) + }), + ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { + // We recurse into the lhs only, because `&&` chains associate to the left. + let res_lhs = self.visit_land(&self.thir[lhs], accumulator); + let res_rhs = self.visit_land_rhs(&self.thir[rhs])?; + accumulator.push(res_rhs); + res_lhs + } + _ => { + let res = self.visit_land_rhs(ex)?; + accumulator.push(res); + Ok(()) + } + } + } + + /// Visit the right-hand-side of a `&&`. Used for if-let chains. Returns `Some` if the + /// expression was ultimately a `let ... = ...`, and `None` if it was a normal boolean + /// expression. This must call `visit_expr` on the subexpressions we are not handling ourselves. + fn visit_land_rhs( + &mut self, + ex: &Expr<'tcx>, + ) -> Result, ErrorGuaranteed> { + match ex.kind { + ExprKind::Scope { value, lint_level, .. } => { + self.with_lint_level(lint_level, |this| this.visit_land_rhs(&this.thir[value])) + } + ExprKind::Let { box ref pat, expr } => { + self.with_let_source(LetSource::None, |this| { + this.visit_expr(&this.thir()[expr]); + }); + Ok(Some((ex.span, self.is_let_irrefutable(pat)?))) + } + _ => { + self.with_let_source(LetSource::None, |this| { + this.visit_expr(ex); + }); + Ok(None) + } + } } fn lower_pattern( - &self, - cx: &mut MatchCheckCtxt<'p, 'tcx>, - pattern: &Pat<'tcx>, - ) -> &'p DeconstructedPat<'p, 'tcx> { - cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)) + &mut self, + cx: &MatchCheckCtxt<'p, 'tcx>, + pat: &Pat<'tcx>, + ) -> Result<&'p DeconstructedPat<'p, 'tcx>, ErrorGuaranteed> { + if let Err(err) = pat.pat_error_reported() { + self.error = Err(err); + Err(err) + } else { + // Check the pattern for some things unrelated to exhaustiveness. + let refutable = if cx.refutable { Refutable } else { Irrefutable }; + pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); + pat.walk_always(|pat| check_for_bindings_named_same_as_variants(self, pat, refutable)); + Ok(cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, pat))) + } } - fn new_cx(&self, hir_id: HirId, refutable: bool) -> MatchCheckCtxt<'p, 'tcx> { + fn new_cx(&self, refutability: RefutableFlag) -> MatchCheckCtxt<'p, 'tcx> { + let refutable = match refutability { + Irrefutable => false, + Refutable => true, + }; MatchCheckCtxt { tcx: self.tcx, param_env: self.param_env, - module: self.tcx.parent_module(hir_id).to_def_id(), + module: self.tcx.parent_module(self.lint_level).to_def_id(), pattern_arena: &self.pattern_arena, refutable, } } #[instrument(level = "trace", skip(self))] - fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: ExprId, source: LetSource, span: Span) { - if let LetSource::None = source { - return; - } - if let Err(err) = pat.pat_error_reported() { - self.error = Err(err); - return; + fn check_let(&mut self, pat: &Pat<'tcx>, scrutinee: Option, span: Span) { + assert!(self.let_source != LetSource::None); + if let LetSource::PlainLet = self.let_source { + self.check_binding_is_irrefutable(pat, "local binding", Some(span)) + } else { + let Ok(refutability) = self.is_let_irrefutable(pat) else { return }; + if matches!(refutability, Irrefutable) { + report_irrefutable_let_patterns( + self.tcx, + self.lint_level, + self.let_source, + 1, + span, + ); + } } - self.check_patterns(pat, Refutable); - let mut cx = self.new_cx(self.lint_level, true); - let tpat = self.lower_pattern(&mut cx, pat); - self.check_let_reachability(&mut cx, self.lint_level, source, tpat, span); } fn check_match( @@ -250,33 +325,22 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { source: hir::MatchSource, expr_span: Span, ) { - let mut cx = self.new_cx(self.lint_level, true); + let cx = self.new_cx(Refutable); + let mut tarms = Vec::with_capacity(arms.len()); for &arm in arms { - // Check the arm for some things unrelated to exhaustiveness. let arm = &self.thir.arms[arm]; - self.with_lint_level(arm.lint_level, |this| { - this.check_patterns(&arm.pattern, Refutable); + let got_error = self.with_lint_level(arm.lint_level, |this| { + let Ok(pat) = this.lower_pattern(&cx, &arm.pattern) else { return true }; + let arm = MatchArm { pat, hir_id: this.lint_level, has_guard: arm.guard.is_some() }; + tarms.push(arm); + false }); - if let Err(err) = arm.pattern.pat_error_reported() { - self.error = Err(err); + if got_error { return; } } - let tarms: Vec<_> = arms - .iter() - .map(|&arm| { - let arm = &self.thir.arms[arm]; - let hir_id = match arm.lint_level { - LintLevel::Explicit(hir_id) => hir_id, - LintLevel::Inherited => self.lint_level, - }; - let pat = self.lower_pattern(&mut cx, &arm.pattern); - MatchArm { pat, hir_id, has_guard: arm.guard.is_some() } - }) - .collect(); - let scrut = &self.thir[scrut]; let scrut_ty = scrut.ty; let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span); @@ -303,118 +367,37 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { debug_assert_eq!(pat.span.desugaring_kind(), Some(DesugaringKind::ForLoop)); let PatKind::Variant { ref subpatterns, .. } = pat.kind else { bug!() }; let [pat_field] = &subpatterns[..] else { bug!() }; - self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None); + self.check_binding_is_irrefutable(&pat_field.pattern, "`for` loop binding", None); } else { - self.error = Err(non_exhaustive_match( + self.error = Err(report_non_exhaustive_match( &cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span, )); } } } - fn check_let_reachability( - &mut self, - cx: &mut MatchCheckCtxt<'p, 'tcx>, - pat_id: HirId, - source: LetSource, - pat: &'p DeconstructedPat<'p, 'tcx>, - span: Span, - ) { - if is_let_irrefutable(cx, pat_id, pat) { - irrefutable_let_patterns(cx.tcx, pat_id, source, 1, span); - } - } - #[instrument(level = "trace", skip(self))] fn check_let_chain( &mut self, - let_source: LetSource, - top_expr_span: Span, - mut lhs: ExprId, - rhs: ExprId, + chain_refutabilities: Vec>, + whole_chain_span: Span, ) { - if let LetSource::None = let_source { - return; - } - - // Lint level enclosing the next `lhs`. - let mut cur_lint_level = self.lint_level; - - // Obtain the refutabilities of all exprs in the chain, - // and record chain members that aren't let exprs. - let mut chain_refutabilities = Vec::new(); - - let mut error = Ok(()); - let mut add = |expr: ExprId, mut local_lint_level| { - // `local_lint_level` is the lint level enclosing the pattern inside `expr`. - let mut expr = &self.thir[expr]; - debug!(?expr, ?local_lint_level, "add"); - // Fast-forward through scopes. - while let ExprKind::Scope { value, lint_level, .. } = expr.kind { - if let LintLevel::Explicit(hir_id) = lint_level { - local_lint_level = hir_id - } - expr = &self.thir[value]; - } - debug!(?expr, ?local_lint_level, "after scopes"); - match expr.kind { - ExprKind::Let { box ref pat, expr: _ } => { - if let Err(err) = pat.pat_error_reported() { - error = Err(err); - return None; - } - let mut ncx = self.new_cx(local_lint_level, true); - let tpat = self.lower_pattern(&mut ncx, pat); - let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat); - Some((expr.span, refutable)) - } - _ => None, - } - }; - - // Let chains recurse on the left, so we start by adding the rightmost. - chain_refutabilities.push(add(rhs, cur_lint_level)); - - loop { - while let ExprKind::Scope { value, lint_level, .. } = self.thir[lhs].kind { - if let LintLevel::Explicit(hir_id) = lint_level { - cur_lint_level = hir_id - } - lhs = value; - } - if let ExprKind::LogicalOp { op: LogicalOp::And, lhs: new_lhs, rhs: expr } = - self.thir[lhs].kind - { - chain_refutabilities.push(add(expr, cur_lint_level)); - lhs = new_lhs; - } else { - chain_refutabilities.push(add(lhs, cur_lint_level)); - break; - } - } - debug!(?chain_refutabilities); - chain_refutabilities.reverse(); - - if error.is_err() { - self.error = error; - return; - } + assert!(self.let_source != LetSource::None); - // Third, emit the actual warnings. - if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) { + if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, Irrefutable)))) { // The entire chain is made up of irrefutable `let` statements - irrefutable_let_patterns( + report_irrefutable_let_patterns( self.tcx, self.lint_level, - let_source, + self.let_source, chain_refutabilities.len(), - top_expr_span, + whole_chain_span, ); return; } if let Some(until) = - chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) + chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, Irrefutable)))) && until > 0 { // The chain has a non-zero prefix of irrefutable `let` statements. @@ -425,7 +408,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // so can't always be moved out. // FIXME: Add checking whether the bindings are actually used in the prefix, // and lint if they are not. - if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) { + if !matches!(self.let_source, LetSource::WhileLet | LetSource::IfLetGuard) { // Emit the lint let prefix = &chain_refutabilities[..until]; let span_start = prefix[0].unwrap().0; @@ -442,7 +425,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } if let Some(from) = - chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) + chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, Irrefutable)))) && from != (chain_refutabilities.len() - 1) { // The chain has a non-empty suffix of irrefutable `let` statements @@ -460,28 +443,36 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } } - #[instrument(level = "trace", skip(self))] - fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option) { - // If we got errors while lowering, don't emit anything more. - if let Err(err) = pat.pat_error_reported() { - self.error = Err(err); - return; - } + fn analyze_binding( + &mut self, + pat: &Pat<'tcx>, + refutability: RefutableFlag, + ) -> Result<(MatchCheckCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> { + let cx = self.new_cx(refutability); + let pat = self.lower_pattern(&cx, pat)?; + let arms = [MatchArm { pat, hir_id: self.lint_level, has_guard: false }]; + let report = compute_match_usefulness(&cx, &arms, self.lint_level, pat.ty(), pat.span()); + Ok((cx, report)) + } - let mut cx = self.new_cx(self.lint_level, false); + fn is_let_irrefutable(&mut self, pat: &Pat<'tcx>) -> Result { + let (cx, report) = self.analyze_binding(pat, Refutable)?; + // Report if the pattern is unreachable, which can only occur when the type is uninhabited. + // This also reports unreachable sub-patterns. + report_arm_reachability(&cx, &report); + // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is + // irrefutable. + Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable }) + } - let pattern = self.lower_pattern(&mut cx, pat); - let pattern_ty = pattern.ty(); - let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false }; - let report = - compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty, pattern.span()); + #[instrument(level = "trace", skip(self))] + fn check_binding_is_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option) { + let pattern_ty = pat.ty; - // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We - // only care about exhaustiveness here. + let Ok((cx, report)) = self.analyze_binding(pat, Irrefutable) else { return }; let witnesses = report.non_exhaustiveness_witnesses; if witnesses.is_empty() { // The pattern is irrefutable. - self.check_patterns(pat, Irrefutable); return; } @@ -528,30 +519,20 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { }); }; - 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![]; - - for span in maybe_point_at_variant(&cx, *def, witnesses.iter().take(5)) { - variants.push(Variant { span }); - } - AdtDefinedHere { adt_def_span, ty, variants } - }; + let adt_defined_here = report_adt_defined_here(self.tcx, pattern_ty, &witnesses, false); // Emit an extra note if the first uncovered witness would be uninhabited // if we disregard visibility. - let witness_1_is_privately_uninhabited = if cx.tcx.features().exhaustive_patterns + let witness_1_is_privately_uninhabited = if self.tcx.features().exhaustive_patterns && let Some(witness_1) = witnesses.get(0) && let ty::Adt(adt, args) = witness_1.ty().kind() && adt.is_enum() && let Constructor::Variant(variant_index) = witness_1.ctor() { let variant = adt.variant(*variant_index); - let inhabited = variant.inhabited_predicate(cx.tcx, *adt).instantiate(cx.tcx, args); - assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module)); - !inhabited.apply_ignore_module(cx.tcx, cx.param_env) + let inhabited = variant.inhabited_predicate(self.tcx, *adt).instantiate(self.tcx, args); + assert!(inhabited.apply(self.tcx, cx.param_env, cx.module)); + !inhabited.apply_ignore_module(self.tcx, cx.param_env) } else { false }; @@ -572,70 +553,154 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { } } -fn check_for_bindings_named_same_as_variants( - cx: &MatchVisitor<'_, '_, '_>, - pat: &Pat<'_>, - rf: RefutableFlag, -) { - pat.walk_always(|p| { - if let PatKind::Binding { - name, - mode: BindingMode::ByValue, - mutability: Mutability::Not, - subpattern: None, - ty, - .. - } = p.kind - && let ty::Adt(edef, _) = ty.peel_refs().kind() - && edef.is_enum() - && edef - .variants() - .iter() - .any(|variant| variant.name == name && variant.ctor_kind() == Some(CtorKind::Const)) - { - let variant_count = edef.variants().len(); - let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); - cx.tcx.emit_spanned_lint( - BINDINGS_WITH_VARIANT_NAME, - cx.lint_level, - p.span, - BindingsWithVariantName { - // If this is an irrefutable pattern, and there's > 1 variant, - // then we can't actually match on this. Applying the below - // suggestion would produce code that breaks on `check_irrefutable`. - suggestion: if rf == Refutable || variant_count == 1 { - Some(p.span) - } else { - None - }, - ty_path, +/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. +/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. +/// +/// For example, this would reject: +/// - `ref x @ Some(ref mut y)`, +/// - `ref mut x @ Some(ref y)`, +/// - `ref mut x @ Some(ref mut y)`, +/// - `ref mut? x @ Some(y)`, and +/// - `x @ Some(ref mut? y)`. +/// +/// This analysis is *not* subsumed by NLL. +fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) { + // Extract `sub` in `binding @ sub`. + let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else { + return; + }; + + let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + + let sess = cx.tcx.sess; + + // Get the binding move, extract the mutability if by-ref. + let mut_outer = match mode { + BindingMode::ByValue if is_binding_by_move(ty) => { + // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. + let mut conflicts_ref = Vec::new(); + sub.each_binding(|_, mode, _, span| match mode { + BindingMode::ByValue => {} + BindingMode::ByRef(_) => conflicts_ref.push(span), + }); + if !conflicts_ref.is_empty() { + sess.emit_err(BorrowOfMovedValue { + binding_span: pat.span, + conflicts_ref, name, - }, - ) + ty, + suggest_borrowing: Some(pat.span.shrink_to_lo()), + }); + } + return; + } + BindingMode::ByValue => return, + BindingMode::ByRef(m) => m.mutability(), + }; + + // We now have `ref $mut_outer binding @ sub` (semantically). + // Recurse into each binding in `sub` and find mutability or move conflicts. + let mut conflicts_move = Vec::new(); + let mut conflicts_mut_mut = Vec::new(); + let mut conflicts_mut_ref = Vec::new(); + sub.each_binding(|name, mode, ty, span| { + match mode { + BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) { + // Both sides are `ref`. + (Mutability::Not, Mutability::Not) => {} + // 2x `ref mut`. + (Mutability::Mut, Mutability::Mut) => { + conflicts_mut_mut.push(Conflict::Mut { span, name }) + } + (Mutability::Not, Mutability::Mut) => { + conflicts_mut_ref.push(Conflict::Mut { span, name }) + } + (Mutability::Mut, Mutability::Not) => { + conflicts_mut_ref.push(Conflict::Ref { span, name }) + } + }, + BindingMode::ByValue if is_binding_by_move(ty) => { + conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. + } + BindingMode::ByValue => {} // `ref mut?` + by-copy is fine. } }); -} -/// Checks for common cases of "catchall" patterns that may not be intended as such. -fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { - use Constructor::*; - match pat.ctor() { - Wildcard => true, - Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)), - _ => false, + let report_mut_mut = !conflicts_mut_mut.is_empty(); + let report_mut_ref = !conflicts_mut_ref.is_empty(); + let report_move_conflict = !conflicts_move.is_empty(); + + let mut occurrences = match mut_outer { + Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }], + Mutability::Not => vec![Conflict::Ref { span: pat.span, name }], + }; + occurrences.extend(conflicts_mut_mut); + occurrences.extend(conflicts_mut_ref); + occurrences.extend(conflicts_move); + + // Report errors if any. + if report_mut_mut { + // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. + sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences }); + } else if report_mut_ref { + // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. + match mut_outer { + Mutability::Mut => { + sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences }); + } + Mutability::Not => { + sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences }); + } + }; + } else if report_move_conflict { + // Report by-ref and by-move conflicts, e.g. `ref x @ y`. + sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences }); } } -fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option) { - tcx.emit_spanned_lint( - UNREACHABLE_PATTERNS, - id, - span, - UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall }, - ); +fn check_for_bindings_named_same_as_variants( + cx: &MatchVisitor<'_, '_, '_>, + pat: &Pat<'_>, + rf: RefutableFlag, +) { + if let PatKind::Binding { + name, + mode: BindingMode::ByValue, + mutability: Mutability::Not, + subpattern: None, + ty, + .. + } = pat.kind + && let ty::Adt(edef, _) = ty.peel_refs().kind() + && edef.is_enum() + && edef + .variants() + .iter() + .any(|variant| variant.name == name && variant.ctor_kind() == Some(CtorKind::Const)) + { + let variant_count = edef.variants().len(); + let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); + cx.tcx.emit_spanned_lint( + BINDINGS_WITH_VARIANT_NAME, + cx.lint_level, + pat.span, + BindingsWithVariantName { + // If this is an irrefutable pattern, and there's > 1 variant, + // then we can't actually match on this. Applying the below + // suggestion would produce code that breaks on `check_binding_is_irrefutable`. + suggestion: if rf == Refutable || variant_count == 1 { + Some(pat.span) + } else { + None + }, + ty_path, + name, + }, + ) + } } -fn irrefutable_let_patterns( +fn report_irrefutable_let_patterns( tcx: TyCtxt<'_>, id: HirId, source: LetSource, @@ -649,7 +714,7 @@ fn irrefutable_let_patterns( } match source { - LetSource::None => bug!(), + LetSource::None | LetSource::PlainLet => bug!(), LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse), @@ -657,34 +722,28 @@ fn irrefutable_let_patterns( } } -fn is_let_irrefutable<'p, 'tcx>( - cx: &mut MatchCheckCtxt<'p, 'tcx>, - pat_id: HirId, - pat: &'p DeconstructedPat<'p, 'tcx>, -) -> bool { - let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; - let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty(), pat.span()); - - // Report if the pattern is unreachable, which can only occur when the type is uninhabited. - // This also reports unreachable sub-patterns though, so we can't just replace it with an - // `is_uninhabited` check. - report_arm_reachability(&cx, &report); - - // If the list of witnesses is empty, the match is exhaustive, - // i.e. the `if let` pattern is irrefutable. - report.non_exhaustiveness_witnesses.is_empty() -} - /// Report unreachable arms, if any. fn report_arm_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>, ) { + let report_unreachable_pattern = |span, hir_id, catchall: Option| { + cx.tcx.emit_spanned_lint( + UNREACHABLE_PATTERNS, + hir_id, + span, + UnreachablePattern { + span: if catchall.is_some() { Some(span) } else { None }, + catchall, + }, + ); + }; + use Reachability::*; let mut catchall = None; for (arm, is_useful) in report.arm_usefulness.iter() { match is_useful { - Unreachable => unreachable_pattern(cx.tcx, arm.pat.span(), arm.hir_id, catchall), + Unreachable => report_unreachable_pattern(arm.pat.span(), arm.hir_id, catchall), Reachable(unreachables) if unreachables.is_empty() => {} // The arm is reachable, but contains unreachable subpatterns (from or-patterns). Reachable(unreachables) => { @@ -692,7 +751,7 @@ fn report_arm_reachability<'p, 'tcx>( // Emit lints in the order in which they occur in the file. unreachables.sort_unstable(); for span in unreachables { - unreachable_pattern(cx.tcx, span, arm.hir_id, None); + report_unreachable_pattern(span, arm.hir_id, None); } } } @@ -702,26 +761,18 @@ fn report_arm_reachability<'p, 'tcx>( } } -fn collect_non_exhaustive_tys<'tcx>( - tcx: TyCtxt<'tcx>, - pat: &WitnessPat<'tcx>, - non_exhaustive_tys: &mut FxHashSet>, -) { - if matches!(pat.ctor(), Constructor::NonExhaustive) { - non_exhaustive_tys.insert(pat.ty()); - } - if let Constructor::IntRange(range) = pat.ctor() { - if range.is_beyond_boundaries(pat.ty(), tcx) { - // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`. - non_exhaustive_tys.insert(pat.ty()); - } +/// Checks for common cases of "catchall" patterns that may not be intended as such. +fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { + use Constructor::*; + match pat.ctor() { + Wildcard => true, + Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)), + _ => false, } - pat.iter_fields() - .for_each(|field_pat| collect_non_exhaustive_tys(tcx, field_pat, non_exhaustive_tys)) } /// Report that a match is not exhaustive. -fn non_exhaustive_match<'p, 'tcx>( +fn report_non_exhaustive_match<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, thir: &Thir<'tcx>, scrut_ty: Ty<'tcx>, @@ -755,7 +806,14 @@ fn non_exhaustive_match<'p, 'tcx>( sp, format!("non-exhaustive patterns: {joined_patterns} not covered"), ); - err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); + err.span_label( + sp, + format!( + "pattern{} {} not covered", + rustc_errors::pluralize!(witnesses.len()), + joined_patterns + ), + ); patterns_len = witnesses.len(); pattern = if witnesses.len() < 4 { witnesses @@ -768,7 +826,17 @@ fn non_exhaustive_match<'p, 'tcx>( }; }; - adt_defined_here(cx, &mut err, scrut_ty, &witnesses); + // Point at the definition of non-covered `enum` variants. + if let Some(AdtDefinedHere { adt_def_span, ty, variants }) = + report_adt_defined_here(cx.tcx, scrut_ty, &witnesses, true) + { + let mut multi_span = MultiSpan::from_span(adt_def_span); + multi_span.push_span_label(adt_def_span, ""); + for Variant { span } in variants { + multi_span.push_span_label(span, "not covered"); + } + err.span_note(multi_span, format!("`{ty}` defined here")); + } err.note(format!("the matched value is of type `{}`", scrut_ty)); if !is_empty_match { @@ -910,7 +978,7 @@ fn non_exhaustive_match<'p, 'tcx>( err.emit() } -pub(crate) fn joined_uncovered_patterns<'p, 'tcx>( +fn joined_uncovered_patterns<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, witnesses: &[WitnessPat<'tcx>], ) -> String { @@ -931,48 +999,51 @@ pub(crate) fn joined_uncovered_patterns<'p, 'tcx>( } } -pub(crate) fn pattern_not_covered_label( - witnesses: &[WitnessPat<'_>], - joined_patterns: &str, -) -> String { - format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns) +fn collect_non_exhaustive_tys<'tcx>( + tcx: TyCtxt<'tcx>, + pat: &WitnessPat<'tcx>, + non_exhaustive_tys: &mut FxHashSet>, +) { + if matches!(pat.ctor(), Constructor::NonExhaustive) { + non_exhaustive_tys.insert(pat.ty()); + } + if let Constructor::IntRange(range) = pat.ctor() { + if range.is_beyond_boundaries(pat.ty(), tcx) { + // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`. + non_exhaustive_tys.insert(pat.ty()); + } + } + pat.iter_fields() + .for_each(|field_pat| collect_non_exhaustive_tys(tcx, field_pat, non_exhaustive_tys)) } -/// Point at the definition of non-covered `enum` variants. -fn adt_defined_here<'p, 'tcx>( - cx: &MatchCheckCtxt<'p, 'tcx>, - err: &mut Diagnostic, +fn report_adt_defined_here<'tcx>( + tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, witnesses: &[WitnessPat<'tcx>], -) { + point_at_non_local_ty: bool, +) -> Option> { let ty = ty.peel_refs(); - if let ty::Adt(def, _) = ty.kind() { - let mut spans = vec![]; - if witnesses.len() < 5 { - for sp in maybe_point_at_variant(cx, *def, witnesses.iter()) { - spans.push(sp); - } - } - let def_span = cx - .tcx - .hir() - .get_if_local(def.did()) - .and_then(|node| node.ident()) - .map(|ident| ident.span) - .unwrap_or_else(|| cx.tcx.def_span(def.did())); - let mut span: MultiSpan = - if spans.is_empty() { def_span.into() } else { spans.clone().into() }; - - span.push_span_label(def_span, ""); - for pat in spans { - span.push_span_label(pat, "not covered"); - } - err.span_note(span, format!("`{ty}` defined here")); + let ty::Adt(def, _) = ty.kind() else { + return None; + }; + let adt_def_span = + tcx.hir().get_if_local(def.did()).and_then(|node| node.ident()).map(|ident| ident.span); + let adt_def_span = if point_at_non_local_ty { + adt_def_span.unwrap_or_else(|| tcx.def_span(def.did())) + } else { + adt_def_span? + }; + + let mut variants = vec![]; + for span in maybe_point_at_variant(tcx, *def, witnesses.iter().take(5)) { + variants.push(Variant { span }); } + Some(AdtDefinedHere { adt_def_span, ty, variants }) } -fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( - cx: &MatchCheckCtxt<'p, 'tcx>, +fn maybe_point_at_variant<'a, 'tcx: 'a>( + tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, patterns: impl Iterator>, ) -> Vec { @@ -985,7 +1056,7 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( { continue; } - let sp = def.variant(*variant_index).ident(cx.tcx).span; + let sp = def.variant(*variant_index).ident(tcx).span; if covered.contains(&sp) { // Don't point at variants that have already been covered due to other patterns to avoid // visual clutter. @@ -993,112 +1064,7 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( } covered.push(sp); } - covered.extend(maybe_point_at_variant(cx, def, pattern.iter_fields())); + covered.extend(maybe_point_at_variant(tcx, def, pattern.iter_fields())); } covered } - -/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. -/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. -/// -/// For example, this would reject: -/// - `ref x @ Some(ref mut y)`, -/// - `ref mut x @ Some(ref y)`, -/// - `ref mut x @ Some(ref mut y)`, -/// - `ref mut? x @ Some(y)`, and -/// - `x @ Some(ref mut? y)`. -/// -/// This analysis is *not* subsumed by NLL. -fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>, pat: &Pat<'tcx>) { - // Extract `sub` in `binding @ sub`. - let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else { - return; - }; - - let is_binding_by_move = |ty: Ty<'tcx>| !ty.is_copy_modulo_regions(cx.tcx, cx.param_env); - - let sess = cx.tcx.sess; - - // Get the binding move, extract the mutability if by-ref. - let mut_outer = match mode { - BindingMode::ByValue if is_binding_by_move(ty) => { - // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. - let mut conflicts_ref = Vec::new(); - sub.each_binding(|_, mode, _, span| match mode { - BindingMode::ByValue => {} - BindingMode::ByRef(_) => conflicts_ref.push(span), - }); - if !conflicts_ref.is_empty() { - sess.emit_err(BorrowOfMovedValue { - binding_span: pat.span, - conflicts_ref, - name, - ty, - suggest_borrowing: Some(pat.span.shrink_to_lo()), - }); - } - return; - } - BindingMode::ByValue => return, - BindingMode::ByRef(m) => m.mutability(), - }; - - // We now have `ref $mut_outer binding @ sub` (semantically). - // Recurse into each binding in `sub` and find mutability or move conflicts. - let mut conflicts_move = Vec::new(); - let mut conflicts_mut_mut = Vec::new(); - let mut conflicts_mut_ref = Vec::new(); - sub.each_binding(|name, mode, ty, span| { - match mode { - BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) { - // Both sides are `ref`. - (Mutability::Not, Mutability::Not) => {} - // 2x `ref mut`. - (Mutability::Mut, Mutability::Mut) => { - conflicts_mut_mut.push(Conflict::Mut { span, name }) - } - (Mutability::Not, Mutability::Mut) => { - conflicts_mut_ref.push(Conflict::Mut { span, name }) - } - (Mutability::Mut, Mutability::Not) => { - conflicts_mut_ref.push(Conflict::Ref { span, name }) - } - }, - BindingMode::ByValue if is_binding_by_move(ty) => { - conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. - } - BindingMode::ByValue => {} // `ref mut?` + by-copy is fine. - } - }); - - let report_mut_mut = !conflicts_mut_mut.is_empty(); - let report_mut_ref = !conflicts_mut_ref.is_empty(); - let report_move_conflict = !conflicts_move.is_empty(); - - let mut occurrences = match mut_outer { - Mutability::Mut => vec![Conflict::Mut { span: pat.span, name }], - Mutability::Not => vec![Conflict::Ref { span: pat.span, name }], - }; - occurrences.extend(conflicts_mut_mut); - occurrences.extend(conflicts_mut_ref); - occurrences.extend(conflicts_move); - - // Report errors if any. - if report_mut_mut { - // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences }); - } else if report_mut_ref { - // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. - match mut_outer { - Mutability::Mut => { - sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences }); - } - Mutability::Not => { - sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences }); - } - }; - } else if report_move_conflict { - // Report by-ref and by-move conflicts, e.g. `ref x @ y`. - sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences }); - } -} diff --git a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr index 0807f4590298f..85426dd9a5ea6 100644 --- a/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr +++ b/tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr @@ -5,10 +5,10 @@ LL | let _b = || { match l1 { L1::A => () } }; | ^^ pattern `L1::B` not covered | note: `L1` defined here - --> $DIR/non-exhaustive-match.rs:12:14 + --> $DIR/non-exhaustive-match.rs:12:6 | LL | enum L1 { A, B } - | -- ^ not covered + | ^^ - not covered = note: the matched value is of type `L1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/error-codes/E0004.stderr b/tests/ui/error-codes/E0004.stderr index 603bc5237ea20..ced478d65eaec 100644 --- a/tests/ui/error-codes/E0004.stderr +++ b/tests/ui/error-codes/E0004.stderr @@ -5,12 +5,12 @@ LL | match x { | ^ pattern `Terminator::HastaLaVistaBaby` not covered | note: `Terminator` defined here - --> $DIR/E0004.rs:2:5 + --> $DIR/E0004.rs:1:6 | LL | enum Terminator { - | ---------- + | ^^^^^^^^^^ LL | HastaLaVistaBaby, - | ^^^^^^^^^^^^^^^^ not covered + | ---------------- not covered = note: the matched value is of type `Terminator` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr index eb61c4cf159ab..8af0eedc82b1a 100644 --- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr +++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr @@ -134,13 +134,13 @@ LL | match Foo::A { | ^^^^^^ pattern `Foo::C` not covered | note: `Foo` defined here - --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:16:9 + --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:10 | LL | enum Foo { - | --- + | ^^^ ... LL | C, - | ^ not covered + | - not covered = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/match/match_non_exhaustive.stderr b/tests/ui/match/match_non_exhaustive.stderr index 7b8bdfe0053ae..40be39ec07747 100644 --- a/tests/ui/match/match_non_exhaustive.stderr +++ b/tests/ui/match/match_non_exhaustive.stderr @@ -5,10 +5,10 @@ LL | match l { L::A => () }; | ^ pattern `L::B` not covered | note: `L` defined here - --> $DIR/match_non_exhaustive.rs:10:13 + --> $DIR/match_non_exhaustive.rs:10:6 | LL | enum L { A, B } - | - ^ not covered + | ^ - not covered = note: the matched value is of type `L` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/issue-94866.stderr b/tests/ui/pattern/issue-94866.stderr index b3c17ce8974df..dee4b3f557c7d 100644 --- a/tests/ui/pattern/issue-94866.stderr +++ b/tests/ui/pattern/issue-94866.stderr @@ -5,10 +5,10 @@ LL | match Enum::A { | ^^^^^^^ pattern `Enum::B` not covered | note: `Enum` defined here - --> $DIR/issue-94866.rs:7:16 + --> $DIR/issue-94866.rs:7:6 | LL | enum Enum { A, B } - | ---- ^ not covered + | ^^^^ - not covered = note: the matched value is of type `Enum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.rs b/tests/ui/pattern/usefulness/conflicting_bindings.rs new file mode 100644 index 0000000000000..0b3e7ce9e9a0f --- /dev/null +++ b/tests/ui/pattern/usefulness/conflicting_bindings.rs @@ -0,0 +1,24 @@ +#![feature(if_let_guard, let_chains)] + +fn main() { + let mut x = Some(String::new()); + let ref mut y @ ref mut z = x; + //~^ ERROR: mutable more than once + let Some(ref mut y @ ref mut z) = x else { return }; + //~^ ERROR: mutable more than once + if let Some(ref mut y @ ref mut z) = x {} + //~^ ERROR: mutable more than once + if let Some(ref mut y @ ref mut z) = x && true {} + //~^ ERROR: mutable more than once + while let Some(ref mut y @ ref mut z) = x {} + //~^ ERROR: mutable more than once + while let Some(ref mut y @ ref mut z) = x && true {} + //~^ ERROR: mutable more than once + match x { + ref mut y @ ref mut z => {} //~ ERROR: mutable more than once + } + match () { + () if let Some(ref mut y @ ref mut z) = x => {} //~ ERROR: mutable more than once + _ => {} + } +} diff --git a/tests/ui/pattern/usefulness/conflicting_bindings.stderr b/tests/ui/pattern/usefulness/conflicting_bindings.stderr new file mode 100644 index 0000000000000..679fc83e7f563 --- /dev/null +++ b/tests/ui/pattern/usefulness/conflicting_bindings.stderr @@ -0,0 +1,66 @@ +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:5:9 + | +LL | let ref mut y @ ref mut z = x; + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:7:14 + | +LL | let Some(ref mut y @ ref mut z) = x else { return }; + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:9:17 + | +LL | if let Some(ref mut y @ ref mut z) = x {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:11:17 + | +LL | if let Some(ref mut y @ ref mut z) = x && true {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:13:20 + | +LL | while let Some(ref mut y @ ref mut z) = x {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:15:20 + | +LL | while let Some(ref mut y @ ref mut z) = x && true {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:18:9 + | +LL | ref mut y @ ref mut z => {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: cannot borrow value as mutable more than once at a time + --> $DIR/conflicting_bindings.rs:21:24 + | +LL | () if let Some(ref mut y @ ref mut z) = x => {} + | ^^^^^^^^^ --------- value is mutably borrowed by `z` here + | | + | value is mutably borrowed by `y` here + +error: aborting due to 8 previous errors + diff --git a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr index ff29de03d6b36..24f3eaa5230d7 100644 --- a/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr +++ b/tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr @@ -23,13 +23,13 @@ LL | match HiddenEnum::A { | ^^^^^^^^^^^^^ pattern `HiddenEnum::B` not covered | note: `HiddenEnum` defined here - --> $DIR/auxiliary/hidden.rs:3:5 + --> $DIR/auxiliary/hidden.rs:1:1 | LL | pub enum HiddenEnum { - | ------------------- + | ^^^^^^^^^^^^^^^^^^^ LL | A, LL | B, - | ^ not covered + | - not covered = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -44,13 +44,13 @@ LL | match HiddenEnum::A { | ^^^^^^^^^^^^^ patterns `HiddenEnum::B` and `_` not covered | note: `HiddenEnum` defined here - --> $DIR/auxiliary/hidden.rs:3:5 + --> $DIR/auxiliary/hidden.rs:1:1 | LL | pub enum HiddenEnum { - | ------------------- + | ^^^^^^^^^^^^^^^^^^^ LL | A, LL | B, - | ^ not covered + | - not covered = note: the matched value is of type `HiddenEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -83,13 +83,13 @@ LL | match InCrate::A { | ^^^^^^^^^^ pattern `InCrate::C` not covered | note: `InCrate` defined here - --> $DIR/doc-hidden-non-exhaustive.rs:11:5 + --> $DIR/doc-hidden-non-exhaustive.rs:7:6 | LL | enum InCrate { - | ------- + | ^^^^^^^ ... LL | C, - | ^ not covered + | - not covered = note: the matched value is of type `InCrate` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr index 5b81a8c3d3c02..8f9bd5bde89aa 100644 --- a/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/empty-match.rs:58:9 + --> $DIR/empty-match.rs:68:9 | LL | _ => {}, | ^ @@ -11,25 +11,25 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:61:9 + --> $DIR/empty-match.rs:71:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:68:9 + --> $DIR/empty-match.rs:78:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:71:9 + --> $DIR/empty-match.rs:81:9 | LL | _ if false => {}, | ^ error[E0005]: refutable pattern in local binding - --> $DIR/empty-match.rs:76:9 + --> $DIR/empty-match.rs:86:9 | LL | let None = x; | ^^^^ pattern `Some(_)` not covered @@ -44,19 +44,19 @@ LL | if let None = x { todo!() }; | ++ +++++++++++ error: unreachable pattern - --> $DIR/empty-match.rs:88:9 + --> $DIR/empty-match.rs:98:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:91:9 + --> $DIR/empty-match.rs:101:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:109:20 + --> $DIR/empty-match.rs:119:20 | LL | match_no_arms!(0u8); | ^^^ @@ -65,7 +65,7 @@ LL | match_no_arms!(0u8); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty - --> $DIR/empty-match.rs:111:20 + --> $DIR/empty-match.rs:121:20 | LL | match_no_arms!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL | struct NonEmptyStruct1; = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty - --> $DIR/empty-match.rs:113:20 + --> $DIR/empty-match.rs:123:20 | LL | match_no_arms!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ LL | struct NonEmptyStruct2(bool); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:115:20 + --> $DIR/empty-match.rs:125:20 | LL | match_no_arms!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | union NonEmptyUnion1 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/empty-match.rs:117:20 + --> $DIR/empty-match.rs:127:20 | LL | match_no_arms!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,42 +121,44 @@ LL | union NonEmptyUnion2 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:119:20 + --> $DIR/empty-match.rs:129:20 | LL | match_no_arms!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:33:5 + --> $DIR/empty-match.rs:32:6 | LL | enum NonEmptyEnum1 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum1` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:122:20 + --> $DIR/empty-match.rs:132:20 | LL | match_no_arms!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:40:5 + --> $DIR/empty-match.rs:39:6 | LL | enum NonEmptyEnum2 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered ... LL | Bar, - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:125:20 + --> $DIR/empty-match.rs:135:20 | LL | match_no_arms!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered @@ -166,11 +168,19 @@ note: `NonEmptyEnum5` defined here | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ +... +LL | V1, V2, V3, V4, V5, + | -- -- -- -- -- not covered + | | | | | + | | | | not covered + | | | not covered + | | not covered + | not covered = note: the matched value is of type `NonEmptyEnum5` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/empty-match.rs:129:24 + --> $DIR/empty-match.rs:139:24 | LL | match_guarded_arm!(0u8); | ^^^ pattern `_` not covered @@ -184,7 +194,7 @@ LL + _ => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered - --> $DIR/empty-match.rs:134:24 + --> $DIR/empty-match.rs:144:24 | LL | match_guarded_arm!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered @@ -203,7 +213,7 @@ LL + NonEmptyStruct1 => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered - --> $DIR/empty-match.rs:139:24 + --> $DIR/empty-match.rs:149:24 | LL | match_guarded_arm!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered @@ -222,7 +232,7 @@ LL + NonEmptyStruct2(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:144:24 + --> $DIR/empty-match.rs:154:24 | LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered @@ -241,7 +251,7 @@ LL + NonEmptyUnion1 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/empty-match.rs:149:24 + --> $DIR/empty-match.rs:159:24 | LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered @@ -260,18 +270,19 @@ LL + NonEmptyUnion2 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:154:24 + --> $DIR/empty-match.rs:164:24 | LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:33:5 + --> $DIR/empty-match.rs:32:6 | LL | enum NonEmptyEnum1 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum1` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown @@ -281,21 +292,22 @@ LL + NonEmptyEnum1::Foo(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:159:24 + --> $DIR/empty-match.rs:169:24 | LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:40:5 + --> $DIR/empty-match.rs:39:6 | LL | enum NonEmptyEnum2 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered ... LL | Bar, - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum2` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms @@ -305,7 +317,7 @@ LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:164:24 + --> $DIR/empty-match.rs:174:24 | LL | match_guarded_arm!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered @@ -315,6 +327,14 @@ note: `NonEmptyEnum5` defined here | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ +... +LL | V1, V2, V3, V4, V5, + | -- -- -- -- -- not covered + | | | | | + | | | | not covered + | | | not covered + | | not covered + | not covered = note: the matched value is of type `NonEmptyEnum5` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms diff --git a/tests/ui/pattern/usefulness/empty-match.normal.stderr b/tests/ui/pattern/usefulness/empty-match.normal.stderr index 6d17455086beb..7f0389f40e233 100644 --- a/tests/ui/pattern/usefulness/empty-match.normal.stderr +++ b/tests/ui/pattern/usefulness/empty-match.normal.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/empty-match.rs:58:9 + --> $DIR/empty-match.rs:68:9 | LL | _ => {}, | ^ @@ -11,25 +11,25 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:61:9 + --> $DIR/empty-match.rs:71:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:68:9 + --> $DIR/empty-match.rs:78:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:71:9 + --> $DIR/empty-match.rs:81:9 | LL | _ if false => {}, | ^ error[E0005]: refutable pattern in local binding - --> $DIR/empty-match.rs:76:9 + --> $DIR/empty-match.rs:86:9 | LL | let None = x; | ^^^^ pattern `Some(_)` not covered @@ -43,19 +43,19 @@ LL | if let None = x { todo!() }; | ++ +++++++++++ error: unreachable pattern - --> $DIR/empty-match.rs:88:9 + --> $DIR/empty-match.rs:98:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:91:9 + --> $DIR/empty-match.rs:101:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:109:20 + --> $DIR/empty-match.rs:119:20 | LL | match_no_arms!(0u8); | ^^^ @@ -64,7 +64,7 @@ LL | match_no_arms!(0u8); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty - --> $DIR/empty-match.rs:111:20 + --> $DIR/empty-match.rs:121:20 | LL | match_no_arms!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ @@ -78,7 +78,7 @@ LL | struct NonEmptyStruct1; = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty - --> $DIR/empty-match.rs:113:20 + --> $DIR/empty-match.rs:123:20 | LL | match_no_arms!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | struct NonEmptyStruct2(bool); = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:115:20 + --> $DIR/empty-match.rs:125:20 | LL | match_no_arms!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | union NonEmptyUnion1 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty - --> $DIR/empty-match.rs:117:20 + --> $DIR/empty-match.rs:127:20 | LL | match_no_arms!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,42 +120,44 @@ LL | union NonEmptyUnion2 { = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:119:20 + --> $DIR/empty-match.rs:129:20 | LL | match_no_arms!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:33:5 + --> $DIR/empty-match.rs:32:6 | LL | enum NonEmptyEnum1 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum1` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:122:20 + --> $DIR/empty-match.rs:132:20 | LL | match_no_arms!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:40:5 + --> $DIR/empty-match.rs:39:6 | LL | enum NonEmptyEnum2 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered ... LL | Bar, - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:125:20 + --> $DIR/empty-match.rs:135:20 | LL | match_no_arms!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered @@ -165,11 +167,19 @@ note: `NonEmptyEnum5` defined here | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ +... +LL | V1, V2, V3, V4, V5, + | -- -- -- -- -- not covered + | | | | | + | | | | not covered + | | | not covered + | | not covered + | not covered = note: the matched value is of type `NonEmptyEnum5` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/empty-match.rs:129:24 + --> $DIR/empty-match.rs:139:24 | LL | match_guarded_arm!(0u8); | ^^^ pattern `_` not covered @@ -183,7 +193,7 @@ LL + _ => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered - --> $DIR/empty-match.rs:134:24 + --> $DIR/empty-match.rs:144:24 | LL | match_guarded_arm!(NonEmptyStruct1); | ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` not covered @@ -202,7 +212,7 @@ LL + NonEmptyStruct1 => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered - --> $DIR/empty-match.rs:139:24 + --> $DIR/empty-match.rs:149:24 | LL | match_guarded_arm!(NonEmptyStruct2(true)); | ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` not covered @@ -221,7 +231,7 @@ LL + NonEmptyStruct2(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:144:24 + --> $DIR/empty-match.rs:154:24 | LL | match_guarded_arm!((NonEmptyUnion1 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered @@ -240,7 +250,7 @@ LL + NonEmptyUnion1 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered - --> $DIR/empty-match.rs:149:24 + --> $DIR/empty-match.rs:159:24 | LL | match_guarded_arm!((NonEmptyUnion2 { foo: () })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered @@ -259,18 +269,19 @@ LL + NonEmptyUnion2 { .. } => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered - --> $DIR/empty-match.rs:154:24 + --> $DIR/empty-match.rs:164:24 | LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here - --> $DIR/empty-match.rs:33:5 + --> $DIR/empty-match.rs:32:6 | LL | enum NonEmptyEnum1 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum1` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown @@ -280,21 +291,22 @@ LL + NonEmptyEnum1::Foo(_) => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered - --> $DIR/empty-match.rs:159:24 + --> $DIR/empty-match.rs:169:24 | LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here - --> $DIR/empty-match.rs:40:5 + --> $DIR/empty-match.rs:39:6 | LL | enum NonEmptyEnum2 { - | ------------- + | ^^^^^^^^^^^^^ +... LL | Foo(bool), - | ^^^ not covered + | --- not covered ... LL | Bar, - | ^^^ not covered + | --- not covered = note: the matched value is of type `NonEmptyEnum2` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms @@ -304,7 +316,7 @@ LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered - --> $DIR/empty-match.rs:164:24 + --> $DIR/empty-match.rs:174:24 | LL | match_guarded_arm!(NonEmptyEnum5::V1); | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered @@ -314,6 +326,14 @@ note: `NonEmptyEnum5` defined here | LL | enum NonEmptyEnum5 { | ^^^^^^^^^^^^^ +... +LL | V1, V2, V3, V4, V5, + | -- -- -- -- -- not covered + | | | | | + | | | | not covered + | | | not covered + | | not covered + | not covered = note: the matched value is of type `NonEmptyEnum5` = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms diff --git a/tests/ui/pattern/usefulness/empty-match.rs b/tests/ui/pattern/usefulness/empty-match.rs index d56d2e3c817ce..fe5d0bce14fe3 100644 --- a/tests/ui/pattern/usefulness/empty-match.rs +++ b/tests/ui/pattern/usefulness/empty-match.rs @@ -30,17 +30,17 @@ union NonEmptyUnion2 { bar: (), } enum NonEmptyEnum1 { - Foo(bool), //~^ NOTE `NonEmptyEnum1` defined here //~| NOTE `NonEmptyEnum1` defined here - //~| NOTE not covered + Foo(bool), + //~^ NOTE not covered //~| NOTE not covered } enum NonEmptyEnum2 { - Foo(bool), //~^ NOTE `NonEmptyEnum2` defined here //~| NOTE `NonEmptyEnum2` defined here - //~| NOTE not covered + Foo(bool), + //~^ NOTE not covered //~| NOTE not covered Bar, //~^ NOTE not covered @@ -50,6 +50,16 @@ enum NonEmptyEnum5 { //~^ NOTE `NonEmptyEnum5` defined here //~| NOTE `NonEmptyEnum5` defined here V1, V2, V3, V4, V5, + //~^ NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered + //~| NOTE not covered } fn empty_enum(x: EmptyEnum) { diff --git a/tests/ui/pattern/usefulness/issue-35609.stderr b/tests/ui/pattern/usefulness/issue-35609.stderr index 6d5e2f410bc97..9feedfde4697a 100644 --- a/tests/ui/pattern/usefulness/issue-35609.stderr +++ b/tests/ui/pattern/usefulness/issue-35609.stderr @@ -107,6 +107,9 @@ LL | match Some(A) { | 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: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | diff --git a/tests/ui/pattern/usefulness/issue-39362.stderr b/tests/ui/pattern/usefulness/issue-39362.stderr index b8b17918aef8c..8dc534916061b 100644 --- a/tests/ui/pattern/usefulness/issue-39362.stderr +++ b/tests/ui/pattern/usefulness/issue-39362.stderr @@ -5,12 +5,12 @@ LL | match f { | ^ patterns `Foo::Bar { bar: Bar::C, .. }`, `Foo::Bar { bar: Bar::D, .. }`, `Foo::Bar { bar: Bar::E, .. }` and 1 more not covered | note: `Foo` defined here - --> $DIR/issue-39362.rs:2:5 + --> $DIR/issue-39362.rs:1:6 | LL | enum Foo { - | --- + | ^^^ LL | Bar { bar: Bar, id: usize } - | ^^^ not covered + | --- not covered = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | diff --git a/tests/ui/pattern/usefulness/issue-40221.stderr b/tests/ui/pattern/usefulness/issue-40221.stderr index 4973e42b05447..40b42af26b347 100644 --- a/tests/ui/pattern/usefulness/issue-40221.stderr +++ b/tests/ui/pattern/usefulness/issue-40221.stderr @@ -5,12 +5,12 @@ LL | match proto { | ^^^^^ pattern `P::C(PC::QA)` not covered | note: `P` defined here - --> $DIR/issue-40221.rs:2:5 + --> $DIR/issue-40221.rs:1:6 | LL | enum P { - | - + | ^ LL | C(PC), - | ^ not covered + | - not covered = note: the matched value is of type `P` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/issue-56379.stderr b/tests/ui/pattern/usefulness/issue-56379.stderr index b3e40b992399a..50e13bdfdfede 100644 --- a/tests/ui/pattern/usefulness/issue-56379.stderr +++ b/tests/ui/pattern/usefulness/issue-56379.stderr @@ -5,16 +5,16 @@ LL | match Foo::A(true) { | ^^^^^^^^^^^^ patterns `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered | note: `Foo` defined here - --> $DIR/issue-56379.rs:2:5 + --> $DIR/issue-56379.rs:1:6 | LL | enum Foo { - | --- + | ^^^ LL | A(bool), - | ^ not covered + | - not covered LL | B(bool), - | ^ not covered + | - not covered LL | C(bool), - | ^ not covered + | - not covered = note: the matched value is of type `Foo` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs index 5145f769075d9..1d1ea8e496466 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs @@ -1,10 +1,15 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] // Test the "defined here" and "not covered" diagnostic hints. // We also make sure that references are peeled off from the scrutinee type // so that the diagnostics work better with default binding modes. #[derive(Clone)] enum E { - //~^ NOTE + //~^ NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE `E` defined here + //~| NOTE //~| NOTE //~| NOTE //~| NOTE @@ -12,10 +17,7 @@ enum E { //~| NOTE A, B, - //~^ NOTE `E` defined here - //~| NOTE `E` defined here - //~| NOTE `E` defined here - //~| NOTE not covered + //~^ NOTE not covered //~| NOTE not covered //~| NOTE not covered //~| NOTE not covered @@ -79,12 +81,12 @@ fn by_ref_thrice(e: & &mut &E) { } enum Opt { - //~^ NOTE + //~^ NOTE `Opt` defined here + //~| NOTE //~| NOTE Some(u8), None, - //~^ NOTE `Opt` defined here - //~| NOTE not covered + //~^ NOTE not covered //~| NOTE not covered } diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr index 8489e2f14b871..a9e55fa53a68e 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -1,20 +1,20 @@ error[E0004]: non-exhaustive patterns: `E::B` and `E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:35:11 + --> $DIR/non-exhaustive-defined-here.rs:37:11 | LL | match e1 { | ^^ patterns `E::B` and `E::C` not covered | note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:8: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: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -23,7 +23,7 @@ LL + E::B | E::C => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/non-exhaustive-defined-here.rs:41:9 + --> $DIR/non-exhaustive-defined-here.rs:43:9 | LL | let E::A = e; | ^^^^ patterns `E::B` and `E::C` not covered @@ -31,7 +31,7 @@ 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:6:6 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { | ^ @@ -48,22 +48,22 @@ 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:50:11 + --> $DIR/non-exhaustive-defined-here.rs:52:11 | LL | match e { | ^ patterns `&E::B` and `&E::C` not covered | note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:8: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: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -72,7 +72,7 @@ LL + &E::B | &E::C => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/non-exhaustive-defined-here.rs:57:9 + --> $DIR/non-exhaustive-defined-here.rs:59:9 | LL | let E::A = e; | ^^^^ patterns `&E::B` and `&E::C` not covered @@ -80,7 +80,7 @@ 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:6:6 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { | ^ @@ -97,22 +97,22 @@ LL | if let E::A = e { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered - --> $DIR/non-exhaustive-defined-here.rs:66:11 + --> $DIR/non-exhaustive-defined-here.rs:68:11 | LL | match e { | ^ patterns `&&mut &E::B` and `&&mut &E::C` not covered | note: `E` defined here - --> $DIR/non-exhaustive-defined-here.rs:14:5 + --> $DIR/non-exhaustive-defined-here.rs:8: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: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -121,7 +121,7 @@ LL + &&mut &E::B | &&mut &E::C => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/non-exhaustive-defined-here.rs:73:9 + --> $DIR/non-exhaustive-defined-here.rs:75:9 | LL | let E::A = e; | ^^^^ patterns `&&mut &E::B` and `&&mut &E::C` not covered @@ -129,7 +129,7 @@ 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:6:6 + --> $DIR/non-exhaustive-defined-here.rs:8:6 | LL | enum E { | ^ @@ -146,19 +146,19 @@ LL | if let E::A = e { todo!() }; | ++ +++++++++++ error[E0004]: non-exhaustive patterns: `Opt::None` not covered - --> $DIR/non-exhaustive-defined-here.rs:92:11 + --> $DIR/non-exhaustive-defined-here.rs:94:11 | LL | match e { | ^ pattern `Opt::None` not covered | note: `Opt` defined here - --> $DIR/non-exhaustive-defined-here.rs:85:5 + --> $DIR/non-exhaustive-defined-here.rs:83:6 | LL | enum Opt { - | --- + | ^^^ ... LL | None, - | ^^^^ not covered + | ---- not covered = note: the matched value is of type `Opt` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -167,7 +167,7 @@ LL + Opt::None => todo!() | error[E0005]: refutable pattern in local binding - --> $DIR/non-exhaustive-defined-here.rs:99:9 + --> $DIR/non-exhaustive-defined-here.rs:101:9 | LL | let Opt::Some(ref _x) = e; | ^^^^^^^^^^^^^^^^^ pattern `Opt::None` not covered @@ -175,7 +175,7 @@ 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:81:6 + --> $DIR/non-exhaustive-defined-here.rs:83:6 | LL | enum Opt { | ^^^ diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr index 98e417a17f860..310049fe13ec1 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-match-nested.stderr @@ -18,10 +18,10 @@ LL | match x { | ^ pattern `T::A(U::C)` not covered | note: `T` defined here - --> $DIR/non-exhaustive-match-nested.rs:1:10 + --> $DIR/non-exhaustive-match-nested.rs:1:6 | LL | enum T { A(U), B } - | - ^ not covered + | ^ - not covered = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr index e59e8885e1a48..4bebd3cbbefd0 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -5,10 +5,10 @@ LL | match x { T::B => { } } | ^ pattern `T::A` not covered | note: `T` defined here - --> $DIR/non-exhaustive-match.rs:3:10 + --> $DIR/non-exhaustive-match.rs:3:6 | LL | enum T { A, B } - | - ^ not covered + | ^ - not covered = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -79,10 +79,10 @@ LL | match T::A { | ^^^^ pattern `T::B` not covered | note: `T` defined here - --> $DIR/non-exhaustive-match.rs:3:13 + --> $DIR/non-exhaustive-match.rs:3:6 | LL | enum T { A, B } - | - ^ not covered + | ^ - not covered = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr index f914b98d9231f..cceb1d8f65ddb 100644 --- a/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr +++ b/tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr @@ -23,12 +23,12 @@ LL | match Color::Red { | ^^^^^^^^^^ pattern `Color::Red` not covered | note: `Color` defined here - --> $DIR/non-exhaustive-pattern-witness.rs:17:5 + --> $DIR/non-exhaustive-pattern-witness.rs:16:6 | LL | enum Color { - | ----- + | ^^^^^ LL | Red, - | ^^^ not covered + | --- not covered = note: the matched value is of type `Color` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | @@ -43,17 +43,17 @@ LL | match Direction::North { | ^^^^^^^^^^^^^^^^ patterns `Direction::East`, `Direction::South` and `Direction::West` not covered | note: `Direction` defined here - --> $DIR/non-exhaustive-pattern-witness.rs:32:5 + --> $DIR/non-exhaustive-pattern-witness.rs:30:6 | LL | enum Direction { - | --------- + | ^^^^^^^^^ LL | North, LL | East, - | ^^^^ not covered + | ---- not covered LL | South, - | ^^^^^ not covered + | ----- not covered LL | West, - | ^^^^ not covered + | ---- not covered = note: the matched value is of type `Direction` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -72,6 +72,17 @@ note: `ExcessiveEnum` defined here | LL | enum ExcessiveEnum { | ^^^^^^^^^^^^^ +LL | First, +LL | Second, + | ------ not covered +LL | Third, + | ----- not covered +LL | Fourth, + | ------ not covered +LL | Fifth, + | ----- not covered +LL | Sixth, + | ----- not covered = note: the matched value is of type `ExcessiveEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms | @@ -86,13 +97,13 @@ LL | match Color::Red { | ^^^^^^^^^^ pattern `Color::CustomRGBA { a: true, .. }` not covered | note: `Color` defined here - --> $DIR/non-exhaustive-pattern-witness.rs:19:5 + --> $DIR/non-exhaustive-pattern-witness.rs:16:6 | LL | enum Color { - | ----- + | ^^^^^ ... LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }, - | ^^^^^^^^^^ not covered + | ---------- not covered = note: the matched value is of type `Color` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr index f944c25a905c4..f75517fb7910d 100644 --- a/tests/ui/pattern/usefulness/stable-gated-patterns.stderr +++ b/tests/ui/pattern/usefulness/stable-gated-patterns.stderr @@ -5,13 +5,13 @@ LL | match UnstableEnum::Stable { | ^^^^^^^^^^^^^^^^^^^^ patterns `UnstableEnum::Stable2` and `_` not covered | note: `UnstableEnum` defined here - --> $DIR/auxiliary/unstable.rs:9:5 + --> $DIR/auxiliary/unstable.rs:5:1 | LL | pub enum UnstableEnum { - | --------------------- + | ^^^^^^^^^^^^^^^^^^^^^ ... LL | Stable2, - | ^^^^^^^ not covered + | ------- not covered = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr index 22425aa0dd4dd..3d2b540a9f57a 100644 --- a/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr +++ b/tests/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr @@ -5,12 +5,12 @@ LL | match x { | ^ pattern `A::B { x: Some(_) }` not covered | note: `A` defined here - --> $DIR/struct-like-enum-nonexhaustive.rs:2:5 + --> $DIR/struct-like-enum-nonexhaustive.rs:1:6 | LL | enum A { - | - + | ^ LL | B { x: Option }, - | ^ not covered + | - not covered = note: the matched value is of type `A` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr index d776249b23181..4a4945156f73c 100644 --- a/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr +++ b/tests/ui/pattern/usefulness/unstable-gated-patterns.stderr @@ -5,13 +5,13 @@ LL | match UnstableEnum::Stable { | ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Unstable` not covered | note: `UnstableEnum` defined here - --> $DIR/auxiliary/unstable.rs:11:5 + --> $DIR/auxiliary/unstable.rs:5:1 | LL | pub enum UnstableEnum { - | --------------------- + | ^^^^^^^^^^^^^^^^^^^^^ ... LL | Unstable, - | ^^^^^^^^ not covered + | -------- not covered = note: the matched value is of type `UnstableEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr index de1bf8be8854e..7386f10a6fb2c 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -17,18 +17,18 @@ LL | match NonExhaustiveEnum::Unit {} | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered | note: `NonExhaustiveEnum` defined here - --> $DIR/enum_same_crate_empty_match.rs:5:5 + --> $DIR/enum_same_crate_empty_match.rs:4:10 | LL | pub enum NonExhaustiveEnum { - | ----------------- + | ^^^^^^^^^^^^^^^^^ LL | Unit, - | ^^^^ not covered + | ---- not covered LL | LL | Tuple(u32), - | ^^^^^ not covered + | ----- not covered LL | LL | Struct { field: u32 } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `NonExhaustiveEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | @@ -44,18 +44,18 @@ LL | match NormalEnum::Unit {} | ^^^^^^^^^^^^^^^^ patterns `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered | note: `NormalEnum` defined here - --> $DIR/enum_same_crate_empty_match.rs:14:5 + --> $DIR/enum_same_crate_empty_match.rs:13:10 | LL | pub enum NormalEnum { - | ---------- + | ^^^^^^^^^^ LL | Unit, - | ^^^^ not covered + | ---- not covered LL | LL | Tuple(u32), - | ^^^^^ not covered + | ----- not covered LL | LL | Struct { field: u32 } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `NormalEnum` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr index a9c54af0418a5..c125756a646d5 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -62,14 +62,14 @@ LL | match x {} | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here - --> $DIR/auxiliary/uninhabited.rs:17:23 + --> $DIR/auxiliary/uninhabited.rs:16:1 | LL | pub enum UninhabitedVariants { - | ---------------------------- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | #[non_exhaustive] Tuple(!), - | ^^^^^ not covered + | ----- not covered LL | #[non_exhaustive] Struct { x: ! } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `UninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr index ec2a2f6f05531..7a12aca8520d3 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -43,14 +43,14 @@ LL | match x {} | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here - --> $DIR/match_same_crate.rs:16:23 + --> $DIR/match_same_crate.rs:15:10 | LL | pub enum UninhabitedVariants { - | ------------------- + | ^^^^^^^^^^^^^^^^^^^ LL | #[non_exhaustive] Tuple(!), - | ^^^^^ not covered + | ----- not covered LL | #[non_exhaustive] Struct { x: ! } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `UninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr index b6b777ec56c43..19e2546b0da88 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -62,14 +62,14 @@ LL | match x {} | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here - --> $DIR/auxiliary/uninhabited.rs:17:23 + --> $DIR/auxiliary/uninhabited.rs:16:1 | LL | pub enum UninhabitedVariants { - | ---------------------------- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | #[non_exhaustive] Tuple(!), - | ^^^^^ not covered + | ----- not covered LL | #[non_exhaustive] Struct { x: ! } - | ^^^^^^ not covered + | ------ not covered = note: the matched value is of type `UninhabitedVariants` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms |