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 @@ fn wrap_in_try_constructor( 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 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { )); } 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 @@ fn print_arm(&mut self, arm: &hir::Arm<'_>) { 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 @@ pub fn check_match( 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 @@ fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) { ); 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 @@ pub(crate) fn expr_into_dest( cond, Some(condition_scope), condition_scope, - source_info + source_info, + true, )); this.expr_into_dest(destination, then_blk, then) @@ -173,6 +174,7 @@ pub(crate) fn expr_into_dest( 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 @@ pub(crate) fn then_else_break( 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 @@ pub(crate) fn then_else_break( temp_scope_override, break_scope, variable_source_info, + declare_bindings, )); let rhs_then_block = unpack!(this.then_else_break( @@ -61,6 +63,7 @@ pub(crate) fn then_else_break( temp_scope_override, break_scope, variable_source_info, + declare_bindings, )); rhs_then_block.unit() @@ -75,6 +78,7 @@ pub(crate) fn then_else_break( temp_scope_override, local_scope, variable_source_info, + true, ) }); let rhs_success_block = unpack!(this.then_else_break( @@ -83,6 +87,7 @@ pub(crate) fn then_else_break( 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 @@ pub(crate) fn then_else_break( temp_scope_override, local_scope, variable_source_info, + true, ) }); this.break_for_else(success_block, break_scope, variable_source_info); @@ -116,6 +122,7 @@ pub(crate) fn then_else_break( temp_scope_override, break_scope, variable_source_info, + declare_bindings, ) }) } @@ -125,6 +132,7 @@ pub(crate) fn then_else_break( temp_scope_override, break_scope, variable_source_info, + declare_bindings, ), ExprKind::Let { expr, ref pat } => this.lower_let_expr( block, @@ -133,7 +141,7 @@ pub(crate) fn then_else_break( 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 @@ pub(crate) fn declare_bindings( ); }, ); - 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 @@ fn bind_and_guard_matched_candidate<'pat>( 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 @@ fn method_callee( 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 @@ fn visit_local(&mut self, local: &'tcx hir::Local<'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 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod 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 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'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