diff options
| author | Caio <c410.f3r@gmail.com> | 2021-08-08 11:49:13 -0300 |
|---|---|---|
| committer | Caio <c410.f3r@gmail.com> | 2021-08-15 16:18:26 -0300 |
| commit | 6aa9937a768bf13e5f7bd0ee6dd8579403b39058 (patch) | |
| tree | ad4c8d3c2233b953d6088456650d26972c3d581b /compiler/rustc_mir_build/src/thir | |
| parent | 2d9f2eae84dc3988c5463fdd1b124a9b695447d7 (diff) | |
| download | rust-6aa9937a768bf13e5f7bd0ee6dd8579403b39058.tar.gz rust-6aa9937a768bf13e5f7bd0ee6dd8579403b39058.zip | |
Introduce hir::ExprKind::Let - Take 2
Diffstat (limited to 'compiler/rustc_mir_build/src/thir')
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/check_match.rs | 192 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/visit.rs | 3 |
3 files changed, 135 insertions, 63 deletions
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index c3908ddd4fb..2b0aa41a4bd 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -590,6 +590,9 @@ impl<'tcx> Cx<'tcx> { }, Err(err) => bug!("invalid loop id for continue: {}", err), }, + hir::ExprKind::Let(ref pat, ref expr, _) => { + ExprKind::Let { expr: self.mirror_expr(expr), pat: self.pattern_from_hir(pat) } + } hir::ExprKind::If(cond, then, else_opt) => ExprKind::If { cond: self.mirror_expr(cond), then: self.mirror_expr(then), 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 57ea6c86e7a..50cbe0f71f5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -55,9 +55,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { intravisit::walk_expr(self, ex); - - if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.kind { - self.check_match(scrut, arms, source); + match &ex.kind { + hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source), + hir::ExprKind::Let(pat, scrut, span) => self.check_let(pat, scrut, *span), + _ => {} } } @@ -117,6 +118,31 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { check_for_bindings_named_same_as_variants(self, pat); } + fn let_source(&mut self, pat: &'tcx hir::Pat<'tcx>, _expr: &hir::Expr<'_>) -> LetSource { + let hir = self.tcx.hir(); + let parent = hir.get_parent_node(pat.hir_id); + let parent_parent = hir.get_parent_node(parent); + let parent_parent_node = hir.get(parent_parent); + + let parent_parent_parent = hir.get_parent_node(parent_parent); + let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent); + let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent); + + if let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _), + .. + }) = parent_parent_parent_parent_node + { + LetSource::WhileLet + } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) = + parent_parent_node + { + LetSource::IfLet + } else { + LetSource::GenericLet + } + } + fn lower_pattern<'p>( &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, @@ -144,6 +170,14 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { } } + fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, expr: &hir::Expr<'_>, span: Span) { + self.check_patterns(pat); + let ls = self.let_source(pat, expr); + let mut cx = self.new_cx(expr.hir_id); + let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; + check_let_reachability(&mut cx, ls, pat.hir_id, &tpat, span); + } + fn check_match( &mut self, scrut: &hir::Expr<'_>, @@ -158,7 +192,13 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { self.check_patterns(pat); let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; - check_if_let_guard(&mut cx, &tpat, pat.hir_id); + check_let_reachability( + &mut cx, + LetSource::IfLetGuard, + pat.hir_id, + &tpat, + tpat.span, + ); } } @@ -181,8 +221,16 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty); - // Report unreachable arms. - report_arm_reachability(&cx, &report, source); + report_arm_reachability(&cx, &report, |_, arm_span, arm_hir_id, catchall| { + match source { + hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { + unreachable_pattern(cx.tcx, arm_span, arm_hir_id, catchall); + } + // Unreachable patterns in try and await expressions occur when one of + // the arms are an uninhabited type. Which is OK. + hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} + } + }); // Check if the match is exhaustive. // Note: An empty match isn't the same as an empty matrix for diagnostics purposes, @@ -349,89 +397,99 @@ 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`"); +fn irrefutable_let_pattern(id: HirId, ls: LetSource, span: Span, tcx: TyCtxt<'_>) { + macro_rules! emit_diag { + ( + $lint:expr, + $source_name:expr, + $note_sufix:expr, + $help_sufix:expr + ) => {{ + let mut diag = $lint.build(concat!("irrefutable ", $source_name, " pattern")); + diag.note(concat!("this pattern will always match, so the ", $note_sufix)); + diag.help(concat!("consider ", $help_sufix)); diag.emit() + }}; + } + + tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match ls { + LetSource::GenericLet => { + emit_diag!(lint, "`let`", "`let` is useless", "removing `let`"); } - 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() + LetSource::IfLet => { + emit_diag!( + lint, + "`if let`", + "`if let` is useless", + "replacing the `if let` with a `let`" + ); } - 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() + LetSource::IfLetGuard => { + emit_diag!( + lint, + "`if let` guard", + "guard is useless", + "removing the guard and adding a `let` inside the match arm" + ); } - _ => { - bug!( - "expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}", - source, - ) + LetSource::WhileLet => { + emit_diag!( + lint, + "`while let`", + "loop will never exit", + "instead using a `loop { ... }` with a `let` inside it" + ); } }); } -fn check_if_let_guard<'p, 'tcx>( +fn check_let_reachability<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, - pat: &'p super::Pat<'tcx>, + ls: LetSource, pat_id: HirId, + pat: &'p super::Pat<'tcx>, + 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, |arm_index, arm_span, arm_hir_id, _| { + match ls { + LetSource::IfLet | LetSource::WhileLet => { + match arm_index { + // The arm with the user-specified pattern. + 0 => unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None), + // The arm with the wildcard pattern. + 1 => irrefutable_let_pattern(pat_id, ls, arm_span, cx.tcx), + _ => bug!(), + } + } + LetSource::IfLetGuard if arm_index == 0 => { + unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None); + } + _ => {} + } + }); 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) + irrefutable_let_pattern(pat_id, ls, span, cx.tcx); } } /// Report unreachable arms, if any. -fn report_arm_reachability<'p, 'tcx>( +fn report_arm_reachability<'p, 'tcx, F>( cx: &MatchCheckCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>, - source: hir::MatchSource, -) { + unreachable: F, +) where + F: Fn(usize, Span, HirId, Option<Span>), +{ use Reachability::*; let mut catchall = None; for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() { match is_useful { - Unreachable => { - match source { - hir::MatchSource::WhileDesugar => bug!(), - - hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => { - // 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), - // The arm with the wildcard pattern. - 1 => irrefutable_let_pattern(cx.tcx, arm.pat.span, arm.hir_id, source), - _ => bug!(), - } - } - - hir::MatchSource::IfLetGuardDesugar => { - assert_eq!(arm_index, 0); - unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None); - } - - hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall); - } - - // Unreachable patterns in try and await expressions occur when one of - // the arms are an uninhabited type. Which is OK. - hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} - } - } + Unreachable => unreachable(arm_index, arm.pat.span, arm.hir_id, catchall), Reachable(unreachables) if unreachables.is_empty() => {} // The arm is reachable, but contains unreachable subpatterns (from or-patterns). Reachable(unreachables) => { @@ -723,3 +781,11 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_ err.emit(); } } + +#[derive(Clone, Copy, Debug)] +pub enum LetSource { + GenericLet, + IfLet, + IfLetGuard, + WhileLet, +} diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs index ce5d4362c08..dda6c74d4de 100644 --- a/compiler/rustc_mir_build/src/thir/visit.rs +++ b/compiler/rustc_mir_build/src/thir/visit.rs @@ -57,6 +57,9 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp Use { source } => visitor.visit_expr(&visitor.thir()[source]), NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + Let { expr, .. } => { + visitor.visit_expr(&visitor.thir()[expr]); + } Loop { body } => visitor.visit_expr(&visitor.thir()[body]), Match { scrutinee, ref arms } => { visitor.visit_expr(&visitor.thir()[scrutinee]); |
