From 407cb241422cd13ab01b0017fcf1ef6e49c80b1b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 21 Sep 2023 11:26:50 +0000 Subject: [PATCH 1/4] Remove `hir::Guard` Use Expr instead. Use `ExprKind::Let` to represent if let guards. --- compiler/rustc_ast_lowering/src/expr.rs | 15 +------ .../src/diagnostics/conflict_errors.rs | 2 +- compiler/rustc_hir/src/hir.rs | 22 +--------- compiler/rustc_hir/src/intravisit.rs | 9 +--- .../rustc_hir_analysis/src/check/region.rs | 3 +- compiler/rustc_hir_pretty/src/lib.rs | 14 ++---- compiler/rustc_hir_typeck/src/_match.rs | 11 +---- .../rustc_hir_typeck/src/expr_use_visitor.rs | 8 +--- .../rustc_mir_build/src/build/expr/into.rs | 4 +- .../rustc_mir_build/src/build/matches/mod.rs | 44 +++++++++++++++++-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 9 +--- compiler/rustc_passes/src/liveness.rs | 21 +++------ .../issue-88118-2.stderr | 4 +- tests/ui/lint/lint-match-arms-2.stderr | 4 +- .../deny-irrefutable-let-patterns.stderr | 4 +- .../rfcs/rfc-2294-if-let-guard/warns.stderr | 4 +- tests/ui/stats/hir-stats.stderr | 8 ++-- 17 files changed, 77 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index ba858d49acf..69704de105c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -546,20 +546,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> { let pat = self.lower_pat(&arm.pat); - let guard = arm.guard.as_ref().map(|cond| { - if let ExprKind::Let(pat, scrutinee, span, is_recovered) = &cond.kind { - hir::Guard::IfLet(self.arena.alloc(hir::Let { - hir_id: self.next_id(), - span: self.lower_span(*span), - pat: self.lower_pat(pat), - ty: None, - init: self.lower_expr(scrutinee), - is_recovered: *is_recovered, - })) - } else { - hir::Guard::If(self.lower_expr(cond)) - } - }); + let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); self.lower_attrs(hir_id, &arm.attrs); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index d824260f47c..9ce753134fb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3590,7 +3590,7 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { )); } else if let Some(guard) = &arm.guard { self.errors.push(( - arm.pat.span.to(guard.body().span), + arm.pat.span.to(guard.span), format!( "if this pattern and condition are matched, {} is not \ initialized", diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2c34fc13919..e88b876534e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1258,7 +1258,7 @@ pub struct Arm<'hir> { /// If this pattern and the optional guard matches, then `body` is evaluated. pub pat: &'hir Pat<'hir>, /// Optional guard clause. - pub guard: Option>, + pub guard: Option<&'hir Expr<'hir>>, /// The expression the arm evaluates to if this arm matches. pub body: &'hir Expr<'hir>, } @@ -1280,26 +1280,6 @@ pub struct Let<'hir> { pub is_recovered: Option, } -#[derive(Debug, Clone, Copy, HashStable_Generic)] -pub enum Guard<'hir> { - If(&'hir Expr<'hir>), - IfLet(&'hir Let<'hir>), -} - -impl<'hir> Guard<'hir> { - /// Returns the body of the guard - /// - /// In other words, returns the e in either of the following: - /// - /// - `if e` - /// - `if let x = e` - pub fn body(&self) -> &'hir Expr<'hir> { - match self { - Guard::If(e) | Guard::IfLet(Let { init: e, .. }) => e, - } - } -} - #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct ExprField<'hir> { #[stable_hasher(ignore)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e58e4c8fe0e..dd3633b6b4f 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -619,13 +619,8 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) { visitor.visit_id(arm.hir_id); visitor.visit_pat(arm.pat); - if let Some(ref g) = arm.guard { - match g { - Guard::If(ref e) => visitor.visit_expr(e), - Guard::IfLet(ref l) => { - visitor.visit_let_expr(l); - } - } + if let Some(ref e) = arm.guard { + visitor.visit_expr(e); } visitor.visit_expr(arm.body); } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index eab83c7a254..c3bdf94d30f 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -184,7 +184,8 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir visitor.enter_node_scope_with_dtor(arm.hir_id.local_id); visitor.cx.var_parent = visitor.cx.parent; - if let Some(hir::Guard::If(expr)) = arm.guard { + if let Some(expr) = arm.guard { + // Check for if?? visitor.terminating_scopes.insert(expr.hir_id.local_id); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index d6eea07cfbc..1eaec997053 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1874,17 +1874,9 @@ impl<'a> State<'a> { self.print_pat(arm.pat); self.space(); if let Some(ref g) = arm.guard { - match *g { - hir::Guard::If(e) => { - self.word_space("if"); - self.print_expr(e); - self.space(); - } - hir::Guard::IfLet(&hir::Let { pat, ty, init, .. }) => { - self.word_nbsp("if"); - self.print_let(pat, ty, init); - } - } + self.word_space("if"); + self.print_expr(g); + self.space(); } self.word_space("=>"); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 181de372840..cf1f232229d 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -78,16 +78,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut other_arms = vec![]; // Used only for diagnostics. let mut prior_arm = None; for arm in arms { - if let Some(g) = &arm.guard { + if let Some(e) = &arm.guard { self.diverges.set(Diverges::Maybe); - match g { - hir::Guard::If(e) => { - self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); - } - hir::Guard::IfLet(l) => { - self.check_expr_let(l); - } - }; + self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {}); } self.diverges.set(Diverges::Maybe); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index e952a7ff9e8..ed3dd1e39df 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -669,12 +669,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ); self.walk_pat(discr_place, arm.pat, arm.guard.is_some()); - match arm.guard { - Some(hir::Guard::If(e)) => self.consume_expr(e), - Some(hir::Guard::IfLet(l)) => { - self.walk_local(l.init, l.pat, None, |t| t.borrow_expr(l.init, ty::ImmBorrow)) - } - None => {} + if let Some(ref e) = arm.guard { + self.consume_expr(e) } self.consume_expr(arm.body); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index f50945a4de0..060a3b521a4 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -82,7 +82,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { cond, Some(condition_scope), condition_scope, - source_info + source_info, + true, )); this.expr_into_dest(destination, then_blk, then) @@ -173,6 +174,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(condition_scope), condition_scope, source_info, + true, ) }); let (short_circuit, continuation, constant) = match op { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7f29e3308f4..1872c762edb 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -40,6 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override: Option, break_scope: region::Scope, variable_source_info: SourceInfo, + declare_bindings: bool, ) -> BlockAnd<()> { let this = self; let expr = &this.thir[expr_id]; @@ -53,6 +54,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + declare_bindings, )); let rhs_then_block = unpack!(this.then_else_break( @@ -61,6 +63,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + declare_bindings, )); rhs_then_block.unit() @@ -75,6 +78,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, local_scope, variable_source_info, + true, ) }); let rhs_success_block = unpack!(this.then_else_break( @@ -83,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + true, )); this.cfg.goto(lhs_success_block, variable_source_info, rhs_success_block); rhs_success_block.unit() @@ -102,6 +107,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, local_scope, variable_source_info, + true, ) }); this.break_for_else(success_block, break_scope, variable_source_info); @@ -116,6 +122,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + declare_bindings, ) }) } @@ -125,6 +132,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { temp_scope_override, break_scope, variable_source_info, + declare_bindings, ), ExprKind::Let { expr, ref pat } => this.lower_let_expr( block, @@ -133,7 +141,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { break_scope, Some(variable_source_info.scope), variable_source_info.span, - true, + declare_bindings, ), _ => { let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope()); @@ -737,13 +745,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); }, ); - if let Some(Guard::IfLet(guard_pat, _)) = guard { - // FIXME: pass a proper `opt_match_place` - self.declare_bindings(visibility_scope, scope_span, guard_pat, None, None); + if let Some(&Guard::If(guard_expr)) = guard { + self.declare_guard_bindings(guard_expr, scope_span, visibility_scope); } visibility_scope } + /// Declare bindings in a guard. This has to be done when declaring bindings + /// for an arm to ensure that or patterns only have one version of each + /// variable. + pub(crate) fn declare_guard_bindings( + &mut self, + guard_expr: ExprId, + scope_span: Span, + visibility_scope: Option, + ) { + match self.thir.exprs[guard_expr].kind { + ExprKind::Let { expr: _, pat: ref guard_pat } => { + // FIXME: pass a proper `opt_match_place` + self.declare_bindings(visibility_scope, scope_span, guard_pat, None, None); + } + ExprKind::Scope { value, .. } => { + self.declare_guard_bindings(value, scope_span, visibility_scope); + } + ExprKind::Use { source } => { + self.declare_guard_bindings(source, scope_span, visibility_scope); + } + ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => { + self.declare_guard_bindings(lhs, scope_span, visibility_scope); + self.declare_guard_bindings(rhs, scope_span, visibility_scope); + } + _ => {} + } + } + pub(crate) fn storage_live_binding( &mut self, block: BasicBlock, @@ -2043,6 +2078,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, match_scope, this.source_info(arm.span), + false, ) } Guard::IfLet(ref pat, s) => { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 8ec70c58c46..da5bd3550ac 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -855,13 +855,8 @@ impl<'tcx> Cx<'tcx> { fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { let arm = Arm { - pattern: self.pattern_from_hir(arm.pat), - guard: arm.guard.as_ref().map(|g| match g { - hir::Guard::If(e) => Guard::If(self.mirror_expr(e)), - hir::Guard::IfLet(l) => { - Guard::IfLet(self.pattern_from_hir(l.pat), self.mirror_expr(l.init)) - } - }), + pattern: self.pattern_from_hir(&arm.pat), + guard: arm.guard.as_ref().map(|g| Guard::If(self.mirror_expr(g))), body: self.mirror_expr(arm.body), lint_level: LintLevel::Explicit(arm.hir_id), scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }, diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index cfe829f170f..8fa4fa1e384 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -351,10 +351,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(let_expr)) = arm.guard { - self.add_from_pat(let_expr.pat); - } + self.add_from_pat(&arm.pat); intravisit::walk_arm(self, arm); } @@ -921,14 +918,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { for arm in arms { let body_succ = self.propagate_through_expr(arm.body, succ); - 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(let_expr) => { - let let_bind = self.define_bindings_in_pat(let_expr.pat, body_succ); - self.propagate_through_expr(let_expr.init, let_bind) - } - }); - let arm_succ = self.define_bindings_in_pat(arm.pat, guard_succ); + let guard_succ = arm + .guard + .as_ref() + .map_or(body_succ, |g| self.propagate_through_expr(g, body_succ)); + let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ); self.merge_from_succ(ln, arm_succ); } self.propagate_through_expr(e, ln) @@ -1328,9 +1322,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { self.check_unused_vars_in_pat(arm.pat, None, None, |_, _, _, _| {}); - if let Some(hir::Guard::IfLet(let_expr)) = arm.guard { - self.check_unused_vars_in_pat(let_expr.pat, None, None, |_, _, _, _| {}); - } intravisit::walk_arm(self, arm); } } diff --git a/tests/ui/closures/2229_closure_analysis/issue-88118-2.stderr b/tests/ui/closures/2229_closure_analysis/issue-88118-2.stderr index b3cb558f976..34b3eab2345 100644 --- a/tests/ui/closures/2229_closure_analysis/issue-88118-2.stderr +++ b/tests/ui/closures/2229_closure_analysis/issue-88118-2.stderr @@ -1,8 +1,8 @@ warning: irrefutable `if let` guard pattern - --> $DIR/issue-88118-2.rs:10:29 + --> $DIR/issue-88118-2.rs:10:25 | LL | Registry if let _ = registry.try_find_description() => { } - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: this pattern will always match, so the guard is useless = help: consider removing the guard and adding a `let` inside the match arm diff --git a/tests/ui/lint/lint-match-arms-2.stderr b/tests/ui/lint/lint-match-arms-2.stderr index 062d5c12e96..5e803ef1934 100644 --- a/tests/ui/lint/lint-match-arms-2.stderr +++ b/tests/ui/lint/lint-match-arms-2.stderr @@ -11,10 +11,10 @@ LL | #[deny(bindings_with_variant_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: irrefutable `if let` guard pattern - --> $DIR/lint-match-arms-2.rs:18:18 + --> $DIR/lint-match-arms-2.rs:18:14 | LL | a if let b = a => {} - | ^ + | ^^^^^^^^^ | = note: this pattern will always match, so the guard is useless = help: consider removing the guard and adding a `let` inside the match arm diff --git a/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr b/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr index cdb6b5c7a49..e8b7f40c70e 100644 --- a/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr +++ b/tests/ui/pattern/usefulness/deny-irrefutable-let-patterns.stderr @@ -22,10 +22,10 @@ LL | while let _ = 5 { = help: consider instead using a `loop { ... }` with a `let` inside it error: irrefutable `if let` guard pattern - --> $DIR/deny-irrefutable-let-patterns.rs:13:18 + --> $DIR/deny-irrefutable-let-patterns.rs:13:14 | LL | _ if let _ = 2 => {} - | ^ + | ^^^^^^^^^ | = note: this pattern will always match, so the guard is useless = help: consider removing the guard and adding a `let` inside the match arm diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr index 75f22ac8dc0..eed5dbb88de 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/warns.stderr @@ -1,8 +1,8 @@ error: irrefutable `if let` guard pattern - --> $DIR/warns.rs:6:24 + --> $DIR/warns.rs:6:20 | LL | Some(x) if let () = x => {} - | ^^ + | ^^^^^^^^^^ | = note: this pattern will always match, so the guard is useless = help: consider removing the guard and adding a `let` inside the match arm diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index 5296475c94a..8b9ec30db63 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -128,8 +128,8 @@ hir-stats Param 64 ( 0.7%) 2 32 hir-stats Body 72 ( 0.8%) 3 24 hir-stats InlineAsm 72 ( 0.8%) 1 72 hir-stats ImplItemRef 72 ( 0.8%) 2 36 +hir-stats Arm 80 ( 0.9%) 2 40 hir-stats FieldDef 96 ( 1.1%) 2 48 -hir-stats Arm 96 ( 1.1%) 2 48 hir-stats Stmt 96 ( 1.1%) 3 32 hir-stats - Local 32 ( 0.4%) 1 hir-stats - Semi 32 ( 0.4%) 1 @@ -151,11 +151,11 @@ hir-stats - Wild 72 ( 0.8%) 1 hir-stats - Struct 72 ( 0.8%) 1 hir-stats - Binding 216 ( 2.4%) 3 hir-stats GenericParam 400 ( 4.4%) 5 80 -hir-stats Generics 560 ( 6.1%) 10 56 +hir-stats Generics 560 ( 6.2%) 10 56 hir-stats Ty 720 ( 7.9%) 15 48 hir-stats - Ptr 48 ( 0.5%) 1 hir-stats - Ref 48 ( 0.5%) 1 -hir-stats - Path 624 ( 6.8%) 13 +hir-stats - Path 624 ( 6.9%) 13 hir-stats Expr 768 ( 8.4%) 12 64 hir-stats - Path 64 ( 0.7%) 1 hir-stats - Struct 64 ( 0.7%) 1 @@ -174,5 +174,5 @@ hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.6%) 31 40 hir-stats PathSegment 1_920 (21.1%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 9_112 +hir-stats Total 9_096 hir-stats From a549711f6e3dc804783652810a40653719dd0af7 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 21 Sep 2023 11:27:29 +0000 Subject: [PATCH 2/4] Remove `thir::Guard` Use Expr instead. Use `ExprKind::Let` to represent if let guards. --- compiler/rustc_middle/src/thir.rs | 9 +---- compiler/rustc_middle/src/thir/visit.rs | 11 ++---- .../rustc_mir_build/src/build/matches/mod.rs | 34 ++++++++----------- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- .../src/thir/pattern/check_match.rs | 18 +++------- compiler/rustc_mir_build/src/thir/print.rs | 25 ++------------ tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs | 30 ++++++++++++++++ 7 files changed, 55 insertions(+), 74 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b6759d35210..2b5983314ee 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -519,20 +519,13 @@ pub struct FruInfo<'tcx> { #[derive(Clone, Debug, HashStable)] pub struct Arm<'tcx> { pub pattern: Box>, - pub guard: Option>, + pub guard: Option, pub body: ExprId, pub lint_level: LintLevel, pub scope: region::Scope, pub span: Span, } -/// A `match` guard. -#[derive(Clone, Debug, HashStable)] -pub enum Guard<'tcx> { - If(ExprId), - IfLet(Box>, ExprId), -} - #[derive(Copy, Clone, Debug, HashStable)] pub enum LogicalOp { /// The `&&` operator. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index ade3ea289cc..4847a7bea91 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -1,5 +1,5 @@ use super::{ - AdtExpr, Arm, Block, ClosureExpr, Expr, ExprKind, Guard, InlineAsmExpr, InlineAsmOperand, Pat, + AdtExpr, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, }; @@ -213,13 +213,8 @@ pub fn walk_arm<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, arm: &'thir Arm<'tcx>, ) { - match arm.guard { - Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), - Some(Guard::IfLet(ref pat, expr)) => { - visitor.visit_pat(pat); - visitor.visit_expr(&visitor.thir()[expr]); - } - None => {} + if let Some(expr) = arm.guard { + visitor.visit_expr(&visitor.thir()[expr]) } visitor.visit_pat(&arm.pattern); visitor.visit_expr(&visitor.thir()[arm.body]); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 1872c762edb..483e70fd6f1 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -425,7 +425,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, arm.span, &arm.pattern, - arm.guard.as_ref(), + arm.guard, opt_scrutinee_place, ); @@ -717,7 +717,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut visibility_scope: Option, scope_span: Span, pattern: &Pat<'tcx>, - guard: Option<&Guard<'tcx>>, + guard: Option, opt_match_place: Option<(Option<&Place<'tcx>>, Span)>, ) -> Option { self.visit_primary_bindings( @@ -745,7 +745,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); }, ); - if let Some(&Guard::If(guard_expr)) = guard { + if let Some(guard_expr) = guard { self.declare_guard_bindings(guard_expr, scope_span, visibility_scope); } visibility_scope @@ -2044,7 +2044,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // * So we eagerly create the reference for the arm and then take a // reference to that. if let Some((arm, match_scope)) = arm_match_scope - && let Some(guard) = &arm.guard + && let Some(guard) = arm.guard { let tcx = self.tcx; let bindings = parent_bindings @@ -2069,22 +2069,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut guard_span = rustc_span::DUMMY_SP; let (post_guard_block, otherwise_post_guard_block) = - self.in_if_then_scope(match_scope, guard_span, |this| match *guard { - Guard::If(e) => { - guard_span = this.thir[e].span; - this.then_else_break( - block, - e, - None, - match_scope, - this.source_info(arm.span), - false, - ) - } - Guard::IfLet(ref pat, s) => { - guard_span = this.thir[s].span; - this.lower_let_expr(block, s, pat, match_scope, None, arm.span, false) - } + self.in_if_then_scope(match_scope, guard_span, |this| { + guard_span = this.thir[guard].span; + this.then_else_break( + block, + guard, + None, + match_scope, + this.source_info(arm.span), + false, + ) }); let source_info = self.source_info(guard_span); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index da5bd3550ac..78d72b30284 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -856,7 +856,7 @@ impl<'tcx> Cx<'tcx> { fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { let arm = Arm { pattern: self.pattern_from_hir(&arm.pat), - guard: arm.guard.as_ref().map(|g| Guard::If(self.mirror_expr(g))), + guard: arm.guard.as_ref().map(|g| self.mirror_expr(g)), body: self.mirror_expr(arm.body), lint_level: LintLevel::Explicit(arm.hir_id), scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }, 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 0bcc2a315ff..f0c767e6ca1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -100,20 +100,10 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { #[instrument(level = "trace", skip(self))] fn visit_arm(&mut self, arm: &'p Arm<'tcx>) { self.with_lint_level(arm.lint_level, |this| { - match arm.guard { - Some(Guard::If(expr)) => { - this.with_let_source(LetSource::IfLetGuard, |this| { - this.visit_expr(&this.thir[expr]) - }); - } - Some(Guard::IfLet(ref pat, expr)) => { - this.with_let_source(LetSource::IfLetGuard, |this| { - this.check_let(pat, Some(expr), pat.span); - this.visit_pat(pat); - this.visit_expr(&this.thir[expr]); - }); - } - None => {} + if let Some(expr) = arm.guard { + this.with_let_source(LetSource::IfLetGuard, |this| { + this.visit_expr(&this.thir[expr]) + }); } this.visit_pat(&arm.pattern); this.visit_expr(&self.thir[arm.body]); diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 28be3139905..267ea3aa3e1 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -593,9 +593,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "pattern: ", depth_lvl + 1); self.print_pat(pattern, depth_lvl + 2); - if let Some(guard) = guard { + if let Some(guard) = *guard { print_indented!(self, "guard: ", depth_lvl + 1); - self.print_guard(guard, depth_lvl + 2); + self.print_expr(guard, depth_lvl + 2); } else { print_indented!(self, "guard: None", depth_lvl + 1); } @@ -764,27 +764,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "}", depth_lvl); } - fn print_guard(&mut self, guard: &Guard<'tcx>, depth_lvl: usize) { - print_indented!(self, "Guard {", depth_lvl); - - match guard { - Guard::If(expr_id) => { - print_indented!(self, "If (", depth_lvl + 1); - self.print_expr(*expr_id, depth_lvl + 2); - print_indented!(self, ")", depth_lvl + 1); - } - Guard::IfLet(pat, expr_id) => { - print_indented!(self, "IfLet (", depth_lvl + 1); - self.print_pat(pat, depth_lvl + 2); - print_indented!(self, ",", depth_lvl + 1); - self.print_expr(*expr_id, depth_lvl + 2); - print_indented!(self, ")", depth_lvl + 1); - } - } - - print_indented!(self, "}", depth_lvl); - } - fn print_closure_expr(&mut self, expr: &ClosureExpr<'tcx>, depth_lvl: usize) { let ClosureExpr { closure_id, args, upvars, movability, fake_reads } = expr; diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs new file mode 100644 index 00000000000..9a3520661a6 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs @@ -0,0 +1,30 @@ +// Tests for #88015 when using if let chains in match guards + +//run-pass + +#![feature(if_let_guard)] +#![feature(let_chains)] +#![allow(irrefutable_let_patterns)] + +fn lhs_let(opt: Option) { + match opt { + None | Some(false) | Some(true) if let x = 42 && true => assert_eq!(x, 42), + _ => panic!() + } +} + +fn rhs_let(opt: Option) { + match opt { + None | Some(false) | Some(true) if true && let x = 41 => assert_eq!(x, 41), + _ => panic!() + } +} + +fn main() { + lhs_let(None); + lhs_let(Some(false)); + lhs_let(Some(true)); + rhs_let(None); + rhs_let(Some(false)); + rhs_let(Some(true)); +} From 1a267e3f40c4c6e32482a7dd98c512f4664a329e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 3 Jan 2024 16:32:13 +0000 Subject: [PATCH 3/4] Restore if let guard temporary scoping difference Match guards with an if let guard or an if let chain guard should have a temporary scope of the whole arm. This is to allow ref bindings to temporaries to borrow check. --- .../rustc_hir_analysis/src/check/region.rs | 13 +++- .../rustc_mir_build/src/build/matches/mod.rs | 6 ++ .../rfcs/rfc-2294-if-let-guard/drop-scope.rs | 72 +++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index c3bdf94d30f..542e69a6c34 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -177,6 +177,14 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h } fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { + fn has_let_expr(expr: &Expr<'_>) -> bool { + match &expr.kind { + hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs), + hir::ExprKind::Let(..) => true, + _ => false, + } + } + let prev_cx = visitor.cx; visitor.terminating_scopes.insert(arm.hir_id.local_id); @@ -184,8 +192,9 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir visitor.enter_node_scope_with_dtor(arm.hir_id.local_id); visitor.cx.var_parent = visitor.cx.parent; - if let Some(expr) = arm.guard { - // Check for if?? + if let Some(expr) = arm.guard + && !has_let_expr(expr) + { visitor.terminating_scopes.insert(expr.hir_id.local_id); } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 483e70fd6f1..906b3205ca7 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -33,6 +33,12 @@ use std::borrow::Borrow; use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { + /// Lowers a condition in a way that ensures that variables bound in any let + /// expressions are definitely initialized in the if body. + /// + /// If `declare_bindings` is false then variables created in `let` + /// expressions will not be declared. This is for if let guards on arms with + /// an or pattern, where the guard is lowered multiple times. pub(crate) fn then_else_break( &mut self, mut block: BasicBlock, diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs new file mode 100644 index 00000000000..9e6e23e8882 --- /dev/null +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/drop-scope.rs @@ -0,0 +1,72 @@ +// Ensure that temporaries in if-let guards live for the arm +// regression test for #118593 + +// check-pass + +#![feature(if_let_guard)] +#![feature(let_chains)] + +fn get_temp() -> Option { + None +} + +fn let_guard(num: u8) { + match num { + 1 | 2 if let Some(ref a) = get_temp() => { + let _b = a; + } + _ => {} + } + match num { + 3 | 4 if let Some(ref mut c) = get_temp() => { + let _d = c; + } + _ => {} + } +} + +fn let_let_chain_guard(num: u8) { + match num { + 5 | 6 + if let Some(ref a) = get_temp() + && let Some(ref b) = get_temp() => + { + let _x = a; + let _y = b; + } + _ => {} + } + match num { + 7 | 8 + if let Some(ref mut c) = get_temp() + && let Some(ref mut d) = get_temp() => + { + let _w = c; + let _z = d; + } + _ => {} + } +} + +fn let_cond_chain_guard(num: u8) { + match num { + 9 | 10 + if let Some(ref a) = get_temp() + && true => + { + let _x = a; + } + _ => {} + } + match num { + 11 | 12 + if let Some(ref mut b) = get_temp() + && true => + { + let _w = b; + } + _ => {} + } +} + +fn main() {} From 44bba5486eebcb6a67f92f43694e42bc074c69ab Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 4 Jan 2024 10:29:47 +0000 Subject: [PATCH 4/4] Update clippy for hir::Guard removal --- src/tools/clippy/clippy_lints/src/entry.rs | 4 +- .../clippy/clippy_lints/src/manual_clamp.rs | 4 +- .../src/matches/collapsible_match.rs | 8 +-- .../src/matches/match_like_matches.rs | 23 ++------- .../src/matches/needless_match.rs | 17 ++----- .../src/matches/redundant_guards.rs | 50 ++++++++----------- .../src/matches/redundant_pattern_match.rs | 20 ++++---- .../src/mixed_read_write_in_expression.rs | 4 +- .../clippy/clippy_lints/src/utils/author.rs | 10 +--- .../clippy/clippy_utils/src/hir_utils.rs | 24 ++------- src/tools/clippy/clippy_utils/src/lib.rs | 4 +- 11 files changed, 56 insertions(+), 112 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index ce0a1dfdc61..0b4bc375df0 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -8,7 +8,7 @@ use core::fmt::{self, Write}; use rustc_errors::Applicability; use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{Block, Expr, ExprKind, Guard, HirId, Let, Pat, Stmt, StmtKind, UnOp}; +use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{Span, SyntaxContext, DUMMY_SP}; @@ -465,7 +465,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { let mut is_map_used = self.is_map_used; for arm in arms { self.visit_pat(arm.pat); - if let Some(Guard::If(guard) | Guard::IfLet(&Let { init: guard, .. })) = arm.guard { + if let Some(guard) = arm.guard { self.visit_non_tail_expr(guard); } is_map_used |= self.visit_cond_arm(arm.body); diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 385fe387a31..0da309f9531 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -11,7 +11,7 @@ use clippy_utils::{ use itertools::Itertools; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::def::Res; -use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind}; +use rustc_hir::{Arm, BinOpKind, Block, Expr, ExprKind, HirId, PatKind, PathSegment, PrimTy, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; @@ -394,7 +394,7 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt // Find possible min/max branches let minmax_values = |a: &'tcx Arm<'tcx>| { if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind - && let Some(Guard::If(e)) = a.guard + && let Some(e) = a.guard { Some((e, var_hir_id, a.body)) } else { diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index 91e6ca7fa8b..5fef5930fab 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -7,7 +7,7 @@ use clippy_utils::{ }; use rustc_errors::MultiSpan; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, Expr, Guard, HirId, Let, Pat, PatKind}; +use rustc_hir::{Arm, Expr, HirId, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::Span; @@ -16,7 +16,7 @@ use super::COLLAPSIBLE_MATCH; pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { for arm in arms { - check_arm(cx, true, arm.pat, arm.body, arm.guard.as_ref(), Some(els_arm.body)); + check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body)); } } } @@ -35,7 +35,7 @@ fn check_arm<'tcx>( outer_is_match: bool, outer_pat: &'tcx Pat<'tcx>, outer_then_body: &'tcx Expr<'tcx>, - outer_guard: Option<&'tcx Guard<'tcx>>, + outer_guard: Option<&'tcx Expr<'tcx>>, outer_else_body: Option<&'tcx Expr<'tcx>>, ) { let inner_expr = peel_blocks_with_stmt(outer_then_body); @@ -71,7 +71,7 @@ fn check_arm<'tcx>( // the binding must not be used in the if guard && outer_guard.map_or( true, - |(Guard::If(e) | Guard::IfLet(Let { init: e, .. }))| !is_local_used(cx, *e, binding_id) + |e| !is_local_used(cx, e, binding_id) ) // ...or anywhere in the inner expression && match inner { diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index 56123326fe4..b062e81cefd 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment}; use rustc_ast::{Attribute, LitKind}; use rustc_errors::Applicability; -use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat, PatKind, QPath}; +use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::source_map::Spanned; @@ -41,14 +41,8 @@ pub(super) fn check_match<'tcx>( find_matches_sugg( cx, scrutinee, - arms.iter().map(|arm| { - ( - cx.tcx.hir().attrs(arm.hir_id), - Some(arm.pat), - arm.body, - arm.guard.as_ref(), - ) - }), + arms.iter() + .map(|arm| (cx.tcx.hir().attrs(arm.hir_id), Some(arm.pat), arm.body, arm.guard)), e, false, ) @@ -67,14 +61,7 @@ where I: Clone + DoubleEndedIterator + ExactSizeIterator - + Iterator< - Item = ( - &'a [Attribute], - Option<&'a Pat<'b>>, - &'a Expr<'b>, - Option<&'a Guard<'b>>, - ), - >, + + Iterator>, &'a Expr<'b>, Option<&'a Expr<'b>>)>, { if !span_contains_comment(cx.sess().source_map(), expr.span) && iter.len() >= 2 @@ -115,7 +102,7 @@ where }) .join(" | ") }; - let pat_and_guard = if let Some(Guard::If(g)) = first_guard { + let pat_and_guard = if let Some(g) = first_guard { format!( "{pat} if {}", snippet_with_applicability(cx, g.span, "..", &mut applicability) diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs index 44dc29c36a6..cc482f15a91 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -8,7 +8,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, Guard, ItemKind, Node, Pat, PatKind, Path, QPath}; +use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; @@ -66,18 +66,9 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) let arm_expr = peel_blocks_with_stmt(arm.body); if let Some(guard_expr) = &arm.guard { - match guard_expr { - // gives up if `pat if expr` can have side effects - Guard::If(if_cond) => { - if if_cond.can_have_side_effects() { - return false; - } - }, - // gives up `pat if let ...` arm - Guard::IfLet(_) => { - return false; - }, - }; + if guard_expr.can_have_side_effects() { + return false; + } } if let PatKind::Wild = arm.pat.kind { diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index f57b22374c8..dfaaeb14ca3 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -5,7 +5,7 @@ use clippy_utils::visitors::{for_each_expr, is_local_used}; use rustc_ast::{BorrowKind, LitKind}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind}; +use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, Pat, PatKind}; use rustc_lint::LateContext; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol}; @@ -21,20 +21,19 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { }; // `Some(x) if matches!(x, y)` - if let Guard::If(if_expr) = guard - && let ExprKind::Match( - scrutinee, - [ - arm, - Arm { - pat: Pat { - kind: PatKind::Wild, .. - }, - .. + if let ExprKind::Match( + scrutinee, + [ + arm, + Arm { + pat: Pat { + kind: PatKind::Wild, .. }, - ], - MatchSource::Normal, - ) = if_expr.kind + .. + }, + ], + MatchSource::Normal, + ) = guard.kind && let Some(binding) = get_pat_binding(cx, scrutinee, outer_arm) { let pat_span = match (arm.pat.kind, binding.byref_ident) { @@ -45,14 +44,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { emit_redundant_guards( cx, outer_arm, - if_expr.span, + guard.span, snippet(cx, pat_span, ""), &binding, arm.guard, ); } // `Some(x) if let Some(2) = x` - else if let Guard::IfLet(let_expr) = guard + else if let ExprKind::Let(let_expr) = guard.kind && let Some(binding) = get_pat_binding(cx, let_expr.init, outer_arm) { let pat_span = match (let_expr.pat.kind, binding.byref_ident) { @@ -71,8 +70,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { } // `Some(x) if x == Some(2)` // `Some(x) if Some(2) == x` - else if let Guard::If(if_expr) = guard - && let ExprKind::Binary(bin_op, local, pat) = if_expr.kind + else if let ExprKind::Binary(bin_op, local, pat) = guard.kind && matches!(bin_op.node, BinOpKind::Eq) // Ensure they have the same type. If they don't, we'd need deref coercion which isn't // possible (currently) in a pattern. In some cases, you can use something like @@ -96,16 +94,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) { emit_redundant_guards( cx, outer_arm, - if_expr.span, + guard.span, snippet(cx, pat_span, ""), &binding, None, ); - } else if let Guard::If(if_expr) = guard - && let ExprKind::MethodCall(path, recv, args, ..) = if_expr.kind + } else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind && let Some(binding) = get_pat_binding(cx, recv, outer_arm) { - check_method_calls(cx, outer_arm, path.ident.name, recv, args, if_expr, &binding); + check_method_calls(cx, outer_arm, path.ident.name, recv, args, guard, &binding); } } } @@ -216,7 +213,7 @@ fn emit_redundant_guards<'tcx>( guard_span: Span, binding_replacement: Cow<'static, str>, pat_binding: &PatBindingInfo, - inner_guard: Option>, + inner_guard: Option<&Expr<'_>>, ) { span_lint_and_then( cx, @@ -242,12 +239,7 @@ fn emit_redundant_guards<'tcx>( ( guard_span.source_callsite().with_lo(outer_arm.pat.span.hi()), inner_guard.map_or_else(String::new, |guard| { - let (prefix, span) = match guard { - Guard::If(e) => ("if", e.span), - Guard::IfLet(l) => ("if let", l.span), - }; - - format!(" {prefix} {}", snippet(cx, span, "")) + format!(" if {}", snippet(cx, guard.span, "")) }), ), ], diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index a4acdfb1db4..b5870d94d99 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; -use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp}; +use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_span::{sym, Span, Symbol}; @@ -277,8 +277,6 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_")); if let Some(guard) = maybe_guard { - let Guard::If(guard) = *guard else { return }; // `...is_none() && let ...` is a syntax error - // wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying! // `guard` here is `Guard::If` with the let expression somewhere deep in the tree of exprs, // counter to the intuition that it should be `Guard::IfLet`, so we need another check @@ -319,7 +317,7 @@ fn found_good_method<'tcx>( cx: &LateContext<'_>, arms: &'tcx [Arm<'tcx>], node: (&PatKind<'_>, &PatKind<'_>), -) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> { +) -> Option<(&'static str, Option<&'tcx Expr<'tcx>>)> { match node { ( PatKind::TupleStruct(ref path_left, patterns_left, _), @@ -409,7 +407,7 @@ fn get_good_method<'tcx>( cx: &LateContext<'_>, arms: &'tcx [Arm<'tcx>], path_left: &QPath<'_>, -) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> { +) -> Option<(&'static str, Option<&'tcx Expr<'tcx>>)> { if let Some(name) = get_ident(path_left) { let (expected_item_left, should_be_left, should_be_right) = match name.as_str() { "Ok" => (Item::Lang(ResultOk), "is_ok()", "is_err()"), @@ -478,7 +476,7 @@ fn find_good_method_for_match<'a, 'tcx>( expected_item_right: Item, should_be_left: &'a str, should_be_right: &'a str, -) -> Option<(&'a str, Option<&'tcx Guard<'tcx>>)> { +) -> Option<(&'a str, Option<&'tcx Expr<'tcx>>)> { let first_pat = arms[0].pat; let second_pat = arms[1].pat; @@ -496,8 +494,8 @@ fn find_good_method_for_match<'a, 'tcx>( match body_node_pair { (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) { - (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard.as_ref())), - (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard.as_ref())), + (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard)), + (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard)), _ => None, }, _ => None, @@ -511,7 +509,7 @@ fn find_good_method_for_matches_macro<'a, 'tcx>( expected_item_left: Item, should_be_left: &'a str, should_be_right: &'a str, -) -> Option<(&'a str, Option<&'tcx Guard<'tcx>>)> { +) -> Option<(&'a str, Option<&'tcx Expr<'tcx>>)> { let first_pat = arms[0].pat; let body_node_pair = if is_pat_variant(cx, first_pat, path_left, expected_item_left) { @@ -522,8 +520,8 @@ fn find_good_method_for_matches_macro<'a, 'tcx>( match body_node_pair { (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) { - (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard.as_ref())), - (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard.as_ref())), + (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard)), + (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard)), _ => None, }, _ => None, diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index 3ff40081c47..195ce17629a 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; @@ -119,7 +119,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { ExprKind::Match(e, arms, _) => { self.visit_expr(e); for arm in arms { - if let Some(Guard::If(if_expr)) = arm.guard { + if let Some(if_expr) = arm.guard { self.visit_expr(if_expr); } // make sure top level arm expressions aren't linted diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 8817e46b3c8..8d38b87e1d7 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -318,17 +318,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.pat(field!(arm.pat)); match arm.value.guard { None => chain!(self, "{arm}.guard.is_none()"), - Some(hir::Guard::If(expr)) => { + Some(expr) => { bind!(self, expr); - chain!(self, "let Some(Guard::If({expr})) = {arm}.guard"); + chain!(self, "let Some({expr}) = {arm}.guard"); self.expr(expr); }, - Some(hir::Guard::IfLet(let_expr)) => { - bind!(self, let_expr); - chain!(self, "let Some(Guard::IfLet({let_expr}) = {arm}.guard"); - self.pat(field!(let_expr.pat)); - self.expr(field!(let_expr.init)); - }, } self.expr(field!(arm.body)); } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index e610ed93050..a23105691bf 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -8,7 +8,7 @@ use rustc_hir::def::Res; use rustc_hir::MatchSource::TryDesugar; use rustc_hir::{ ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, - GenericArgs, Guard, HirId, HirIdMap, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, + GenericArgs, HirId, HirIdMap, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; @@ -320,7 +320,7 @@ impl HirEqInterExpr<'_, '_, '_> { && self.eq_expr(le, re) && over(la, ra, |l, r| { self.eq_pat(l.pat, r.pat) - && both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r)) + && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r)) && self.eq_expr(l.body, r.body) }) }, @@ -410,16 +410,6 @@ impl HirEqInterExpr<'_, '_, '_> { left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr) } - 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(l), Guard::IfLet(r)) => { - self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init) - }, - _ => false, - } - } - fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool { match (left, right) { (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body), @@ -876,7 +866,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { for arm in arms { self.hash_pat(arm.pat); if let Some(ref e) = arm.guard { - self.hash_guard(e); + self.hash_expr(e); } self.hash_expr(arm.body); } @@ -1056,14 +1046,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } - pub fn hash_guard(&mut self, g: &Guard<'_>) { - match g { - Guard::If(expr) | Guard::IfLet(Let { init: expr, .. }) => { - self.hash_expr(expr); - }, - } - } - pub fn hash_lifetime(&mut self, lifetime: &Lifetime) { lifetime.ident.name.hash(&mut self.s); std::mem::discriminant(&lifetime.res).hash(&mut self.s); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 70a3c6f82c1..cdf8528f48a 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -3164,7 +3164,7 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option< self.is_never = false; if let Some(guard) = arm.guard { let in_final_expr = mem::replace(&mut self.in_final_expr, false); - self.visit_expr(guard.body()); + self.visit_expr(guard); self.in_final_expr = in_final_expr; // The compiler doesn't consider diverging guards as causing the arm to diverge. self.is_never = false; @@ -3223,7 +3223,7 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option< fn visit_arm(&mut self, arm: &Arm<'tcx>) { if let Some(guard) = arm.guard { let in_final_expr = mem::replace(&mut self.in_final_expr, false); - self.visit_expr(guard.body()); + self.visit_expr(guard); self.in_final_expr = in_final_expr; } self.visit_expr(arm.body);