diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6d44feec2c49..24fa127fccd7 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -88,9 +88,14 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_expr_let(e.span, pat, scrutinee) } ExprKind::If(ref cond, ref then, ref else_opt) => match cond.kind { - ExprKind::Let(ref pat, ref scrutinee) => { - self.lower_expr_if_let(e.span, pat, scrutinee, then, else_opt.as_deref()) - } + ExprKind::Let(ref pat, ref scrutinee) => self.lower_expr_if_let( + e.span, + pat, + scrutinee, + then, + else_opt.as_deref(), + cond.span, + ), _ => self.lower_expr_if(cond, then, else_opt.as_deref()), }, ExprKind::While(ref cond, ref body, opt_label) => self @@ -366,6 +371,7 @@ impl<'hir> LoweringContext<'_, 'hir> { scrutinee: &Expr, then: &Block, else_opt: Option<&Expr>, + let_span: Span, ) -> hir::ExprKind<'hir> { // FIXME(#53667): handle lowering of && and parens. @@ -384,7 +390,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let then_expr = self.lower_block_expr(then); let then_arm = self.arm(then_pat, self.arena.alloc(then_expr)); - let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause }; + let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause, let_span }; hir::ExprKind::Match(scrutinee, arena_vec![self; then_arm, else_arm], desugar) } @@ -420,7 +426,12 @@ impl<'hir> LoweringContext<'_, 'hir> { // } let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee)); let pat = self.lower_pat(pat); - (pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet) + ( + pat, + scrutinee, + hir::MatchSource::WhileLetDesugar { let_span: cond.span }, + hir::LoopSource::WhileLet, + ) } _ => { // We desugar: `'label: while $cond $body` into: @@ -521,7 +532,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let pat = self.lower_pat(&arm.pat); let guard = arm.guard.as_ref().map(|cond| { if let ExprKind::Let(ref pat, ref scrutinee) = cond.kind { - hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee)) + hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee), cond.span) } else { hir::Guard::If(self.lower_expr(cond)) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f4402843afcb..f83e756d3815 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1210,7 +1210,7 @@ pub struct Arm<'hir> { #[derive(Debug, HashStable_Generic)] pub enum Guard<'hir> { If(&'hir Expr<'hir>), - IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>), + IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>, Span), } #[derive(Debug, HashStable_Generic)] @@ -1879,14 +1879,14 @@ pub enum MatchSource { /// A `match _ { .. }`. Normal, /// An `if let _ = _ { .. }` (optionally with `else { .. }`). - IfLetDesugar { contains_else_clause: bool }, + IfLetDesugar { contains_else_clause: bool, let_span: Span }, /// An `if let _ = _ => { .. }` match guard. - IfLetGuardDesugar, + IfLetGuardDesugar { let_span: Span }, /// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`). WhileDesugar, /// A `while let _ = _ { .. }` (which was desugared to a /// `loop { match _ { .. } }`). - WhileLetDesugar, + WhileLetDesugar { let_span: Span }, /// A desugared `for _ in _ { .. }` loop. ForLoopDesugar, /// A desugared `?` operator. @@ -1895,13 +1895,33 @@ pub enum MatchSource { AwaitDesugar, } +impl MatchSource { + pub fn equivalent(&self, other: &Self) -> bool { + use MatchSource::*; + match (self, other) { + (Normal, Normal) + | (IfLetGuardDesugar { .. }, IfLetGuardDesugar { .. }) + | (WhileDesugar, WhileDesugar) + | (WhileLetDesugar { .. }, WhileLetDesugar { .. }) + | (ForLoopDesugar, ForLoopDesugar) + | (TryDesugar, TryDesugar) + | (AwaitDesugar, AwaitDesugar) => true, + ( + IfLetDesugar { contains_else_clause: l, .. }, + IfLetDesugar { contains_else_clause: r, .. }, + ) => l == r, + _ => false, + } + } +} + impl MatchSource { pub fn name(self) -> &'static str { use MatchSource::*; match self { Normal => "match", - IfLetDesugar { .. } | IfLetGuardDesugar => "if", - WhileDesugar | WhileLetDesugar => "while", + IfLetDesugar { .. } | IfLetGuardDesugar { .. } => "if", + WhileDesugar | WhileLetDesugar { .. } => "while", ForLoopDesugar => "for", TryDesugar => "?", AwaitDesugar => ".await", diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 6a2719c2d667..2bdeef7426b6 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1239,7 +1239,7 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { if let Some(ref g) = arm.guard { match g { Guard::If(ref e) => visitor.visit_expr(e), - Guard::IfLet(ref pat, ref e) => { + Guard::IfLet(ref pat, ref e, _) => { visitor.visit_pat(pat); visitor.visit_expr(e); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 416918e3344e..d9f26c88bf63 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2043,7 +2043,7 @@ impl<'a> State<'a> { self.print_expr(&e); self.s.space(); } - hir::Guard::IfLet(pat, e) => { + hir::Guard::IfLet(pat, e, _) => { self.word_nbsp("if"); self.word_nbsp("let"); self.print_pat(&pat); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 620ce360e7d9..c2d09cac023d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -781,7 +781,9 @@ fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'t pattern: cx.pattern_from_hir(&arm.pat), guard: arm.guard.as_ref().map(|g| match g { hir::Guard::If(ref e) => Guard::If(e.to_ref()), - hir::Guard::IfLet(ref pat, ref e) => Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()), + hir::Guard::IfLet(ref pat, ref e, _) => { + Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()) + } }), body: arm.body.to_ref(), lint_level: LintLevel::Explicit(arm.hir_id), 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 fdecbb947880..dc267701ca22 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -164,7 +164,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { for arm in arms { // Check the arm for some things unrelated to exhaustiveness. self.check_patterns(&arm.pat); - if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + if let Some(hir::Guard::IfLet(ref pat, _, _)) = arm.guard { self.check_patterns(pat); } } @@ -172,9 +172,9 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let mut cx = self.new_cx(scrut.hir_id); for arm in arms { - if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + if let Some(hir::Guard::IfLet(ref pat, _, span)) = arm.guard { let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; - check_if_let_guard(&mut cx, &tpat, pat.hir_id); + check_if_let_guard(&mut cx, &tpat, pat.hir_id, span); } } @@ -366,31 +366,38 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option< } fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) { - tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source { - hir::MatchSource::IfLetDesugar { .. } => { - let mut diag = lint.build("irrefutable `if let` pattern"); - diag.note("this pattern will always match, so the `if let` is useless"); - diag.help("consider replacing the `if let` with a `let`"); - diag.emit() - } - hir::MatchSource::WhileLetDesugar => { - let mut diag = lint.build("irrefutable `while let` pattern"); - diag.note("this pattern will always match, so the loop will never exit"); - diag.help("consider instead using a `loop { ... }` with a `let` inside it"); - diag.emit() - } - hir::MatchSource::IfLetGuardDesugar => { - let mut diag = lint.build("irrefutable `if let` guard pattern"); - diag.note("this pattern will always match, so the guard is useless"); - diag.help("consider removing the guard and adding a `let` inside the match arm"); - diag.emit() - } - _ => { - bug!( - "expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}", - source, - ) - } + tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| { + let mut diag = match source { + hir::MatchSource::IfLetDesugar { .. } => { + let mut diag = lint.build("irrefutable `if let` pattern"); + diag.span_label(span, "this pattern will always match, so the `if let` is useless"); + diag.help("consider replacing the `if let` with a `let`"); + diag + } + hir::MatchSource::WhileLetDesugar { .. } => { + let mut diag = lint.build("irrefutable `while let` pattern"); + diag.span_label(span, "this pattern will always match, so the loop will never exit"); + diag.help("consider instead using a `loop { ... }` with a `let` inside it"); + diag + } + hir::MatchSource::IfLetGuardDesugar { .. }=> { + let mut diag = lint.build("irrefutable `if let` guard pattern"); + diag.span_label(span, "this pattern will always match, so the guard is useless"); + diag.help("consider removing the guard and adding a `let` inside the match arm"); + diag + } + _ => { + bug!( + "expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}", + source, + ) + } + }; + diag.help( + "for more information, visit \ + ", + ); + diag.emit(); }); } @@ -398,14 +405,20 @@ fn check_if_let_guard<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, pat: &'p super::Pat<'tcx>, pat_id: HirId, + let_span: Span, ) { let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty); - report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar); + report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar { let_span }); if report.non_exhaustiveness_witnesses.is_empty() { - // The match is exhaustive, i.e. the `if let` pattern is irrefutable. - irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar) + // The match is exhaustive, i.e. the if let pattern is irrefutable. + irrefutable_let_pattern( + cx.tcx, + let_span, + pat_id, + hir::MatchSource::IfLetGuardDesugar { let_span }, + ) } } @@ -423,20 +436,21 @@ fn report_arm_reachability<'p, 'tcx>( match source { hir::MatchSource::WhileDesugar => bug!(), - hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => { + hir::MatchSource::IfLetDesugar { let_span, .. } + | hir::MatchSource::WhileLetDesugar { let_span } => { // Check which arm we're on. match arm_index { // The arm with the user-specified pattern. - 0 => unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None), + 0 => unreachable_pattern(cx.tcx, let_span, arm.hir_id, None), // The arm with the wildcard pattern. - 1 => irrefutable_let_pattern(cx.tcx, arm.pat.span, arm.hir_id, source), + 1 => irrefutable_let_pattern(cx.tcx, let_span, arm.hir_id, source), _ => bug!(), } } - hir::MatchSource::IfLetGuardDesugar => { + hir::MatchSource::IfLetGuardDesugar { let_span } => { assert_eq!(arm_index, 0); - unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None); + unreachable_pattern(cx.tcx, let_span, arm.hir_id, None); } hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index da713566c312..8bfbbb881468 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -45,11 +45,15 @@ impl NonConstExpr { return None; } - Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"), + Self::Match(IfLetGuardDesugar { .. }) => { + bug!("if-let guard outside a `match` expression") + } // All other expressions are allowed. Self::Loop(Loop | While | WhileLet) - | Self::Match(WhileDesugar | WhileLetDesugar | Normal | IfLetDesugar { .. }) => &[], + | Self::Match(WhileDesugar | WhileLetDesugar { .. } | Normal | IfLetDesugar { .. }) => { + &[] + } }; Some(gates) @@ -207,7 +211,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { let non_const_expr = match source { // These are handled by `ExprKind::Loop` above. hir::MatchSource::WhileDesugar - | hir::MatchSource::WhileLetDesugar + | hir::MatchSource::WhileLetDesugar { .. } | hir::MatchSource::ForLoopDesugar => None, _ => Some(NonConstExpr::Match(*source)), diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index c11dc231d482..e751d71c3a03 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -360,7 +360,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { self.add_from_pat(&arm.pat); - if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { + if let Some(hir::Guard::IfLet(ref pat, _, _)) = arm.guard { self.add_from_pat(pat); } intravisit::walk_arm(self, arm); @@ -891,7 +891,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let guard_succ = arm.guard.as_ref().map_or(body_succ, |g| match g { hir::Guard::If(e) => self.propagate_through_expr(e, body_succ), - hir::Guard::IfLet(pat, e) => { + hir::Guard::IfLet(pat, e, _) => { let let_bind = self.define_bindings_in_pat(pat, body_succ); self.propagate_through_expr(e, let_bind) } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 30e0e3eecd4a..f611329a30c5 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -134,7 +134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Guard::If(e) => { self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); } - hir::Guard::IfLet(pat, e) => { + hir::Guard::IfLet(pat, e, _) => { let scrutinee_ty = self.demand_scrutinee_type( e, pat.contains_explicit_ref_binding(), diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 91708465b3f6..21ed42127f86 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -248,7 +248,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { Guard::If(ref e) => { self.visit_expr(e); } - Guard::IfLet(ref pat, ref e) => { + Guard::IfLet(ref pat, ref e, _) => { self.visit_pat(pat); self.visit_expr(e); } diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr index 8586dfd91863..ac806e1f3be8 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/closure-origin-single-variant-diagnostics.stderr @@ -8,17 +8,14 @@ LL | #![feature(capture_disjoint_fields)] = note: see issue #53488 for more information warning: irrefutable `if let` pattern - --> $DIR/closure-origin-single-variant-diagnostics.rs:18:9 + --> $DIR/closure-origin-single-variant-diagnostics.rs:18:12 | -LL | / if let SingleVariant::Point(ref mut x, _) = point { -LL | | -LL | | *x += 1; -LL | | } - | |_________^ +LL | if let SingleVariant::Point(ref mut x, _) = point { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this pattern will always match, so the `if let` is useless | = note: `#[warn(irrefutable_let_patterns)]` on by default - = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` + = help: for more information, visit error[E0382]: use of moved value: `c` --> $DIR/closure-origin-single-variant-diagnostics.rs:25:13 diff --git a/src/test/ui/expr/if/if-let.stderr b/src/test/ui/expr/if/if-let.stderr index c64c9093ee54..52aba62b99c2 100644 --- a/src/test/ui/expr/if/if-let.stderr +++ b/src/test/ui/expr/if/if-let.stderr @@ -1,8 +1,8 @@ warning: irrefutable `if let` pattern - --> $DIR/if-let.rs:6:13 + --> $DIR/if-let.rs:6:16 | LL | if let $p = $e $b - | ^^^^^^^^^^^^^^^^^ + | ^^^ this pattern will always match, so the `if let` is useless ... LL | / foo!(a, 1, { LL | | println!("irrefutable pattern"); @@ -10,74 +10,60 @@ LL | | }); | |_______- in this macro invocation | = note: `#[warn(irrefutable_let_patterns)]` on by default - = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` + = help: for more information, visit = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `if let` pattern - --> $DIR/if-let.rs:6:13 + --> $DIR/if-let.rs:6:16 | LL | if let $p = $e $b - | ^^^^^^^^^^^^^^^^^ + | ^^^ this pattern will always match, so the `if let` is useless ... LL | / bar!(a, 1, { LL | | println!("irrefutable pattern"); LL | | }); | |_______- in this macro invocation | - = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` + = help: for more information, visit = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `if let` pattern - --> $DIR/if-let.rs:26:5 + --> $DIR/if-let.rs:26:8 | -LL | / if let a = 1 { -LL | | println!("irrefutable pattern"); -LL | | } - | |_____^ +LL | if let a = 1 { + | ^^^^^^^^^ this pattern will always match, so the `if let` is useless | - = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` + = help: for more information, visit warning: irrefutable `if let` pattern - --> $DIR/if-let.rs:30:5 + --> $DIR/if-let.rs:30:8 | -LL | / if let a = 1 { -LL | | println!("irrefutable pattern"); -LL | | } else if true { -LL | | println!("else-if in irrefutable `if let`"); -LL | | } else { -LL | | println!("else in irrefutable `if let`"); -LL | | } - | |_____^ +LL | if let a = 1 { + | ^^^^^^^^^ this pattern will always match, so the `if let` is useless | - = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` + = help: for more information, visit warning: irrefutable `if let` pattern - --> $DIR/if-let.rs:40:12 + --> $DIR/if-let.rs:40:15 | -LL | } else if let a = 1 { - | ____________^ -LL | | println!("irrefutable pattern"); -LL | | } - | |_____^ +LL | } else if let a = 1 { + | ^^^^^^^^^ this pattern will always match, so the `if let` is useless | - = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` + = help: for more information, visit warning: irrefutable `if let` pattern - --> $DIR/if-let.rs:46:12 + --> $DIR/if-let.rs:46:15 | -LL | } else if let a = 1 { - | ____________^ -LL | | println!("irrefutable pattern"); -LL | | } - | |_____^ +LL | } else if let a = 1 { + | ^^^^^^^^^ this pattern will always match, so the `if let` is useless | - = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` + = help: for more information, visit warning: 6 warnings emitted diff --git a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr index d6926ee12eea..a7e0651302cb 100644 --- a/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr +++ b/src/test/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr @@ -1,36 +1,34 @@ error: irrefutable `if let` pattern - --> $DIR/deny-irrefutable-let-patterns.rs:7:5 + --> $DIR/deny-irrefutable-let-patterns.rs:7:8 | LL | if let _ = 5 {} - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^ this pattern will always match, so the `if let` is useless | note: the lint level is defined here --> $DIR/deny-irrefutable-let-patterns.rs:4:9 | LL | #![deny(irrefutable_let_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` + = help: for more information, visit error: irrefutable `while let` pattern - --> $DIR/deny-irrefutable-let-patterns.rs:9:5 + --> $DIR/deny-irrefutable-let-patterns.rs:9:11 | -LL | / while let _ = 5 { -LL | | break; -LL | | } - | |_____^ +LL | while let _ = 5 { + | ^^^^^^^^^ this pattern will always match, so the loop will never exit | - = note: this pattern will always match, so the loop will never exit = help: consider instead using a `loop { ... }` with a `let` inside it + = help: for more information, visit error: irrefutable `if let` guard pattern - --> $DIR/deny-irrefutable-let-patterns.rs:14:18 + --> $DIR/deny-irrefutable-let-patterns.rs:14:14 | LL | _ if let _ = 2 => {} - | ^ + | ^^^^^^^^^ this pattern will always match, so the guard is useless | - = note: this pattern will always match, so the guard is useless = help: consider removing the guard and adding a `let` inside the match arm + = help: for more information, visit error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr index 8bfd6e91f4de..80d718e10ecd 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr @@ -17,22 +17,22 @@ LL | Some(_x) => (), | ^^^^^^^^ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:61:15 + --> $DIR/patterns_same_crate.rs:61:11 | LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:65:15 + --> $DIR/patterns_same_crate.rs:65:11 | LL | while let Some(_x) = uninhabited_struct() { - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/patterns_same_crate.rs:68:15 + --> $DIR/patterns_same_crate.rs:68:11 | LL | while let Some(_x) = uninhabited_tuple_struct() { - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/rfc-2294-if-let-guard/warns.stderr b/src/test/ui/rfc-2294-if-let-guard/warns.stderr index c7627f1c3c50..1ee5de944ac9 100644 --- a/src/test/ui/rfc-2294-if-let-guard/warns.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/warns.stderr @@ -1,16 +1,16 @@ error: irrefutable `if let` guard pattern - --> $DIR/warns.rs:7:24 + --> $DIR/warns.rs:7:20 | LL | Some(x) if let () = x => {} - | ^^ + | ^^^^^^^^^^ this pattern will always match, so the guard is useless | note: the lint level is defined here --> $DIR/warns.rs:4:8 | LL | #[deny(irrefutable_let_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this pattern will always match, so the guard is useless = help: consider removing the guard and adding a `let` inside the match arm + = help: for more information, visit error: unreachable pattern --> $DIR/warns.rs:16:25 diff --git a/src/test/ui/uninhabited/uninhabited-patterns.stderr b/src/test/ui/uninhabited/uninhabited-patterns.stderr index 655569ad6e08..518d44d60c4c 100644 --- a/src/test/ui/uninhabited/uninhabited-patterns.stderr +++ b/src/test/ui/uninhabited/uninhabited-patterns.stderr @@ -29,10 +29,10 @@ LL | Err(Ok(_y)) => (), | ^^^^^^^^^^^ error: unreachable pattern - --> $DIR/uninhabited-patterns.rs:44:15 + --> $DIR/uninhabited-patterns.rs:44:11 | LL | while let Some(_y) = foo() { - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/while-let.stderr b/src/test/ui/while-let.stderr index 04e77bf9470a..ff6f3121ac50 100644 --- a/src/test/ui/while-let.stderr +++ b/src/test/ui/while-let.stderr @@ -1,8 +1,8 @@ warning: irrefutable `while let` pattern - --> $DIR/while-let.rs:7:13 + --> $DIR/while-let.rs:7:19 | LL | while let $p = $e $b - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^ this pattern will always match, so the loop will never exit ... LL | / foo!(_a, 1, { LL | | println!("irrefutable pattern"); @@ -10,36 +10,33 @@ LL | | }); | |_______- in this macro invocation | = note: `#[warn(irrefutable_let_patterns)]` on by default - = note: this pattern will always match, so the loop will never exit = help: consider instead using a `loop { ... }` with a `let` inside it + = help: for more information, visit = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `while let` pattern - --> $DIR/while-let.rs:7:13 + --> $DIR/while-let.rs:7:19 | LL | while let $p = $e $b - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^ this pattern will always match, so the loop will never exit ... LL | / bar!(_a, 1, { LL | | println!("irrefutable pattern"); LL | | }); | |_______- in this macro invocation | - = note: this pattern will always match, so the loop will never exit = help: consider instead using a `loop { ... }` with a `let` inside it + = help: for more information, visit = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: irrefutable `while let` pattern - --> $DIR/while-let.rs:27:5 + --> $DIR/while-let.rs:27:11 | -LL | / while let _a = 1 { -LL | | println!("irrefutable pattern"); -LL | | break; -LL | | } - | |_____^ +LL | while let _a = 1 { + | ^^^^^^^^^^ this pattern will always match, so the loop will never exit | - = note: this pattern will always match, so the loop will never exit = help: consider instead using a `loop { ... }` with a `let` inside it + = help: for more information, visit warning: 3 warnings emitted diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs index 3c45525684be..732c928d7469 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs @@ -87,7 +87,7 @@ fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext let mut used_visitor = LocalUsedVisitor::new(cx, binding_id); if match arm.guard { None => true, - Some(Guard::If(expr) | Guard::IfLet(_, expr)) => !used_visitor.check_expr(expr), + Some(Guard::If(expr) | Guard::IfLet(_, expr, _)) => !used_visitor.check_expr(expr), }; // ...or anywhere in the inner match if !arms_inner.iter().any(|arm| used_visitor.check_arm(arm)); diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index 58511c6d57c6..4045ecc72f10 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -57,6 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { ref arms, MatchSource::IfLetDesugar { contains_else_clause: true, + .. }, ) = ex.kind { diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index 109d90ff772b..9ea632aabf19 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -92,6 +92,7 @@ fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) { let check_all_arms = match source { MatchSource::IfLetDesugar { contains_else_clause: has_else, + .. } => has_else, _ => true, }; diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 1c9373a756c8..97692c256eec 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -629,7 +629,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { } } } - if let ExprKind::Match(ref match_expr, ref arms, MatchSource::WhileLetDesugar) = expr.kind { + if let ExprKind::Match(ref match_expr, ref arms, MatchSource::WhileLetDesugar { .. }) = expr.kind { let pat = &arms[0].pat.kind; if let ( &PatKind::TupleStruct(ref qpath, ref pat_args, _), @@ -1994,7 +1994,9 @@ fn check_manual_flatten<'tcx>( if_chain! { if let Some(inner_expr) = inner_expr; if let ExprKind::Match( - ref match_expr, ref match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false } + ref match_expr, + ref match_arms, + MatchSource::IfLetDesugar { contains_else_clause: false, .. }, ) = inner_expr.kind; // Ensure match_expr in `if let` statement is the same as the pat from the for-loop if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index efc8b1394250..632c1c6c7f5b 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1627,7 +1627,7 @@ mod redundant_pattern_match { match match_source { MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms), MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "if"), - MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, arms, "while"), + MatchSource::WhileLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms, "while"), _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index 9ef0d267b0b2..fa03bfe9bc45 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -118,6 +118,7 @@ fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { arms, MatchSource::IfLetDesugar { contains_else_clause: true, + .. }, ), .. @@ -159,7 +160,7 @@ fn detect_option_if_let_else<'tcx>( ) -> Option { if_chain! { if !utils::in_macro(expr.span); // Don't lint macros, because it behaves weirdly - if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind; + if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{ contains_else_clause: true, .. }) = &expr.kind; if arms.len() == 2; if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 5539331d0460..6a2c055f427e 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Match(ref expr, arms, source) = expr.kind { match source { - MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => { + MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar { .. }=> { if let Some(expr_ty) = cx.typeck_results().node_type_opt(expr.hir_id) { 'pattern_checks: for arm in arms { let pat = &arm.pat; diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 6c480d48c756..4deb4faa6df7 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -97,7 +97,7 @@ impl QuestionMark { fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Match(subject, arms, source) = &expr.kind; - if *source == MatchSource::IfLetDesugar { contains_else_clause: true }; + if let MatchSource::IfLetDesugar { contains_else_clause: true, .. } = source; if Self::is_option(cx, subject); if let PatKind::TupleStruct(path1, fields, None) = &arms[0].pat.kind; diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index e438f92b136a..ab64f9af09a7 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -213,6 +213,7 @@ fn check_final_expr<'tcx>( }, MatchSource::IfLetDesugar { contains_else_clause: true, + .. } => { if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind { check_block_return(cx, ifblock); diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index 32f6bc74642c..aaf8cc378b99 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -349,7 +349,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut if let Some(ref guard) = arm.guard { match guard { Guard::If(if_expr) => check_expr(cx, if_expr, bindings), - Guard::IfLet(guard_pat, guard_expr) => { + Guard::IfLet(guard_pat, guard_expr, _) => { check_pat(cx, guard_pat, Some(*guard_expr), guard_pat.span, bindings); check_expr(cx, guard_expr, bindings); }, diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 6e3d4fde1077..ada55c3c703f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -365,11 +365,11 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = if_expr_pat; self.visit_expr(if_expr); }, - hir::Guard::IfLet(ref if_let_pat, ref if_let_expr) => { + hir::Guard::IfLet(ref if_let_pat, ref if_let_expr, _) => { let if_let_pat_pat = self.next("pat"); let if_let_expr_pat = self.next("expr"); println!( - " if let Guard::IfLet(ref {}, ref {}) = {};", + " if let Guard::IfLet(ref {}, ref {}, _) = {};", if_let_pat_pat, if_let_expr_pat, guard_pat ); self.current = if_let_expr_pat; @@ -729,13 +729,13 @@ fn desugaring_name(des: hir::MatchSource) -> String { hir::MatchSource::ForLoopDesugar => "MatchSource::ForLoopDesugar".to_string(), hir::MatchSource::TryDesugar => "MatchSource::TryDesugar".to_string(), hir::MatchSource::WhileDesugar => "MatchSource::WhileDesugar".to_string(), - hir::MatchSource::WhileLetDesugar => "MatchSource::WhileLetDesugar".to_string(), + hir::MatchSource::WhileLetDesugar { .. } => "MatchSource::WhileLetDesugar".to_string(), hir::MatchSource::Normal => "MatchSource::Normal".to_string(), - hir::MatchSource::IfLetDesugar { contains_else_clause } => format!( + hir::MatchSource::IfLetDesugar { contains_else_clause, .. } => format!( "MatchSource::IfLetDesugar {{ contains_else_clause: {} }}", contains_else_clause ), - hir::MatchSource::IfLetGuardDesugar => "MatchSource::IfLetGuardDesugar".to_string(), + hir::MatchSource::IfLetGuardDesugar { .. }=> "MatchSource::IfLetGuardDesugar".to_string(), hir::MatchSource::AwaitDesugar => "MatchSource::AwaitDesugar".to_string(), } } diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 9c1d98cd7074..195cf42aacce 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -568,7 +568,7 @@ fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) { println!("{}If", ind); print_expr(cx, expr, indent + 1); }, - hir::Guard::IfLet(pat, expr) => { + hir::Guard::IfLet(pat, expr, _) => { println!("{}IfLet", ind); print_pat(cx, pat, indent + 1); print_expr(cx, expr, indent + 1); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 81be9254cbe1..292c2b699b79 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -177,7 +177,7 @@ impl HirEqInterExpr<'_, '_, '_> { lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name) }, (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => { - ls == rs + ls.equivalent(rs) && self.eq_expr(le, re) && over(la, ra, |l, r| { self.eq_pat(&l.pat, &r.pat) @@ -223,7 +223,7 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool { match (left, right) { (Guard::If(l), Guard::If(r)) => self.eq_expr(l, r), - (Guard::IfLet(lp, le), Guard::IfLet(rp, re)) => self.eq_pat(lp, rp) && self.eq_expr(le, re), + (Guard::IfLet(lp, le, _), Guard::IfLet(rp, re, _)) => self.eq_pat(lp, rp) && self.eq_expr(le, re), _ => false, } } @@ -736,7 +736,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_guard(&mut self, g: &Guard<'_>) { match g { - Guard::If(ref expr) | Guard::IfLet(_, ref expr) => { + Guard::If(ref expr) | Guard::IfLet(_, ref expr, _) => { self.hash_expr(expr); }, }