diff --git a/Cargo.lock b/Cargo.lock index c4704fb0dd593..f2e4d6c4bc4a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1324,9 +1324,9 @@ dependencies = [ [[package]] name = "either" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elasticlunr-rs" @@ -4735,6 +4735,7 @@ checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f" name = "rustc_trait_selection" version = "0.0.0" dependencies = [ + "either", "itertools", "rustc_ast", "rustc_attr", diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index f7fe0d771a13c..06416a2d9b567 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -10,6 +10,7 @@ use rustc_middle::span_bug; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::{Span, DUMMY_SP}; +use std::ops::ControlFlow::{self, Continue}; /// A visitor that walks over the HIR and collects `Node`s into a HIR map. pub(super) struct NodeCollector<'a, 'hir> { @@ -110,39 +111,44 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { /// deep walking so that we walk nested items in the context of /// their outer items. - fn visit_nested_item(&mut self, item: ItemId) { + fn visit_nested_item(&mut self, item: ItemId) -> ControlFlow { debug!("visit_nested_item: {:?}", item); self.insert_nested(item.owner_id.def_id); + Continue(()) } - fn visit_nested_trait_item(&mut self, item_id: TraitItemId) { + fn visit_nested_trait_item(&mut self, item_id: TraitItemId) -> ControlFlow { self.insert_nested(item_id.owner_id.def_id); + Continue(()) } - fn visit_nested_impl_item(&mut self, item_id: ImplItemId) { + fn visit_nested_impl_item(&mut self, item_id: ImplItemId) -> ControlFlow { self.insert_nested(item_id.owner_id.def_id); + Continue(()) } - fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) { + fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) -> ControlFlow { self.insert_nested(foreign_id.owner_id.def_id); + Continue(()) } - fn visit_nested_body(&mut self, id: BodyId) { + fn visit_nested_body(&mut self, id: BodyId) -> ControlFlow { debug_assert_eq!(id.hir_id.owner, self.owner); let body = self.bodies[&id.hir_id.local_id]; - self.visit_body(body); + self.visit_body(body) } - fn visit_param(&mut self, param: &'hir Param<'hir>) { + fn visit_param(&mut self, param: &'hir Param<'hir>) -> ControlFlow { let node = Node::Param(param); self.insert(param.pat.span, param.hir_id, node); self.with_parent(param.hir_id, |this| { intravisit::walk_param(this, param); }); + Continue(()) } #[instrument(level = "debug", skip(self))] - fn visit_item(&mut self, i: &'hir Item<'hir>) { + fn visit_item(&mut self, i: &'hir Item<'hir>) -> ControlFlow { debug_assert_eq!(i.owner_id, self.owner); self.with_parent(i.hir_id(), |this| { if let ItemKind::Struct(struct_def, _) = &i.kind { @@ -153,59 +159,66 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } intravisit::walk_item(this, i); }); + Continue(()) } #[instrument(level = "debug", skip(self))] - fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { + fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) -> ControlFlow { debug_assert_eq!(fi.owner_id, self.owner); self.with_parent(fi.hir_id(), |this| { intravisit::walk_foreign_item(this, fi); }); + Continue(()) } - fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) { + fn visit_generic_param(&mut self, param: &'hir GenericParam<'hir>) -> ControlFlow { self.insert(param.span, param.hir_id, Node::GenericParam(param)); - intravisit::walk_generic_param(self, param); + intravisit::walk_generic_param(self, param) } - fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) { + fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) -> ControlFlow { self.with_parent(param, |this| { intravisit::walk_const_param_default(this, ct); - }) + }); + Continue(()) } #[instrument(level = "debug", skip(self))] - fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { + fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) -> ControlFlow { debug_assert_eq!(ti.owner_id, self.owner); self.with_parent(ti.hir_id(), |this| { intravisit::walk_trait_item(this, ti); }); + Continue(()) } #[instrument(level = "debug", skip(self))] - fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { + fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) -> ControlFlow { debug_assert_eq!(ii.owner_id, self.owner); self.with_parent(ii.hir_id(), |this| { intravisit::walk_impl_item(this, ii); }); + Continue(()) } - fn visit_pat(&mut self, pat: &'hir Pat<'hir>) { + fn visit_pat(&mut self, pat: &'hir Pat<'hir>) -> ControlFlow { self.insert(pat.span, pat.hir_id, Node::Pat(pat)); self.with_parent(pat.hir_id, |this| { intravisit::walk_pat(this, pat); }); + Continue(()) } - fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) { + fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) -> ControlFlow { self.insert(field.span, field.hir_id, Node::PatField(field)); self.with_parent(field.hir_id, |this| { intravisit::walk_pat_field(this, field); }); + Continue(()) } - fn visit_arm(&mut self, arm: &'hir Arm<'hir>) { + fn visit_arm(&mut self, arm: &'hir Arm<'hir>) -> ControlFlow { let node = Node::Arm(arm); self.insert(arm.span, arm.hir_id, node); @@ -213,87 +226,98 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.with_parent(arm.hir_id, |this| { intravisit::walk_arm(this, arm); }); + Continue(()) } - fn visit_anon_const(&mut self, constant: &'hir AnonConst) { + fn visit_anon_const(&mut self, constant: &'hir AnonConst) -> ControlFlow { self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); self.with_parent(constant.hir_id, |this| { intravisit::walk_anon_const(this, constant); }); + Continue(()) } - fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { + fn visit_expr(&mut self, expr: &'hir Expr<'hir>) -> ControlFlow { self.insert(expr.span, expr.hir_id, Node::Expr(expr)); self.with_parent(expr.hir_id, |this| { intravisit::walk_expr(this, expr); }); + Continue(()) } - fn visit_expr_field(&mut self, field: &'hir ExprField<'hir>) { + fn visit_expr_field(&mut self, field: &'hir ExprField<'hir>) -> ControlFlow { self.insert(field.span, field.hir_id, Node::ExprField(field)); self.with_parent(field.hir_id, |this| { intravisit::walk_expr_field(this, field); }); + Continue(()) } - fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) { + fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) -> ControlFlow { self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt)); self.with_parent(stmt.hir_id, |this| { intravisit::walk_stmt(this, stmt); }); + Continue(()) } - fn visit_path_segment(&mut self, path_segment: &'hir PathSegment<'hir>) { + fn visit_path_segment(&mut self, path_segment: &'hir PathSegment<'hir>) -> ControlFlow { self.insert(path_segment.ident.span, path_segment.hir_id, Node::PathSegment(path_segment)); - intravisit::walk_path_segment(self, path_segment); + intravisit::walk_path_segment(self, path_segment) } - fn visit_ty(&mut self, ty: &'hir Ty<'hir>) { + fn visit_ty(&mut self, ty: &'hir Ty<'hir>) -> ControlFlow { self.insert(ty.span, ty.hir_id, Node::Ty(ty)); self.with_parent(ty.hir_id, |this| { intravisit::walk_ty(this, ty); }); + Continue(()) } - fn visit_infer(&mut self, inf: &'hir InferArg) { + fn visit_infer(&mut self, inf: &'hir InferArg) -> ControlFlow { self.insert(inf.span, inf.hir_id, Node::Infer(inf)); self.with_parent(inf.hir_id, |this| { intravisit::walk_inf(this, inf); }); + Continue(()) } - fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) { + fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) -> ControlFlow { self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr)); self.with_parent(tr.hir_ref_id, |this| { intravisit::walk_trait_ref(this, tr); }); + Continue(()) } - fn visit_block(&mut self, block: &'hir Block<'hir>) { + fn visit_block(&mut self, block: &'hir Block<'hir>) -> ControlFlow { self.insert(block.span, block.hir_id, Node::Block(block)); self.with_parent(block.hir_id, |this| { intravisit::walk_block(this, block); }); + Continue(()) } - fn visit_local(&mut self, l: &'hir Local<'hir>) { + fn visit_local(&mut self, l: &'hir Local<'hir>) -> ControlFlow { self.insert(l.span, l.hir_id, Node::Local(l)); self.with_parent(l.hir_id, |this| { intravisit::walk_local(this, l); - }) + }); + Continue(()) } - fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) -> ControlFlow { self.insert(lifetime.ident.span, lifetime.hir_id, Node::Lifetime(lifetime)); + Continue(()) } - fn visit_variant(&mut self, v: &'hir Variant<'hir>) { + fn visit_variant(&mut self, v: &'hir Variant<'hir>) -> ControlFlow { self.insert(v.span, v.hir_id, Node::Variant(v)); self.with_parent(v.hir_id, |this| { // Register the constructor of this variant. @@ -302,43 +326,49 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } intravisit::walk_variant(this, v); }); + Continue(()) } - fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) { + fn visit_field_def(&mut self, field: &'hir FieldDef<'hir>) -> ControlFlow { self.insert(field.span, field.hir_id, Node::Field(field)); self.with_parent(field.hir_id, |this| { intravisit::walk_field_def(this, field); }); + Continue(()) } - fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) { + fn visit_assoc_type_binding( + &mut self, + type_binding: &'hir TypeBinding<'hir>, + ) -> ControlFlow { self.insert(type_binding.span, type_binding.hir_id, Node::TypeBinding(type_binding)); self.with_parent(type_binding.hir_id, |this| { - intravisit::walk_assoc_type_binding(this, type_binding) - }) + intravisit::walk_assoc_type_binding(this, type_binding); + }); + Continue(()) } - fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) { + fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) -> ControlFlow { // Do not visit the duplicate information in TraitItemRef. We want to // map the actual nodes, not the duplicate ones in the *Ref. let TraitItemRef { id, ident: _, kind: _, span: _ } = *ii; - self.visit_nested_trait_item(id); + self.visit_nested_trait_item(id) } - fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) { + fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) -> ControlFlow { // Do not visit the duplicate information in ImplItemRef. We want to // map the actual nodes, not the duplicate ones in the *Ref. let ImplItemRef { id, ident: _, kind: _, span: _, trait_item_def_id: _ } = *ii; - self.visit_nested_impl_item(id); + self.visit_nested_impl_item(id) } - fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) { + fn visit_foreign_item_ref(&mut self, fi: &'hir ForeignItemRef) -> ControlFlow { // Do not visit the duplicate information in ForeignItemRef. We want to // map the actual nodes, not the duplicate ones in the *Ref. let ForeignItemRef { id, ident: _, span: _ } = *fi; - self.visit_nested_foreign_item(id); + self.visit_nested_foreign_item(id) } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index cb97699d7d2ec..a6c9cc202db46 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -24,6 +24,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; +use std::ops::ControlFlow::{self, Break, Continue}; use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; @@ -317,58 +318,72 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { in_pattern: &mut bool, move_spans: UseSpans<'_>, ) { - struct ExpressionFinder<'hir> { + struct ExpressionFinder { expr_span: Span, - expr: Option<&'hir hir::Expr<'hir>>, - pat: Option<&'hir hir::Pat<'hir>>, - parent_pat: Option<&'hir hir::Pat<'hir>>, } - impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { - fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { + impl<'hir> Visitor<'hir> for ExpressionFinder { + type BreakTy = + Either<&'hir hir::Expr<'hir>, (&'hir hir::Pat<'hir>, Option<&'hir hir::Pat<'hir>>)>; + + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) -> ControlFlow { if e.span == self.expr_span { - self.expr = Some(e); + return Break(Either::Left(e)); } - hir::intravisit::walk_expr(self, e); + hir::intravisit::walk_expr(self, e) } - fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) { + fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) -> ControlFlow { if p.span == self.expr_span { - self.pat = Some(p); + return Break(Either::Right((p, None))); } if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, sub) = p.kind { - if i.span == self.expr_span || p.span == self.expr_span { - self.pat = Some(p); + if i.span == self.expr_span { + return Break(Either::Right((p, None))); } // Check if we are in a situation of `ident @ ident` where we want to suggest // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`. - if let Some(subpat) = sub && self.pat.is_none() { - self.visit_pat(subpat); - if self.pat.is_some() { - self.parent_pat = Some(p); - } - return; + if let Some(subpat) = sub { + return match self.visit_pat(subpat) { + Break(Either::Right((found, _))) => { + Break(Either::Right((found, Some(p)))) + } + res => res, + }; } } - hir::intravisit::walk_pat(self, p); + hir::intravisit::walk_pat(self, p) } } let hir = self.infcx.tcx.hir(); - if let Some(hir::Node::Item(hir::Item { + let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. - })) = hir.find(self.mir_hir_id()) - && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) - { - let place = &self.move_data.move_paths[mpi].place; - let span = place.as_local() - .map(|local| self.body.local_decls[local].source_info.span); - let mut finder = ExpressionFinder { - expr_span: move_span, - expr: None, - pat: None, - parent_pat: None, - }; - finder.visit_expr(expr); - if let Some(span) = span && let Some(expr) = finder.expr { + })) = hir.find(self.mir_hir_id()) else { + return; + }; + let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) else { + return; + }; + let place = &self.move_data.move_paths[mpi].place; + let span = place.as_local().map(|local| self.body.local_decls[local].source_info.span); + let mut finder = ExpressionFinder { expr_span: move_span }; + match finder.visit_expr(expr) { + Continue(()) => {} + Break(Either::Right((pat, parent))) => { + *in_pattern = true; + let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())]; + if let Some(pat) = parent { + sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string())); + } + err.multipart_suggestion_verbose( + "borrow this binding in the pattern to avoid moving the value", + sugg, + Applicability::MachineApplicable, + ); + } + Break(Either::Left(expr)) => { + let Some(span) = span else { + return; + }; for (_, expr) in hir.parent_iter(expr.hir_id) { if let hir::Node::Expr(expr) = expr { if expr.span.contains(span) { @@ -454,18 +469,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - if let Some(pat) = finder.pat { - *in_pattern = true; - let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())]; - if let Some(pat) = finder.parent_pat { - sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string())); - } - err.multipart_suggestion_verbose( - "borrow this binding in the pattern to avoid moving the value", - sugg, - Applicability::MachineApplicable, - ); - } } } @@ -592,26 +595,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if show_assign_sugg { struct LetVisitor { decl_span: Span, - sugg_span: Option, } impl<'v> Visitor<'v> for LetVisitor { - fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { - if self.sugg_span.is_some() { - return; - } + type BreakTy = Span; + + fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> ControlFlow { if let hir::StmtKind::Local(hir::Local { span, ty, init: None, .. }) = &ex.kind && span.contains(self.decl_span) { - self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span)); + return Break(ty.map_or(self.decl_span, |ty| ty.span)); } - hir::intravisit::walk_stmt(self, ex); + hir::intravisit::walk_stmt(self, ex) } } - let mut visitor = LetVisitor { decl_span, sugg_span: None }; - visitor.visit_body(&body); - if let Some(span) = visitor.sugg_span { + let mut visitor = LetVisitor { decl_span }; + if let Break(span) = visitor.visit_body(&body) { self.suggest_assign_value(&mut err, moved_place, span); } } @@ -1264,7 +1264,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { closure_call_changes: Vec<(Span, String)>, } impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { - fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) -> ControlFlow { if e.span.contains(self.capture_span) { if let hir::ExprKind::Closure(&hir::Closure { movability: None, @@ -1290,10 +1290,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.closure_change_spans.push(e.span); } } - hir::intravisit::walk_expr(self, e); + hir::intravisit::walk_expr(self, e) } - fn visit_local(&mut self, local: &'hir hir::Local<'hir>) { + fn visit_local(&mut self, local: &'hir hir::Local<'hir>) -> ControlFlow { if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat && let Some(init) = local.init { @@ -1305,10 +1305,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.closure_local_id = Some(*hir_id); } } - hir::intravisit::walk_local(self, local); + hir::intravisit::walk_local(self, local) } - fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) { + fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) -> ControlFlow { if let hir::StmtKind::Semi(e) = s.kind && let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind && let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path && @@ -1322,7 +1322,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }; self.closure_call_changes.push((span, arg_str)); } - hir::intravisit::walk_stmt(self, s); + hir::intravisit::walk_stmt(self, s) } } @@ -1863,20 +1863,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { struct NestedStatementVisitor { span: Span, current: usize, - found: usize, } impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { - fn visit_block(&mut self, block: &hir::Block<'tcx>) { + type BreakTy = (); + + fn visit_block(&mut self, block: &hir::Block<'tcx>) -> ControlFlow<()> { self.current += 1; - walk_block(self, block); + walk_block(self, block)?; self.current -= 1; + Continue(()) } - fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { - if self.span == expr.span { - self.found = self.current; + fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) -> ControlFlow<()> { + if self.span == expr.span && self.current != 0 { + return Break(()); } - walk_expr(self, expr); + walk_expr(self, expr) } } let source_info = self.body.source_info(location); @@ -1890,10 +1892,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut visitor = NestedStatementVisitor { span: proper_span, current: 0, - found: 0, }; - visitor.visit_stmt(stmt); - if visitor.found == 0 + if visitor.visit_stmt(stmt).is_continue() && stmt.span.contains(proper_span) && let Some(p) = sm.span_to_margin(stmt.span) && let Ok(s) = sm.span_to_snippet(proper_span) @@ -2986,15 +2986,14 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { } /// Detect whether one of the provided spans is a statement nested within the top-most visited expr -struct ReferencedStatementsVisitor<'a>(&'a [Span], bool); +struct ReferencedStatementsVisitor<'a>(&'a [Span]); impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> { - fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { + type BreakTy = (); + fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> ControlFlow<()> { match s.kind { - hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => { - self.1 = true; - } - _ => {} + hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => Break(()), + _ => Continue(()), } } } @@ -3008,14 +3007,13 @@ struct ConditionVisitor<'b> { } impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> ControlFlow { match ex.kind { hir::ExprKind::If(cond, body, None) => { // `if` expressions with no `else` that initialize the binding might be missing an // `else` arm. - let mut v = ReferencedStatementsVisitor(self.spans, false); - v.visit_expr(body); - if v.1 { + let mut v = ReferencedStatementsVisitor(self.spans); + if v.visit_expr(body).is_break() { self.errors.push(( cond.span, format!( @@ -3032,11 +3030,9 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { hir::ExprKind::If(cond, body, Some(other)) => { // `if` expressions where the binding is only initialized in one of the two arms // might be missing a binding initialization. - let mut a = ReferencedStatementsVisitor(self.spans, false); - a.visit_expr(body); - let mut b = ReferencedStatementsVisitor(self.spans, false); - b.visit_expr(other); - match (a.1, b.1) { + let mut a = ReferencedStatementsVisitor(self.spans); + let mut b = ReferencedStatementsVisitor(self.spans); + match (a.visit_expr(body).is_break(), b.visit_expr(other).is_break()) { (true, true) | (false, false) => {} (true, false) => { if other.span.is_desugaring(DesugaringKind::WhileLoop) { @@ -3076,9 +3072,8 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { let results: Vec = arms .iter() .map(|arm| { - let mut v = ReferencedStatementsVisitor(self.spans, false); - v.visit_arm(arm); - v.1 + let mut v = ReferencedStatementsVisitor(self.spans); + v.visit_arm(arm).is_break() }) .collect(); if results.iter().any(|x| *x) && !results.iter().all(|x| *x) { @@ -3120,6 +3115,6 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> { // *some* context. _ => {} } - walk_expr(self, ex); + walk_expr(self, ex) } } diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 19855075ced80..f408e8b827cf5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -1,5 +1,6 @@ //! Print diagnostics to explain why values are borrowed. +use either::Either; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; @@ -14,6 +15,7 @@ use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, DesugaringKind, Span}; use rustc_trait_selection::traits::error_reporting::FindExprBySpan; +use std::ops::ControlFlow::Break; use crate::region_infer::{BlameConstraint, ExtraConstraintInfo}; use crate::{ @@ -72,9 +74,8 @@ impl<'tcx> BorrowExplanation<'tcx> { && let Some(body_id) = node.body_id() { let body = tcx.hir().body(body_id); - let mut expr_finder = FindExprBySpan::new(span); - expr_finder.visit_expr(body.value); - if let Some(mut expr) = expr_finder.result { + let mut expr_finder = FindExprBySpan { span }; + if let Break(Either::Left(mut expr)) = expr_finder.visit_expr(body.value) { while let hir::ExprKind::AddrOf(_, _, inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) | hir::ExprKind::Field(inner, _) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 328ac880dd451..9e640cbc7e093 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -12,6 +12,7 @@ use rustc_middle::{ use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, Span}; +use std::ops::ControlFlow::{self, Break, Continue}; use crate::diagnostics::BorrowedContentSource; use crate::MirBorrowckCtxt; @@ -608,17 +609,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Some((false, err_label_span, message)) => { struct BindingFinder { span: Span, - hir_id: Option, } impl<'tcx> Visitor<'tcx> for BindingFinder { - fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { - if let hir::StmtKind::Local(local) = s.kind { - if local.pat.span == self.span { - self.hir_id = Some(local.hir_id); - } + type BreakTy = hir::HirId; + + fn visit_stmt( + &mut self, + s: &'tcx hir::Stmt<'tcx>, + ) -> ControlFlow + { + if let hir::StmtKind::Local(local) = s.kind + && local.pat.span == self.span + { + Break(local.hir_id) + } else { + hir::intravisit::walk_stmt(self, s) } - hir::intravisit::walk_stmt(self, s); } } let hir_map = self.infcx.tcx.hir(); @@ -631,10 +638,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let body = hir_map.body(body_id); let mut v = BindingFinder { span: err_label_span, - hir_id: None, }; - v.visit_body(body); - v.hir_id + v.visit_body(body).break_value() } else { None }; @@ -732,16 +737,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { assign_span: Span, err: &'a mut Diagnostic, ty: Ty<'tcx>, - suggested: bool, } impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> { - fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { - hir::intravisit::walk_stmt(self, stmt); + type BreakTy = (); + + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) -> ControlFlow<()> { + hir::intravisit::walk_stmt(self, stmt)?; let expr = match stmt.kind { hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr, hir::StmtKind::Local(hir::Local { init: Some(expr), .. }) => expr, _ => { - return; + return Continue(()); } }; if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind @@ -796,7 +802,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ], Applicability::MachineApplicable, ); - self.suggested = true; + Break(()) } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind && let hir::ExprKind::Index(val, index) = receiver.kind && expr.span == self.assign_span @@ -817,7 +823,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ], Applicability::MachineApplicable, ); - self.suggested = true; + Break(()) + } else { + Continue(()) } } } @@ -828,9 +836,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let Some(hir::Node::Item(item)) = node else { return; }; let hir::ItemKind::Fn(.., body_id) = item.kind else { return; }; let body = self.infcx.tcx.hir().body(body_id); - let mut v = V { assign_span: span, err, ty, suggested: false }; - v.visit_body(body); - if !v.suggested { + let mut v = V { assign_span: span, err, ty }; + + if v.visit_body(body).is_continue() { err.help(&format!( "to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API", )); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 0f591460e9d19..ed1d83d621346 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -3,6 +3,7 @@ #![allow(rustc::potential_query_instability)] #![feature(associated_type_bounds)] #![feature(box_patterns)] +#![feature(control_flow_enum)] #![feature(let_chains)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 72e9f7c13437e..dabafcf48e36b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -25,6 +25,7 @@ use rustc_target::spec::abi::Abi; use smallvec::SmallVec; use std::fmt; +use std::ops::ControlFlow::{self, Continue}; #[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)] pub struct Lifetime { @@ -2501,7 +2502,7 @@ impl<'hir> Ty<'hir> { use crate::intravisit::Visitor; struct MyVisitor(Vec); impl<'v> Visitor<'v> for MyVisitor { - fn visit_ty(&mut self, t: &'v Ty<'v>) { + fn visit_ty(&mut self, t: &'v Ty<'v>) -> ControlFlow { if matches!( &t.kind, TyKind::Path(QPath::Resolved( @@ -2510,9 +2511,9 @@ impl<'hir> Ty<'hir> { )) ) { self.0.push(t.span); - return; + return Continue(()); } - crate::intravisit::walk_ty(self, t); + crate::intravisit::walk_ty(self, t) } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index cc0f64017e426..959ff54b1c2e6 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -65,11 +65,11 @@ //! example generator inference, and possibly also HIR borrowck. use crate::hir::*; -use rustc_ast::walk_list; use rustc_ast::{Attribute, Label}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; +use std::ops::ControlFlow::{self, Continue}; pub trait IntoVisitor<'hir> { type Visitor: Visitor<'hir>; @@ -182,6 +182,18 @@ pub mod nested_filter { use nested_filter::NestedFilter; +#[macro_export] +macro_rules! walk_list { + ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => { + { + #[allow(for_loops_over_fallibles)] + for elem in $list { + $visitor.$method(elem $(, $($extra_args,)* )?)?; + } + } + } +} + /// Each method of the Visitor trait is a hook to be potentially /// overridden. Each method's default implementation recursively visits /// the substructure of the input via the corresponding `walk` method; @@ -216,6 +228,8 @@ pub trait Visitor<'v>: Sized { /// and fixed appropriately. type NestedFilter: NestedFilter<'v> = nested_filter::None; + type BreakTy = !; + /// If `type NestedFilter` is set to visit nested items, this method /// must also be overridden to provide a map to retrieve nested items. fn nested_visit_map(&mut self) -> Self::Map { @@ -233,244 +247,303 @@ pub trait Visitor<'v>: Sized { /// `itemlikevisit::ItemLikeVisitor`. The only reason to override /// this method is if you want a nested pattern but cannot supply a /// [`Map`]; see `nested_visit_map` for advice. - fn visit_nested_item(&mut self, id: ItemId) { + fn visit_nested_item(&mut self, id: ItemId) -> ControlFlow { if Self::NestedFilter::INTER { let item = self.nested_visit_map().item(id); - self.visit_item(item); + self.visit_item(item) + } else { + Continue(()) } } /// Like `visit_nested_item()`, but for trait items. See /// `visit_nested_item()` for advice on when to override this /// method. - fn visit_nested_trait_item(&mut self, id: TraitItemId) { + fn visit_nested_trait_item(&mut self, id: TraitItemId) -> ControlFlow { if Self::NestedFilter::INTER { let item = self.nested_visit_map().trait_item(id); - self.visit_trait_item(item); + self.visit_trait_item(item) + } else { + Continue(()) } } /// Like `visit_nested_item()`, but for impl items. See /// `visit_nested_item()` for advice on when to override this /// method. - fn visit_nested_impl_item(&mut self, id: ImplItemId) { + fn visit_nested_impl_item(&mut self, id: ImplItemId) -> ControlFlow { if Self::NestedFilter::INTER { let item = self.nested_visit_map().impl_item(id); - self.visit_impl_item(item); + self.visit_impl_item(item) + } else { + Continue(()) } } /// Like `visit_nested_item()`, but for foreign items. See /// `visit_nested_item()` for advice on when to override this /// method. - fn visit_nested_foreign_item(&mut self, id: ForeignItemId) { + fn visit_nested_foreign_item(&mut self, id: ForeignItemId) -> ControlFlow { if Self::NestedFilter::INTER { let item = self.nested_visit_map().foreign_item(id); - self.visit_foreign_item(item); + self.visit_foreign_item(item) + } else { + Continue(()) } } /// Invoked to visit the body of a function, method or closure. Like /// `visit_nested_item`, does nothing by default unless you override /// `Self::NestedFilter`. - fn visit_nested_body(&mut self, id: BodyId) { + fn visit_nested_body(&mut self, id: BodyId) -> ControlFlow { if Self::NestedFilter::INTRA { let body = self.nested_visit_map().body(id); - self.visit_body(body); + self.visit_body(body) + } else { + Continue(()) } } - fn visit_param(&mut self, param: &'v Param<'v>) { + fn visit_param(&mut self, param: &'v Param<'v>) -> ControlFlow { walk_param(self, param) } /// Visits the top-level item and (optionally) nested items / impl items. See /// `visit_nested_item` for details. - fn visit_item(&mut self, i: &'v Item<'v>) { + fn visit_item(&mut self, i: &'v Item<'v>) -> ControlFlow { walk_item(self, i) } - fn visit_body(&mut self, b: &'v Body<'v>) { - walk_body(self, b); + fn visit_body(&mut self, b: &'v Body<'v>) -> ControlFlow { + walk_body(self, b) } /////////////////////////////////////////////////////////////////////////// - fn visit_id(&mut self, _hir_id: HirId) { + fn visit_id(&mut self, _hir_id: HirId) -> ControlFlow { // Nothing to do. + Continue(()) } - fn visit_name(&mut self, _name: Symbol) { + fn visit_name(&mut self, _name: Symbol) -> ControlFlow { // Nothing to do. + Continue(()) } - fn visit_ident(&mut self, ident: Ident) { + fn visit_ident(&mut self, ident: Ident) -> ControlFlow { walk_ident(self, ident) } - fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) { + fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) -> ControlFlow { walk_mod(self, m, n) } - fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) { + fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> ControlFlow { walk_foreign_item(self, i) } - fn visit_local(&mut self, l: &'v Local<'v>) { + fn visit_local(&mut self, l: &'v Local<'v>) -> ControlFlow { walk_local(self, l) } - fn visit_block(&mut self, b: &'v Block<'v>) { + fn visit_block(&mut self, b: &'v Block<'v>) -> ControlFlow { walk_block(self, b) } - fn visit_stmt(&mut self, s: &'v Stmt<'v>) { + fn visit_stmt(&mut self, s: &'v Stmt<'v>) -> ControlFlow { walk_stmt(self, s) } - fn visit_arm(&mut self, a: &'v Arm<'v>) { + fn visit_arm(&mut self, a: &'v Arm<'v>) -> ControlFlow { walk_arm(self, a) } - fn visit_pat(&mut self, p: &'v Pat<'v>) { + fn visit_pat(&mut self, p: &'v Pat<'v>) -> ControlFlow { walk_pat(self, p) } - fn visit_pat_field(&mut self, f: &'v PatField<'v>) { + fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> ControlFlow { walk_pat_field(self, f) } - fn visit_array_length(&mut self, len: &'v ArrayLen) { + fn visit_array_length(&mut self, len: &'v ArrayLen) -> ControlFlow { walk_array_len(self, len) } - fn visit_anon_const(&mut self, c: &'v AnonConst) { + fn visit_anon_const(&mut self, c: &'v AnonConst) -> ControlFlow { walk_anon_const(self, c) } - fn visit_expr(&mut self, ex: &'v Expr<'v>) { + fn visit_expr(&mut self, ex: &'v Expr<'v>) -> ControlFlow { walk_expr(self, ex) } - fn visit_let_expr(&mut self, lex: &'v Let<'v>) { + fn visit_let_expr(&mut self, lex: &'v Let<'v>) -> ControlFlow { walk_let_expr(self, lex) } - fn visit_expr_field(&mut self, field: &'v ExprField<'v>) { + fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> ControlFlow { walk_expr_field(self, field) } - fn visit_ty(&mut self, t: &'v Ty<'v>) { + fn visit_ty(&mut self, t: &'v Ty<'v>) -> ControlFlow { walk_ty(self, t) } - fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) { + fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> ControlFlow { walk_generic_param(self, p) } - fn visit_const_param_default(&mut self, _param: HirId, ct: &'v AnonConst) { + fn visit_const_param_default( + &mut self, + _param: HirId, + ct: &'v AnonConst, + ) -> ControlFlow { walk_const_param_default(self, ct) } - fn visit_generics(&mut self, g: &'v Generics<'v>) { + fn visit_generics(&mut self, g: &'v Generics<'v>) -> ControlFlow { walk_generics(self, g) } - fn visit_where_predicate(&mut self, predicate: &'v WherePredicate<'v>) { + fn visit_where_predicate( + &mut self, + predicate: &'v WherePredicate<'v>, + ) -> ControlFlow { walk_where_predicate(self, predicate) } - fn visit_fn_ret_ty(&mut self, ret_ty: &'v FnRetTy<'v>) { + fn visit_fn_ret_ty(&mut self, ret_ty: &'v FnRetTy<'v>) -> ControlFlow { walk_fn_ret_ty(self, ret_ty) } - fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) { + fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) -> ControlFlow { walk_fn_decl(self, fd) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: LocalDefId) { + fn visit_fn( + &mut self, + fk: FnKind<'v>, + fd: &'v FnDecl<'v>, + b: BodyId, + _: Span, + id: LocalDefId, + ) -> ControlFlow { walk_fn(self, fk, fd, b, id) } - fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) { + fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) -> ControlFlow { walk_use(self, path, hir_id) } - fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) { + fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) -> ControlFlow { walk_trait_item(self, ti) } - fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) { + fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) -> ControlFlow { walk_trait_item_ref(self, ii) } - fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) { + fn visit_impl_item(&mut self, ii: &'v ImplItem<'v>) -> ControlFlow { walk_impl_item(self, ii) } - fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef) { + fn visit_foreign_item_ref(&mut self, ii: &'v ForeignItemRef) -> ControlFlow { walk_foreign_item_ref(self, ii) } - fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) { + fn visit_impl_item_ref(&mut self, ii: &'v ImplItemRef) -> ControlFlow { walk_impl_item_ref(self, ii) } - fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) { + fn visit_trait_ref(&mut self, t: &'v TraitRef<'v>) -> ControlFlow { walk_trait_ref(self, t) } - fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) { + fn visit_param_bound(&mut self, bounds: &'v GenericBound<'v>) -> ControlFlow { walk_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) { + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>) -> ControlFlow { walk_poly_trait_ref(self, t) } - fn visit_variant_data(&mut self, s: &'v VariantData<'v>) { + fn visit_variant_data(&mut self, s: &'v VariantData<'v>) -> ControlFlow { walk_struct_def(self, s) } - fn visit_field_def(&mut self, s: &'v FieldDef<'v>) { + fn visit_field_def(&mut self, s: &'v FieldDef<'v>) -> ControlFlow { walk_field_def(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) { + fn visit_enum_def( + &mut self, + enum_definition: &'v EnumDef<'v>, + item_id: HirId, + ) -> ControlFlow { walk_enum_def(self, enum_definition, item_id) } - fn visit_variant(&mut self, v: &'v Variant<'v>) { + fn visit_variant(&mut self, v: &'v Variant<'v>) -> ControlFlow { walk_variant(self, v) } - fn visit_label(&mut self, label: &'v Label) { + fn visit_label(&mut self, label: &'v Label) -> ControlFlow { walk_label(self, label) } - fn visit_infer(&mut self, inf: &'v InferArg) { - walk_inf(self, inf); + fn visit_infer(&mut self, inf: &'v InferArg) -> ControlFlow { + walk_inf(self, inf) } - fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) { - walk_generic_arg(self, generic_arg); + fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) -> ControlFlow { + walk_generic_arg(self, generic_arg) } - fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'v Lifetime) -> ControlFlow { walk_lifetime(self, lifetime) } // The span is that of the surrounding type/pattern/expr/whatever. - fn visit_qpath(&mut self, qpath: &'v QPath<'v>, id: HirId, _span: Span) { + fn visit_qpath( + &mut self, + qpath: &'v QPath<'v>, + id: HirId, + _span: Span, + ) -> ControlFlow { walk_qpath(self, qpath, id) } - fn visit_path(&mut self, path: &Path<'v>, _id: HirId) { + fn visit_path(&mut self, path: &Path<'v>, _id: HirId) -> ControlFlow { walk_path(self, path) } - fn visit_path_segment(&mut self, path_segment: &'v PathSegment<'v>) { + fn visit_path_segment( + &mut self, + path_segment: &'v PathSegment<'v>, + ) -> ControlFlow { walk_path_segment(self, path_segment) } - fn visit_generic_args(&mut self, generic_args: &'v GenericArgs<'v>) { + fn visit_generic_args( + &mut self, + generic_args: &'v GenericArgs<'v>, + ) -> ControlFlow { walk_generic_args(self, generic_args) } - fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding<'v>) { + fn visit_assoc_type_binding( + &mut self, + type_binding: &'v TypeBinding<'v>, + ) -> ControlFlow { walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, _attr: &'v Attribute) {} - fn visit_associated_item_kind(&mut self, kind: &'v AssocItemKind) { - walk_associated_item_kind(self, kind); + fn visit_attribute(&mut self, _attr: &'v Attribute) -> ControlFlow { + Continue(()) + } + fn visit_associated_item_kind( + &mut self, + kind: &'v AssocItemKind, + ) -> ControlFlow { + walk_associated_item_kind(self, kind) } - fn visit_defaultness(&mut self, defaultness: &'v Defaultness) { - walk_defaultness(self, defaultness); + fn visit_defaultness(&mut self, defaultness: &'v Defaultness) -> ControlFlow { + walk_defaultness(self, defaultness) } - fn visit_inline_asm(&mut self, asm: &'v InlineAsm<'v>, id: HirId) { - walk_inline_asm(self, asm, id); + fn visit_inline_asm( + &mut self, + asm: &'v InlineAsm<'v>, + id: HirId, + ) -> ControlFlow { + walk_inline_asm(self, asm, id) } } -pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) { - visitor.visit_id(param.hir_id); - visitor.visit_pat(param.pat); +pub fn walk_param<'v, V: Visitor<'v>>( + visitor: &mut V, + param: &'v Param<'v>, +) -> ControlFlow { + visitor.visit_id(param.hir_id)?; + visitor.visit_pat(param.pat) } -pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { - visitor.visit_ident(item.ident); +pub fn walk_item<'v, V: Visitor<'v>>( + visitor: &mut V, + item: &'v Item<'v>, +) -> ControlFlow { + visitor.visit_ident(item.ident)?; match item.kind { ItemKind::ExternCrate(orig_name) => { - visitor.visit_id(item.hir_id()); + visitor.visit_id(item.hir_id())?; if let Some(orig_name) = orig_name { - visitor.visit_name(orig_name); + visitor.visit_name(orig_name) + } else { + Continue(()) } } - ItemKind::Use(ref path, _) => { - visitor.visit_use(path, item.hir_id()); + ItemKind::Use(path, _) => visitor.visit_use(path, item.hir_id()), + ItemKind::Static(typ, _, body) | ItemKind::Const(typ, body) => { + visitor.visit_id(item.hir_id())?; + visitor.visit_ty(typ)?; + visitor.visit_nested_body(body) } - ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => { - visitor.visit_id(item.hir_id()); - visitor.visit_ty(typ); - visitor.visit_nested_body(body); - } - ItemKind::Fn(ref sig, ref generics, body_id) => { - visitor.visit_id(item.hir_id()); + ItemKind::Fn(ref sig, generics, body_id) => { + visitor.visit_id(item.hir_id())?; visitor.visit_fn( FnKind::ItemFn(item.ident, generics, sig.header), sig.decl, @@ -479,261 +552,293 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { item.owner_id.def_id, ) } - ItemKind::Macro(..) => { - visitor.visit_id(item.hir_id()); - } - ItemKind::Mod(ref module) => { + ItemKind::Macro(..) => visitor.visit_id(item.hir_id()), + ItemKind::Mod(module) => { // `visit_mod()` takes care of visiting the `Item`'s `HirId`. visitor.visit_mod(module, item.span, item.hir_id()) } ItemKind::ForeignMod { abi: _, items } => { - visitor.visit_id(item.hir_id()); + visitor.visit_id(item.hir_id())?; walk_list!(visitor, visit_foreign_item_ref, items); + Continue(()) } ItemKind::GlobalAsm(asm) => { - visitor.visit_id(item.hir_id()); - visitor.visit_inline_asm(asm, item.hir_id()); + visitor.visit_id(item.hir_id())?; + visitor.visit_inline_asm(asm, item.hir_id()) } - ItemKind::TyAlias(ref ty, ref generics) => { - visitor.visit_id(item.hir_id()); - visitor.visit_ty(ty); + ItemKind::TyAlias(ty, generics) => { + visitor.visit_id(item.hir_id())?; + visitor.visit_ty(ty)?; visitor.visit_generics(generics) } - ItemKind::OpaqueTy(OpaqueTy { ref generics, bounds, .. }) => { - visitor.visit_id(item.hir_id()); - walk_generics(visitor, generics); + ItemKind::OpaqueTy(OpaqueTy { generics, bounds, .. }) => { + visitor.visit_id(item.hir_id())?; + walk_generics(visitor, generics)?; walk_list!(visitor, visit_param_bound, bounds); + Continue(()) } - ItemKind::Enum(ref enum_definition, ref generics) => { - visitor.visit_generics(generics); + ItemKind::Enum(ref enum_definition, generics) => { + visitor.visit_generics(generics)?; // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`. visitor.visit_enum_def(enum_definition, item.hir_id()) } - ItemKind::Impl(Impl { + ItemKind::Impl(&Impl { unsafety: _, defaultness: _, polarity: _, constness: _, defaultness_span: _, - ref generics, + generics, ref of_trait, - ref self_ty, + self_ty, items, }) => { - visitor.visit_id(item.hir_id()); - visitor.visit_generics(generics); + visitor.visit_id(item.hir_id())?; + visitor.visit_generics(generics)?; walk_list!(visitor, visit_trait_ref, of_trait); - visitor.visit_ty(self_ty); - walk_list!(visitor, visit_impl_item_ref, *items); - } - ItemKind::Struct(ref struct_definition, ref generics) - | ItemKind::Union(ref struct_definition, ref generics) => { - visitor.visit_generics(generics); - visitor.visit_id(item.hir_id()); - visitor.visit_variant_data(struct_definition); - } - ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => { - visitor.visit_id(item.hir_id()); - visitor.visit_generics(generics); + visitor.visit_ty(self_ty)?; + walk_list!(visitor, visit_impl_item_ref, items); + Continue(()) + } + ItemKind::Struct(ref struct_definition, generics) + | ItemKind::Union(ref struct_definition, generics) => { + visitor.visit_generics(generics)?; + visitor.visit_id(item.hir_id())?; + visitor.visit_variant_data(struct_definition) + } + ItemKind::Trait(.., generics, bounds, trait_item_refs) => { + visitor.visit_id(item.hir_id())?; + visitor.visit_generics(generics)?; walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_trait_item_ref, trait_item_refs); + Continue(()) } - ItemKind::TraitAlias(ref generics, bounds) => { - visitor.visit_id(item.hir_id()); - visitor.visit_generics(generics); + ItemKind::TraitAlias(generics, bounds) => { + visitor.visit_id(item.hir_id())?; + visitor.visit_generics(generics)?; walk_list!(visitor, visit_param_bound, bounds); + Continue(()) } } } -pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) { +pub fn walk_body<'v, V: Visitor<'v>>( + visitor: &mut V, + body: &'v Body<'v>, +) -> ControlFlow { walk_list!(visitor, visit_param, body.params); - visitor.visit_expr(body.value); + visitor.visit_expr(body.value) } -pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) { - visitor.visit_name(ident.name); +pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> ControlFlow { + visitor.visit_name(ident.name) } -pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) { - visitor.visit_id(mod_hir_id); - for &item_id in module.item_ids { - visitor.visit_nested_item(item_id); - } +pub fn walk_mod<'v, V: Visitor<'v>>( + visitor: &mut V, + module: &'v Mod<'v>, + mod_hir_id: HirId, +) -> ControlFlow { + visitor.visit_id(mod_hir_id)?; + walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied()); + Continue(()) } -pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) { - visitor.visit_id(foreign_item.hir_id()); - visitor.visit_ident(foreign_item.ident); +pub fn walk_foreign_item<'v, V: Visitor<'v>>( + visitor: &mut V, + foreign_item: &'v ForeignItem<'v>, +) -> ControlFlow { + visitor.visit_id(foreign_item.hir_id())?; + visitor.visit_ident(foreign_item.ident)?; match foreign_item.kind { - ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => { - visitor.visit_generics(generics); - visitor.visit_fn_decl(function_declaration); - for ¶m_name in param_names { - visitor.visit_ident(param_name); - } + ForeignItemKind::Fn(function_declaration, param_names, generics) => { + visitor.visit_generics(generics)?; + visitor.visit_fn_decl(function_declaration)?; + walk_list!(visitor, visit_ident, param_names.iter().copied()); + Continue(()) } - ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), - ForeignItemKind::Type => (), + ForeignItemKind::Static(typ, _) => visitor.visit_ty(typ), + ForeignItemKind::Type => Continue(()), } } -pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) { +pub fn walk_local<'v, V: Visitor<'v>>( + visitor: &mut V, + local: &'v Local<'v>, +) -> ControlFlow { // Intentionally visiting the expr first - the initialization expr // dominates the local's definition. - walk_list!(visitor, visit_expr, &local.init); - visitor.visit_id(local.hir_id); - visitor.visit_pat(local.pat); - if let Some(els) = local.els { - visitor.visit_block(els); - } - walk_list!(visitor, visit_ty, &local.ty); + walk_list!(visitor, visit_expr, local.init); + visitor.visit_id(local.hir_id)?; + visitor.visit_pat(local.pat)?; + walk_list!(visitor, visit_block, local.els); + walk_list!(visitor, visit_ty, local.ty); + Continue(()) } -pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) { - visitor.visit_id(block.hir_id); +pub fn walk_block<'v, V: Visitor<'v>>( + visitor: &mut V, + block: &'v Block<'v>, +) -> ControlFlow { + visitor.visit_id(block.hir_id)?; walk_list!(visitor, visit_stmt, block.stmts); walk_list!(visitor, visit_expr, &block.expr); + Continue(()) } -pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { - visitor.visit_id(statement.hir_id); +pub fn walk_stmt<'v, V: Visitor<'v>>( + visitor: &mut V, + statement: &'v Stmt<'v>, +) -> ControlFlow { + visitor.visit_id(statement.hir_id)?; match statement.kind { - StmtKind::Local(ref local) => visitor.visit_local(local), + StmtKind::Local(local) => visitor.visit_local(local), StmtKind::Item(item) => visitor.visit_nested_item(item), - StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { - visitor.visit_expr(expression) - } + StmtKind::Expr(expression) | StmtKind::Semi(expression) => visitor.visit_expr(expression), } } -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); +pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> ControlFlow { + 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); - } + Guard::If(e) => visitor.visit_expr(e)?, + Guard::IfLet(l) => visitor.visit_let_expr(l)?, } } - visitor.visit_expr(arm.body); + visitor.visit_expr(arm.body) } -pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { - visitor.visit_id(pattern.hir_id); +pub fn walk_pat<'v, V: Visitor<'v>>( + visitor: &mut V, + pattern: &'v Pat<'v>, +) -> ControlFlow { + visitor.visit_id(pattern.hir_id)?; match pattern.kind { PatKind::TupleStruct(ref qpath, children, _) => { - visitor.visit_qpath(qpath, pattern.hir_id, pattern.span); + visitor.visit_qpath(qpath, pattern.hir_id, pattern.span)?; walk_list!(visitor, visit_pat, children); } PatKind::Path(ref qpath) => { - visitor.visit_qpath(qpath, pattern.hir_id, pattern.span); + visitor.visit_qpath(qpath, pattern.hir_id, pattern.span)?; } PatKind::Struct(ref qpath, fields, _) => { - visitor.visit_qpath(qpath, pattern.hir_id, pattern.span); + visitor.visit_qpath(qpath, pattern.hir_id, pattern.span)?; walk_list!(visitor, visit_pat_field, fields); } PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats), PatKind::Tuple(tuple_elements, _) => { walk_list!(visitor, visit_pat, tuple_elements); } - PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) => { - visitor.visit_pat(subpattern) + PatKind::Box(subpattern) | PatKind::Ref(subpattern, _) => { + visitor.visit_pat(subpattern)?; } - PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => { - visitor.visit_ident(ident); + PatKind::Binding(_, _hir_id, ident, optional_subpattern) => { + visitor.visit_ident(ident)?; walk_list!(visitor, visit_pat, optional_subpattern); } - PatKind::Lit(ref expression) => visitor.visit_expr(expression), - PatKind::Range(ref lower_bound, ref upper_bound, _) => { + PatKind::Lit(expression) => visitor.visit_expr(expression)?, + PatKind::Range(lower_bound, upper_bound, _) => { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } PatKind::Wild => (), - PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { + PatKind::Slice(prepatterns, slice_pattern, postpatterns) => { walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, slice_pattern); walk_list!(visitor, visit_pat, postpatterns); } } + Continue(()) } -pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) { - visitor.visit_id(field.hir_id); - visitor.visit_ident(field.ident); +pub fn walk_pat_field<'v, V: Visitor<'v>>( + visitor: &mut V, + field: &'v PatField<'v>, +) -> ControlFlow { + visitor.visit_id(field.hir_id)?; + visitor.visit_ident(field.ident)?; visitor.visit_pat(field.pat) } -pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) { +pub fn walk_array_len<'v, V: Visitor<'v>>( + visitor: &mut V, + len: &'v ArrayLen, +) -> ControlFlow { match len { &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id), ArrayLen::Body(c) => visitor.visit_anon_const(c), } } -pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) { - visitor.visit_id(constant.hir_id); - visitor.visit_nested_body(constant.body); +pub fn walk_anon_const<'v, V: Visitor<'v>>( + visitor: &mut V, + constant: &'v AnonConst, +) -> ControlFlow { + visitor.visit_id(constant.hir_id)?; + visitor.visit_nested_body(constant.body) } -pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) { - visitor.visit_id(expression.hir_id); +pub fn walk_expr<'v, V: Visitor<'v>>( + visitor: &mut V, + expression: &'v Expr<'v>, +) -> ControlFlow { + visitor.visit_id(expression.hir_id)?; match expression.kind { - ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression), + ExprKind::Box(subexpression) => visitor.visit_expr(subexpression)?, ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } - ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const), - ExprKind::Repeat(ref element, ref count) => { - visitor.visit_expr(element); - visitor.visit_array_length(count) + ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const)?, + ExprKind::Repeat(element, ref count) => { + visitor.visit_expr(element)?; + visitor.visit_array_length(count)?; } - ExprKind::Struct(ref qpath, fields, ref optional_base) => { - visitor.visit_qpath(qpath, expression.hir_id, expression.span); + ExprKind::Struct(qpath, fields, optional_base) => { + visitor.visit_qpath(qpath, expression.hir_id, expression.span)?; walk_list!(visitor, visit_expr_field, fields); walk_list!(visitor, visit_expr, optional_base); } ExprKind::Tup(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } - ExprKind::Call(ref callee_expression, arguments) => { - visitor.visit_expr(callee_expression); + ExprKind::Call(callee_expression, arguments) => { + visitor.visit_expr(callee_expression)?; walk_list!(visitor, visit_expr, arguments); } - ExprKind::MethodCall(ref segment, receiver, arguments, _) => { - visitor.visit_path_segment(segment); - visitor.visit_expr(receiver); + ExprKind::MethodCall(segment, receiver, arguments, _) => { + visitor.visit_path_segment(segment)?; + visitor.visit_expr(receiver)?; walk_list!(visitor, visit_expr, arguments); } - ExprKind::Binary(_, ref left_expression, ref right_expression) => { - visitor.visit_expr(left_expression); - visitor.visit_expr(right_expression) + ExprKind::Binary(_, left_expression, right_expression) => { + visitor.visit_expr(left_expression)?; + visitor.visit_expr(right_expression)?; } - ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => { - visitor.visit_expr(subexpression) + ExprKind::AddrOf(_, _, subexpression) | ExprKind::Unary(_, subexpression) => { + visitor.visit_expr(subexpression)?; } - ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => { - visitor.visit_expr(subexpression); - visitor.visit_ty(typ) + ExprKind::Cast(subexpression, typ) | ExprKind::Type(subexpression, typ) => { + visitor.visit_expr(subexpression)?; + visitor.visit_ty(typ)?; } - ExprKind::DropTemps(ref subexpression) => { - visitor.visit_expr(subexpression); + ExprKind::DropTemps(subexpression) => { + visitor.visit_expr(subexpression)?; } - ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr), - ExprKind::If(ref cond, ref then, ref else_opt) => { - visitor.visit_expr(cond); - visitor.visit_expr(then); + ExprKind::Let(let_expr) => visitor.visit_let_expr(let_expr)?, + ExprKind::If(cond, then, else_opt) => { + visitor.visit_expr(cond)?; + visitor.visit_expr(then)?; walk_list!(visitor, visit_expr, else_opt); } - ExprKind::Loop(ref block, ref opt_label, _, _) => { + ExprKind::Loop(block, ref opt_label, _, _) => { walk_list!(visitor, visit_label, opt_label); - visitor.visit_block(block); + visitor.visit_block(block)?; } - ExprKind::Match(ref subexpression, arms, _) => { - visitor.visit_expr(subexpression); + ExprKind::Match(subexpression, arms, _) => { + visitor.visit_expr(subexpression)?; walk_list!(visitor, visit_arm, arms); } ExprKind::Closure(&Closure { @@ -749,176 +854,199 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) constness: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); - visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, def_id) + visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, def_id)?; } - ExprKind::Block(ref block, ref opt_label) => { + ExprKind::Block(block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); - visitor.visit_block(block); + visitor.visit_block(block)?; } - ExprKind::Assign(ref lhs, ref rhs, _) => { - visitor.visit_expr(rhs); - visitor.visit_expr(lhs) + ExprKind::Assign(lhs, rhs, _) => { + visitor.visit_expr(rhs)?; + visitor.visit_expr(lhs)?; } - ExprKind::AssignOp(_, ref left_expression, ref right_expression) => { - visitor.visit_expr(right_expression); - visitor.visit_expr(left_expression); + ExprKind::AssignOp(_, left_expression, right_expression) => { + visitor.visit_expr(right_expression)?; + visitor.visit_expr(left_expression)?; } - ExprKind::Field(ref subexpression, ident) => { - visitor.visit_expr(subexpression); - visitor.visit_ident(ident); + ExprKind::Field(subexpression, ident) => { + visitor.visit_expr(subexpression)?; + visitor.visit_ident(ident)?; } - ExprKind::Index(ref main_expression, ref index_expression) => { - visitor.visit_expr(main_expression); - visitor.visit_expr(index_expression) + ExprKind::Index(main_expression, index_expression) => { + visitor.visit_expr(main_expression)?; + visitor.visit_expr(index_expression)?; } ExprKind::Path(ref qpath) => { - visitor.visit_qpath(qpath, expression.hir_id, expression.span); + visitor.visit_qpath(qpath, expression.hir_id, expression.span)?; } - ExprKind::Break(ref destination, ref opt_expr) => { + ExprKind::Break(ref destination, opt_expr) => { walk_list!(visitor, visit_label, &destination.label); walk_list!(visitor, visit_expr, opt_expr); } ExprKind::Continue(ref destination) => { walk_list!(visitor, visit_label, &destination.label); } - ExprKind::Ret(ref optional_expression) => { + ExprKind::Ret(optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } - ExprKind::InlineAsm(ref asm) => { - visitor.visit_inline_asm(asm, expression.hir_id); + ExprKind::InlineAsm(asm) => { + visitor.visit_inline_asm(asm, expression.hir_id)?; } - ExprKind::Yield(ref subexpression, _) => { - visitor.visit_expr(subexpression); + ExprKind::Yield(subexpression, _) => { + visitor.visit_expr(subexpression)?; } ExprKind::Lit(_) | ExprKind::Err(_) => {} } + Continue(()) } -pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) { +pub fn walk_let_expr<'v, V: Visitor<'v>>( + visitor: &mut V, + let_expr: &'v Let<'v>, +) -> ControlFlow { // match the visit order in walk_local - visitor.visit_expr(let_expr.init); - visitor.visit_id(let_expr.hir_id); - visitor.visit_pat(let_expr.pat); + visitor.visit_expr(let_expr.init)?; + visitor.visit_id(let_expr.hir_id)?; + visitor.visit_pat(let_expr.pat)?; walk_list!(visitor, visit_ty, let_expr.ty); + Continue(()) } -pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) { - visitor.visit_id(field.hir_id); - visitor.visit_ident(field.ident); +pub fn walk_expr_field<'v, V: Visitor<'v>>( + visitor: &mut V, + field: &'v ExprField<'v>, +) -> ControlFlow { + visitor.visit_id(field.hir_id)?; + visitor.visit_ident(field.ident)?; visitor.visit_expr(field.expr) } -pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { - visitor.visit_id(typ.hir_id); +pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> ControlFlow { + visitor.visit_id(typ.hir_id)?; match typ.kind { - TyKind::Slice(ref ty) => visitor.visit_ty(ty), + TyKind::Slice(ty) => visitor.visit_ty(ty), TyKind::Ptr(ref mutable_type) => visitor.visit_ty(mutable_type.ty), - TyKind::Ref(ref lifetime, ref mutable_type) => { - visitor.visit_lifetime(lifetime); + TyKind::Ref(lifetime, ref mutable_type) => { + visitor.visit_lifetime(lifetime)?; visitor.visit_ty(mutable_type.ty) } - TyKind::Never => {} TyKind::Tup(tuple_element_types) => { walk_list!(visitor, visit_ty, tuple_element_types); + Continue(()) } - TyKind::BareFn(ref function_declaration) => { + TyKind::BareFn(function_declaration) => { walk_list!(visitor, visit_generic_param, function_declaration.generic_params); - visitor.visit_fn_decl(function_declaration.decl); - } - TyKind::Path(ref qpath) => { - visitor.visit_qpath(qpath, typ.hir_id, typ.span); + visitor.visit_fn_decl(function_declaration.decl) } + TyKind::Path(ref qpath) => visitor.visit_qpath(qpath, typ.hir_id, typ.span), TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => { - visitor.visit_nested_item(item_id); + visitor.visit_nested_item(item_id)?; walk_list!(visitor, visit_generic_arg, lifetimes); + Continue(()) } - TyKind::Array(ref ty, ref length) => { - visitor.visit_ty(ty); + TyKind::Array(ty, ref length) => { + visitor.visit_ty(ty)?; visitor.visit_array_length(length) } - TyKind::TraitObject(bounds, ref lifetime, _syntax) => { - for bound in bounds { - visitor.visit_poly_trait_ref(bound); - } - visitor.visit_lifetime(lifetime); + TyKind::TraitObject(bounds, lifetime, _syntax) => { + walk_list!(visitor, visit_poly_trait_ref, bounds); + visitor.visit_lifetime(lifetime) } TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), - TyKind::Infer | TyKind::Err(_) => {} + TyKind::Infer | TyKind::Err(_) | TyKind::Never => Continue(()), } } -pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v GenericParam<'v>) { - visitor.visit_id(param.hir_id); +pub fn walk_generic_param<'v, V: Visitor<'v>>( + visitor: &mut V, + param: &'v GenericParam<'v>, +) -> ControlFlow { + visitor.visit_id(param.hir_id)?; match param.name { - ParamName::Plain(ident) => visitor.visit_ident(ident), + ParamName::Plain(ident) => visitor.visit_ident(ident)?, ParamName::Error | ParamName::Fresh => {} } match param.kind { GenericParamKind::Lifetime { .. } => {} - GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default), - GenericParamKind::Const { ref ty, ref default } => { - visitor.visit_ty(ty); - if let Some(ref default) = default { - visitor.visit_const_param_default(param.hir_id, default); + GenericParamKind::Type { default, .. } => walk_list!(visitor, visit_ty, default), + GenericParamKind::Const { ty, ref default } => { + visitor.visit_ty(ty)?; + if let Some(default) = default { + visitor.visit_const_param_default(param.hir_id, default)?; } } } + Continue(()) } -pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v AnonConst) { +pub fn walk_const_param_default<'v, V: Visitor<'v>>( + visitor: &mut V, + ct: &'v AnonConst, +) -> ControlFlow { visitor.visit_anon_const(ct) } -pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) { +pub fn walk_generics<'v, V: Visitor<'v>>( + visitor: &mut V, + generics: &'v Generics<'v>, +) -> ControlFlow { walk_list!(visitor, visit_generic_param, generics.params); walk_list!(visitor, visit_where_predicate, generics.predicates); + Continue(()) } pub fn walk_where_predicate<'v, V: Visitor<'v>>( visitor: &mut V, predicate: &'v WherePredicate<'v>, -) { +) -> ControlFlow { match *predicate { WherePredicate::BoundPredicate(WhereBoundPredicate { hir_id, - ref bounded_ty, + bounded_ty, bounds, bound_generic_params, origin: _, span: _, }) => { - visitor.visit_id(hir_id); - visitor.visit_ty(bounded_ty); + visitor.visit_id(hir_id)?; + visitor.visit_ty(bounded_ty)?; walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_generic_param, bound_generic_params); } WherePredicate::RegionPredicate(WhereRegionPredicate { - ref lifetime, + lifetime, bounds, span: _, in_where_clause: _, }) => { - visitor.visit_lifetime(lifetime); + visitor.visit_lifetime(lifetime)?; walk_list!(visitor, visit_param_bound, bounds); } - WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span: _ }) => { - visitor.visit_ty(lhs_ty); - visitor.visit_ty(rhs_ty); + WherePredicate::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty, span: _ }) => { + visitor.visit_ty(lhs_ty)?; + visitor.visit_ty(rhs_ty)?; } } + Continue(()) } -pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl<'v>) { - for ty in function_declaration.inputs { - visitor.visit_ty(ty) - } +pub fn walk_fn_decl<'v, V: Visitor<'v>>( + visitor: &mut V, + function_declaration: &'v FnDecl<'v>, +) -> ControlFlow { + walk_list!(visitor, visit_ty, function_declaration.inputs); visitor.visit_fn_ret_ty(&function_declaration.output) } -pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) { - if let FnRetTy::Return(ref output_ty) = *ret_ty { +pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>( + visitor: &mut V, + ret_ty: &'v FnRetTy<'v>, +) -> ControlFlow { + if let FnRetTy::Return(output_ty) = *ret_ty { visitor.visit_ty(output_ty) + } else { + Continue(()) } } @@ -928,47 +1056,54 @@ pub fn walk_fn<'v, V: Visitor<'v>>( function_declaration: &'v FnDecl<'v>, body_id: BodyId, _: LocalDefId, -) { - visitor.visit_fn_decl(function_declaration); - walk_fn_kind(visitor, function_kind); +) -> ControlFlow { + visitor.visit_fn_decl(function_declaration)?; + walk_fn_kind(visitor, function_kind)?; visitor.visit_nested_body(body_id) } -pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) { +pub fn walk_fn_kind<'v, V: Visitor<'v>>( + visitor: &mut V, + function_kind: FnKind<'v>, +) -> ControlFlow { match function_kind { - FnKind::ItemFn(_, generics, ..) => { - visitor.visit_generics(generics); - } - FnKind::Closure | FnKind::Method(..) => {} + FnKind::ItemFn(_, generics, ..) => visitor.visit_generics(generics), + FnKind::Closure | FnKind::Method(..) => Continue(()), } } -pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v UsePath<'v>, hir_id: HirId) { - visitor.visit_id(hir_id); +pub fn walk_use<'v, V: Visitor<'v>>( + visitor: &mut V, + path: &'v UsePath<'v>, + hir_id: HirId, +) -> ControlFlow { + visitor.visit_id(hir_id)?; let UsePath { segments, ref res, span } = *path; for &res in res { - visitor.visit_path(&Path { segments, res, span }, hir_id); + visitor.visit_path(&Path { segments, res, span }, hir_id)?; } + Continue(()) } -pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) { +pub fn walk_trait_item<'v, V: Visitor<'v>>( + visitor: &mut V, + trait_item: &'v TraitItem<'v>, +) -> ControlFlow { // N.B., deliberately force a compilation error if/when new fields are added. let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; let hir_id = trait_item.hir_id(); - visitor.visit_ident(ident); - visitor.visit_generics(&generics); - visitor.visit_defaultness(&defaultness); - visitor.visit_id(hir_id); + visitor.visit_ident(ident)?; + visitor.visit_generics(&generics)?; + visitor.visit_defaultness(&defaultness)?; + visitor.visit_id(hir_id)?; match *kind { - TraitItemKind::Const(ref ty, default) => { - visitor.visit_ty(ty); + TraitItemKind::Const(ty, default) => { + visitor.visit_ty(ty)?; walk_list!(visitor, visit_nested_body, default); } TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => { - visitor.visit_fn_decl(sig.decl); - for ¶m_name in param_names { - visitor.visit_ident(param_name); - } + visitor.visit_fn_decl(sig.decl)?; + walk_list!(visitor, visit_ident, param_names.iter().copied()); } TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => { visitor.visit_fn( @@ -977,139 +1112,160 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai body_id, span, trait_item.owner_id.def_id, - ); + )?; } - TraitItemKind::Type(bounds, ref default) => { + TraitItemKind::Type(bounds, default) => { walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, default); } } + Continue(()) } -pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) { +pub fn walk_trait_item_ref<'v, V: Visitor<'v>>( + visitor: &mut V, + trait_item_ref: &'v TraitItemRef, +) -> ControlFlow { // N.B., deliberately force a compilation error if/when new fields are added. let TraitItemRef { id, ident, ref kind, span: _ } = *trait_item_ref; - visitor.visit_nested_trait_item(id); - visitor.visit_ident(ident); - visitor.visit_associated_item_kind(kind); + visitor.visit_nested_trait_item(id)?; + visitor.visit_ident(ident)?; + visitor.visit_associated_item_kind(kind) } -pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) { +pub fn walk_impl_item<'v, V: Visitor<'v>>( + visitor: &mut V, + impl_item: &'v ImplItem<'v>, +) -> ControlFlow { // N.B., deliberately force a compilation error if/when new fields are added. - let ImplItem { - owner_id: _, - ident, - ref generics, - ref kind, - ref defaultness, - span: _, - vis_span: _, - } = *impl_item; - - visitor.visit_ident(ident); - visitor.visit_generics(generics); - visitor.visit_defaultness(defaultness); - visitor.visit_id(impl_item.hir_id()); + let ImplItem { owner_id: _, ident, generics, ref kind, ref defaultness, span: _, vis_span: _ } = + *impl_item; + + visitor.visit_ident(ident)?; + visitor.visit_generics(generics)?; + visitor.visit_defaultness(defaultness)?; + visitor.visit_id(impl_item.hir_id())?; match *kind { ImplItemKind::Const(ref ty, body) => { - visitor.visit_ty(ty); - visitor.visit_nested_body(body); - } - ImplItemKind::Fn(ref sig, body_id) => { - visitor.visit_fn( - FnKind::Method(impl_item.ident, sig), - sig.decl, - body_id, - impl_item.span, - impl_item.owner_id.def_id, - ); - } - ImplItemKind::Type(ref ty) => { - visitor.visit_ty(ty); - } + visitor.visit_ty(ty)?; + visitor.visit_nested_body(body) + } + ImplItemKind::Fn(ref sig, body_id) => visitor.visit_fn( + FnKind::Method(impl_item.ident, sig), + sig.decl, + body_id, + impl_item.span, + impl_item.owner_id.def_id, + ), + ImplItemKind::Type(ref ty) => visitor.visit_ty(ty), } } pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, foreign_item_ref: &'v ForeignItemRef, -) { +) -> ControlFlow { // N.B., deliberately force a compilation error if/when new fields are added. let ForeignItemRef { id, ident, span: _ } = *foreign_item_ref; - visitor.visit_nested_foreign_item(id); - visitor.visit_ident(ident); + visitor.visit_nested_foreign_item(id)?; + visitor.visit_ident(ident) } -pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) { +pub fn walk_impl_item_ref<'v, V: Visitor<'v>>( + visitor: &mut V, + impl_item_ref: &'v ImplItemRef, +) -> ControlFlow { // N.B., deliberately force a compilation error if/when new fields are added. let ImplItemRef { id, ident, ref kind, span: _, trait_item_def_id: _ } = *impl_item_ref; - visitor.visit_nested_impl_item(id); - visitor.visit_ident(ident); - visitor.visit_associated_item_kind(kind); + visitor.visit_nested_impl_item(id)?; + visitor.visit_ident(ident)?; + visitor.visit_associated_item_kind(kind) } -pub fn walk_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef<'v>) { - visitor.visit_id(trait_ref.hir_ref_id); +pub fn walk_trait_ref<'v, V: Visitor<'v>>( + visitor: &mut V, + trait_ref: &'v TraitRef<'v>, +) -> ControlFlow { + visitor.visit_id(trait_ref.hir_ref_id)?; visitor.visit_path(trait_ref.path, trait_ref.hir_ref_id) } -pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) { +pub fn walk_param_bound<'v, V: Visitor<'v>>( + visitor: &mut V, + bound: &'v GenericBound<'v>, +) -> ControlFlow { match *bound { - GenericBound::Trait(ref typ, _modifier) => { - visitor.visit_poly_trait_ref(typ); - } + GenericBound::Trait(ref typ, _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::LangItemTrait(_, _span, hir_id, args) => { - visitor.visit_id(hir_id); - visitor.visit_generic_args(args); + visitor.visit_id(hir_id)?; + visitor.visit_generic_args(args) } - GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), + GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime), } } -pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>) { +pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( + visitor: &mut V, + trait_ref: &'v PolyTraitRef<'v>, +) -> ControlFlow { walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params); - visitor.visit_trait_ref(&trait_ref.trait_ref); + visitor.visit_trait_ref(&trait_ref.trait_ref) } pub fn walk_struct_def<'v, V: Visitor<'v>>( visitor: &mut V, struct_definition: &'v VariantData<'v>, -) { +) -> ControlFlow { walk_list!(visitor, visit_id, struct_definition.ctor_hir_id()); walk_list!(visitor, visit_field_def, struct_definition.fields()); + Continue(()) } -pub fn walk_field_def<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v FieldDef<'v>) { - visitor.visit_id(field.hir_id); - visitor.visit_ident(field.ident); - visitor.visit_ty(field.ty); +pub fn walk_field_def<'v, V: Visitor<'v>>( + visitor: &mut V, + field: &'v FieldDef<'v>, +) -> ControlFlow { + visitor.visit_id(field.hir_id)?; + visitor.visit_ident(field.ident)?; + visitor.visit_ty(field.ty) } pub fn walk_enum_def<'v, V: Visitor<'v>>( visitor: &mut V, enum_definition: &'v EnumDef<'v>, item_id: HirId, -) { - visitor.visit_id(item_id); +) -> ControlFlow { + visitor.visit_id(item_id)?; walk_list!(visitor, visit_variant, enum_definition.variants); + Continue(()) } -pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) { - visitor.visit_ident(variant.ident); - visitor.visit_id(variant.hir_id); - visitor.visit_variant_data(&variant.data); +pub fn walk_variant<'v, V: Visitor<'v>>( + visitor: &mut V, + variant: &'v Variant<'v>, +) -> ControlFlow { + visitor.visit_ident(variant.ident)?; + visitor.visit_id(variant.hir_id)?; + visitor.visit_variant_data(&variant.data)?; walk_list!(visitor, visit_anon_const, &variant.disr_expr); + Continue(()) } -pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) { - visitor.visit_ident(label.ident); +pub fn walk_label<'v, V: Visitor<'v>>( + visitor: &mut V, + label: &'v Label, +) -> ControlFlow { + visitor.visit_ident(label.ident) } -pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) { - visitor.visit_id(inf.hir_id); +pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> ControlFlow { + visitor.visit_id(inf.hir_id) } -pub fn walk_generic_arg<'v, V: Visitor<'v>>(visitor: &mut V, generic_arg: &'v GenericArg<'v>) { +pub fn walk_generic_arg<'v, V: Visitor<'v>>( + visitor: &mut V, + generic_arg: &'v GenericArg<'v>, +) -> ControlFlow { match generic_arg { GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt), GenericArg::Type(ty) => visitor.visit_ty(ty), @@ -1118,92 +1274,116 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>(visitor: &mut V, generic_arg: &'v Ge } } -pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { - visitor.visit_id(lifetime.hir_id); - visitor.visit_ident(lifetime.ident); +pub fn walk_lifetime<'v, V: Visitor<'v>>( + visitor: &mut V, + lifetime: &'v Lifetime, +) -> ControlFlow { + visitor.visit_id(lifetime.hir_id)?; + visitor.visit_ident(lifetime.ident) } -pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) { +pub fn walk_qpath<'v, V: Visitor<'v>>( + visitor: &mut V, + qpath: &'v QPath<'v>, + id: HirId, +) -> ControlFlow { match *qpath { - QPath::Resolved(ref maybe_qself, ref path) => { + QPath::Resolved(maybe_qself, path) => { walk_list!(visitor, visit_ty, maybe_qself); visitor.visit_path(path, id) } - QPath::TypeRelative(ref qself, ref segment) => { - visitor.visit_ty(qself); - visitor.visit_path_segment(segment); + QPath::TypeRelative(qself, segment) => { + visitor.visit_ty(qself)?; + visitor.visit_path_segment(segment) } - QPath::LangItem(..) => {} + QPath::LangItem(..) => Continue(()), } } -pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &Path<'v>) { - for segment in path.segments { - visitor.visit_path_segment(segment); - } +pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &Path<'v>) -> ControlFlow { + walk_list!(visitor, visit_path_segment, path.segments); + Continue(()) } -pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, segment: &'v PathSegment<'v>) { - visitor.visit_ident(segment.ident); - visitor.visit_id(segment.hir_id); - if let Some(ref args) = segment.args { - visitor.visit_generic_args(args); - } +pub fn walk_path_segment<'v, V: Visitor<'v>>( + visitor: &mut V, + segment: &'v PathSegment<'v>, +) -> ControlFlow { + visitor.visit_ident(segment.ident)?; + visitor.visit_id(segment.hir_id)?; + walk_list!(visitor, visit_generic_args, segment.args); + Continue(()) } -pub fn walk_generic_args<'v, V: Visitor<'v>>(visitor: &mut V, generic_args: &'v GenericArgs<'v>) { +pub fn walk_generic_args<'v, V: Visitor<'v>>( + visitor: &mut V, + generic_args: &'v GenericArgs<'v>, +) -> ControlFlow { walk_list!(visitor, visit_generic_arg, generic_args.args); walk_list!(visitor, visit_assoc_type_binding, generic_args.bindings); + Continue(()) } pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>( visitor: &mut V, type_binding: &'v TypeBinding<'v>, -) { - visitor.visit_id(type_binding.hir_id); - visitor.visit_ident(type_binding.ident); - visitor.visit_generic_args(type_binding.gen_args); +) -> ControlFlow { + visitor.visit_id(type_binding.hir_id)?; + visitor.visit_ident(type_binding.ident)?; + visitor.visit_generic_args(type_binding.gen_args)?; match type_binding.kind { TypeBindingKind::Equality { ref term } => match term { - Term::Ty(ref ty) => visitor.visit_ty(ty), + Term::Ty(ty) => visitor.visit_ty(ty), Term::Const(ref c) => visitor.visit_anon_const(c), }, - TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds), + TypeBindingKind::Constraint { bounds } => { + walk_list!(visitor, visit_param_bound, bounds); + Continue(()) + } } } -pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) { +pub fn walk_associated_item_kind<'v, V: Visitor<'v>>( + _: &mut V, + _: &'v AssocItemKind, +) -> ControlFlow { // No visitable content here: this fn exists so you can call it if // the right thing to do, should content be added in the future, // would be to walk it. + Continue(()) } -pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) { +pub fn walk_defaultness<'v, V: Visitor<'v>>( + _: &mut V, + _: &'v Defaultness, +) -> ControlFlow { // No visitable content here: this fn exists so you can call it if // the right thing to do, should content be added in the future, // would be to walk it. + Continue(()) } -pub fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>, id: HirId) { +pub fn walk_inline_asm<'v, V: Visitor<'v>>( + visitor: &mut V, + asm: &'v InlineAsm<'v>, + id: HirId, +) -> ControlFlow { for (op, op_sp) in asm.operands { match op { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => { - visitor.visit_expr(expr) + visitor.visit_expr(expr)?; } InlineAsmOperand::Out { expr, .. } => { - if let Some(expr) = expr { - visitor.visit_expr(expr); - } + walk_list!(visitor, visit_expr, expr); } InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { - visitor.visit_expr(in_expr); - if let Some(out_expr) = out_expr { - visitor.visit_expr(out_expr); - } + visitor.visit_expr(in_expr)?; + walk_list!(visitor, visit_expr, out_expr); } InlineAsmOperand::Const { anon_const, .. } - | InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const), - InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp), + | InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const)?, + InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp)?, } } + Continue(()) } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4ea471f8f0553..0de31c2780743 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -290,7 +290,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( self.tcx.hir() } - fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> ControlFlow { match arg.kind { hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { [PathSegment { res: Res::SelfTyParam { .. }, .. }] => { @@ -305,7 +305,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( }, _ => {} } - hir::intravisit::walk_ty(self, arg); + hir::intravisit::walk_ty(self, arg) } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index b0dc6b1dcacc3..3eee9ef05d458 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -7,7 +7,7 @@ use rustc_errors::{ }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit; +use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -27,6 +27,7 @@ use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; use std::iter; +use std::ops::ControlFlow::{self, Break}; /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. @@ -1497,24 +1498,27 @@ fn compare_synthetic_generics<'tcx>( let (sig, _) = impl_m.expect_fn(); let input_tys = sig.decl.inputs; - struct Visitor(Option, hir::def_id::LocalDefId); + struct Visitor(hir::def_id::LocalDefId); impl<'v> intravisit::Visitor<'v> for Visitor { - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { - intravisit::walk_ty(self, ty); + type BreakTy = Span; + fn visit_ty( + &mut self, + ty: &'v hir::Ty<'v>, + ) -> ControlFlow { if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind && let Res::Def(DefKind::TyParam, def_id) = path.res - && def_id == self.1.to_def_id() + && def_id == self.0.to_def_id() { - self.0 = Some(ty.span); + Break(ty.span) + } else { + intravisit::walk_ty(self, ty) } } } - let mut visitor = Visitor(None, impl_def_id); - for ty in input_tys { - intravisit::Visitor::visit_ty(&mut visitor, ty); - } - let span = visitor.0?; + let mut visitor = Visitor(impl_def_id); + let span = + input_tys.iter().find_map(|ty| visitor.visit_ty(ty).break_value())?; let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds; let bounds = bounds.first()?.span().to(bounds.last()?.span()); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index b28bfb1d54b6c..9e8259c9e66cc 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -6,11 +6,11 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html -use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::walk_list; use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt}; use rustc_index::vec::Idx; use rustc_middle::middle::region::*; @@ -19,6 +19,7 @@ use rustc_span::source_map; use rustc_span::Span; use std::mem; +use std::ops::ControlFlow::{self, Continue}; #[derive(Debug, Copy, Clone)] pub struct Context { @@ -85,7 +86,10 @@ fn record_var_lifetime( } } -fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx hir::Block<'tcx>) { +fn resolve_block<'tcx>( + visitor: &mut RegionResolutionVisitor<'tcx>, + blk: &'tcx hir::Block<'tcx>, +) -> ControlFlow { debug!("resolve_block(blk.hir_id={:?})", blk.hir_id); let prev_cx = visitor.cx; @@ -161,15 +165,18 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h data: ScopeData::Remainder(FirstStatementIndex::new(i)), }); visitor.cx.var_parent = visitor.cx.parent; - visitor.visit_stmt(statement) + visitor.visit_stmt(statement); + } + hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => { + visitor.visit_stmt(statement); } - hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => visitor.visit_stmt(statement), } } walk_list!(visitor, visit_expr, &blk.expr); } visitor.cx = prev_cx; + Continue(()) } fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) { @@ -466,7 +473,9 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h visitor.cx = expr_cx; } - _ => intravisit::walk_expr(visitor, expr), + _ => { + intravisit::walk_expr(visitor, expr); + } } visitor.expr_and_pat_count += 1; @@ -756,11 +765,11 @@ impl<'tcx> RegionResolutionVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { - fn visit_block(&mut self, b: &'tcx Block<'tcx>) { - resolve_block(self, b); + fn visit_block(&mut self, b: &'tcx Block<'tcx>) -> ControlFlow { + resolve_block(self, b) } - fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { + fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) -> ControlFlow { let body_id = body.id(); let owner_id = self.tcx.hir().body_owner_def_id(body_id); @@ -797,7 +806,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // The body of the every fn is a root scope. self.cx.parent = self.cx.var_parent; if self.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() { - self.visit_expr(&body.value) + self.visit_expr(&body.value); } else { // Only functions have an outer terminating (drop) scope, while // temporaries in constant initializers may be 'static, but only @@ -830,22 +839,28 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { self.cx = outer_cx; self.terminating_scopes = outer_ts; self.pessimistic_yield = outer_pessimistic_yield; + Continue(()) } - fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) { + fn visit_arm(&mut self, a: &'tcx Arm<'tcx>) -> ControlFlow { resolve_arm(self, a); + Continue(()) } - fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) { + fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) -> ControlFlow { resolve_pat(self, p); + Continue(()) } - fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) { + fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) -> ControlFlow { resolve_stmt(self, s); + Continue(()) } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow { resolve_expr(self, ex); + Continue(()) } - fn visit_local(&mut self, l: &'tcx Local<'tcx>) { - resolve_local(self, Some(&l.pat), l.init) + fn visit_local(&mut self, l: &'tcx Local<'tcx>) -> ControlFlow { + resolve_local(self, Some(&l.pat), l.init); + Continue(()) } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 604d54cafb532..22c9036b2a6dc 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -38,6 +38,7 @@ use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use rustc_trait_selection::traits::ObligationCtxt; use std::iter; +use std::ops::ControlFlow::{self, Continue}; mod generics_of; mod item_bounds; @@ -122,23 +123,23 @@ pub struct ItemCtxt<'tcx> { pub(crate) struct HirPlaceholderCollector(pub(crate) Vec); impl<'v> Visitor<'v> for HirPlaceholderCollector { - fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { + fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> ControlFlow { if let hir::TyKind::Infer = t.kind { self.0.push(t.span); } intravisit::walk_ty(self, t) } - fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) { + fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) -> ControlFlow { match generic_arg { hir::GenericArg::Infer(inf) => { self.0.push(inf.span); - intravisit::walk_inf(self, inf); + intravisit::walk_inf(self, inf) } hir::GenericArg::Type(t) => self.visit_ty(t), - _ => {} + _ => Continue(()), } } - fn visit_array_length(&mut self, length: &'v hir::ArrayLen) { + fn visit_array_length(&mut self, length: &'v hir::ArrayLen) -> ControlFlow { if let &hir::ArrayLen::Infer(_, span) = length { self.0.push(span); } @@ -273,13 +274,13 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { self.tcx.hir() } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { convert_item(self.tcx, item.item_id()); reject_placeholder_type_signatures_in_item(self.tcx, item); - intravisit::walk_item(self, item); + intravisit::walk_item(self, item) } - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { + fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) -> ControlFlow { for param in generics.params { match param.kind { hir::GenericParamKind::Lifetime { .. } => {} @@ -297,10 +298,10 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { } } } - intravisit::walk_generics(self, generics); + intravisit::walk_generics(self, generics) } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Closure(closure) = expr.kind { self.tcx.ensure().generics_of(closure.def_id); self.tcx.ensure().codegen_fn_attrs(closure.def_id); @@ -308,17 +309,17 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { // depends on typecheck and would therefore hide // any further errors in case one typeck fails. } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { convert_trait_item(self.tcx, trait_item.trait_item_id()); - intravisit::walk_trait_item(self, trait_item); + intravisit::walk_trait_item(self, trait_item) } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { convert_impl_item(self.tcx, impl_item.impl_item_id()); - intravisit::walk_impl_item(self, impl_item); + intravisit::walk_impl_item(self, impl_item) } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 127d4fa908bb9..44beb0fbb83a0 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; +use std::ops::ControlFlow::{self, Break, Continue}; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { use rustc_hir::*; @@ -34,14 +35,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let mut in_param_ty = false; for (_parent, node) in tcx.hir().parent_iter(hir_id) { if let Some(generics) = node.generics() { - let mut visitor = AnonConstInParamTyDetector { - in_param_ty: false, - found_anon_const_in_param_ty: false, - ct: hir_id, - }; + let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id }; - visitor.visit_generics(generics); - in_param_ty = visitor.found_anon_const_in_param_ty; + in_param_ty = visitor.visit_generics(generics).is_break(); break; } } @@ -362,50 +358,49 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option { tcx: TyCtxt<'tcx>, outer_index: ty::DebruijnIndex, - has_late_bound_regions: Option, } impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if self.has_late_bound_regions.is_some() { - return; - } + type BreakTy = Span; + + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow { match ty.kind { hir::TyKind::BareFn(..) => { self.outer_index.shift_in(1); - intravisit::walk_ty(self, ty); + intravisit::walk_ty(self, ty)?; self.outer_index.shift_out(1); } - _ => intravisit::walk_ty(self, ty), + _ => intravisit::walk_ty(self, ty)?, } + Continue(()) } - fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) { - if self.has_late_bound_regions.is_some() { - return; - } + fn visit_poly_trait_ref( + &mut self, + tr: &'tcx hir::PolyTraitRef<'tcx>, + ) -> ControlFlow { self.outer_index.shift_in(1); - intravisit::walk_poly_trait_ref(self, tr); + intravisit::walk_poly_trait_ref(self, tr)?; self.outer_index.shift_out(1); + Continue(()) } - fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { - if self.has_late_bound_regions.is_some() { - return; - } - + fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow { match self.tcx.named_bound_var(lt.hir_id) { - Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {} + Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => { + Continue(()) + } Some(rbv::ResolvedArg::LateBound(debruijn, _, _)) - if debruijn < self.outer_index => {} + if debruijn < self.outer_index => + { + Continue(()) + } Some( rbv::ResolvedArg::LateBound(..) | rbv::ResolvedArg::Free(..) | rbv::ResolvedArg::Error(_), ) - | None => { - self.has_late_bound_regions = Some(lt.ident.span); - } + | None => Break(lt.ident.span), } } } @@ -415,11 +410,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option, decl: &'tcx hir::FnDecl<'tcx>, ) -> Option { - let mut visitor = LateBoundRegionsDetector { - tcx, - outer_index: ty::INNERMOST, - has_late_bound_regions: None, - }; + let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST }; for param in generics.params { if let GenericParamKind::Lifetime { .. } = param.kind { if tcx.is_late_bound(param.hir_id) { @@ -427,8 +418,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option Visitor<'v> for AnonConstInParamTyDetector { - fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { + type BreakTy = (); + + fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> ControlFlow<()> { if let GenericParamKind::Const { ty, default: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; - self.visit_ty(ty); + self.visit_ty(ty)?; self.in_param_ty = prev; } + Continue(()) } - fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> ControlFlow<()> { if self.in_param_ty && self.ct == c.hir_id { - self.found_anon_const_in_param_ty = true; + Break(()) } else { intravisit::walk_anon_const(self, c) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 2badd66e346f1..a4171b18b3e1b 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericPredicates, ToPredicate}; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; +use std::ops::ControlFlow::{self, Continue}; #[derive(Debug)] struct OnlySelfBounds(bool); @@ -336,7 +337,7 @@ fn const_evaluatable_predicates_of( } impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { - fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) -> ControlFlow { let ct = ty::Const::from_anon_const(self.tcx, c.def_id); if let ty::ConstKind::Unevaluated(_) = ct.kind() { let span = self.tcx.def_span(c.def_id); @@ -346,9 +347,14 @@ fn const_evaluatable_predicates_of( span, )); } + Continue(()) } - fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) { + fn visit_const_param_default( + &mut self, + _param: HirId, + _ct: &'tcx hir::AnonConst, + ) -> ControlFlow { // Do not look into const param defaults, // these get checked when they are actually instantiated. // @@ -356,6 +362,7 @@ fn const_evaluatable_predicates_of( // // struct Foo; // struct Bar(Foo); + Continue(()) } } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6c00b8ff7bdee..c1b19dd41fbc3 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -6,13 +6,13 @@ //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file //! is also responsible for assigning their semantics to implicit lifetimes in trait objects. -use rustc_ast::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::walk_list; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; @@ -23,6 +23,7 @@ use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use std::fmt; +use std::ops::ControlFlow::{self, Break, Continue}; trait RegionExt { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg); @@ -246,19 +247,23 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou scope: &Scope::Root { opt_parent_item: None }, }; match tcx.hir().owner(local_def_id) { - hir::OwnerNode::Item(item) => visitor.visit_item(item), - hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), + hir::OwnerNode::Item(item) => { + visitor.visit_item(item); + } + hir::OwnerNode::ForeignItem(item) => { + visitor.visit_foreign_item(item); + } hir::OwnerNode::TraitItem(item) => { let scope = Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) }; visitor.scope = &scope; - visitor.visit_trait_item(item) + visitor.visit_trait_item(item); } hir::OwnerNode::ImplItem(item) => { let scope = Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) }; visitor.scope = &scope; - visitor.visit_impl_item(item) + visitor.visit_impl_item(item); } hir::OwnerNode::Crate(_) => {} } @@ -378,7 +383,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| { walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); - this.visit_trait_ref(&trait_ref.trait_ref); + this.visit_trait_ref(&trait_ref.trait_ref) }); } } @@ -395,37 +400,32 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.tcx.hir() } - fn visit_nested_body(&mut self, body: hir::BodyId) { + fn visit_nested_body(&mut self, body: hir::BodyId) -> ControlFlow { let body = self.tcx.hir().body(body); - self.with(Scope::Body { id: body.id(), s: self.scope }, |this| { - this.visit_body(body); - }); + self.with(Scope::Body { id: body.id(), s: self.scope }, |this| this.visit_body(body)) } - fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Closure(hir::Closure { binder, bound_generic_params, fn_decl, .. }) = e.kind { if let &hir::ClosureBinder::For { span: for_sp, .. } = binder { fn span_of_infer(ty: &hir::Ty<'_>) -> Option { - struct V(Option); + struct V; impl<'v> Visitor<'v> for V { - fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { + type BreakTy = Span; + fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> ControlFlow { match t.kind { - _ if self.0.is_some() => (), - hir::TyKind::Infer => { - self.0 = Some(t.span); - } + hir::TyKind::Infer => Break(t.span), _ => intravisit::walk_ty(self, t), } } } - let mut v = V(None); - v.visit_ty(ty); - v.0 + let mut v = V; + v.visit_ty(ty).break_value() } let infer_in_rt_sp = match fn_decl.output { @@ -477,14 +477,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // a closure has no bounds, so everything // contained within is scoped within its binder. intravisit::walk_expr(this, e) - }); + }) } else { intravisit::walk_expr(self, e) } } #[instrument(level = "debug", skip(self))] - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { match &item.kind { hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { if let Some(of_trait) = of_trait { @@ -496,8 +496,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { match item.kind { hir::ItemKind::Fn(_, generics, _) => { self.visit_early_late(item.hir_id(), generics, |this| { - intravisit::walk_item(this, item); - }); + intravisit::walk_item(this, item) + }) } hir::ItemKind::ExternCrate(_) @@ -507,13 +507,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::GlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. - intravisit::walk_item(self, item); + intravisit::walk_item(self, item) } hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { // No lifetime parameters, but implied 'static. self.with(Scope::Elision { s: self.scope }, |this| { intravisit::walk_item(this, item) - }); + }) } hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. @@ -543,6 +543,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { ); }); } + Continue(()) } hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent), @@ -570,7 +571,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { this.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; this.with(scope, |this| intravisit::walk_item(this, item)) - }); + }) }) } hir::ItemKind::TyAlias(_, generics) @@ -592,32 +593,26 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; - this.with(scope, |this| { - intravisit::walk_item(this, item); - }); - }); + this.with(scope, |this| intravisit::walk_item(this, item)) + }) } } } - fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { match item.kind { hir::ForeignItemKind::Fn(_, _, generics) => { self.visit_early_late(item.hir_id(), generics, |this| { - intravisit::walk_foreign_item(this, item); + intravisit::walk_foreign_item(this, item) }) } - hir::ForeignItemKind::Static(..) => { - intravisit::walk_foreign_item(self, item); - } - hir::ForeignItemKind::Type => { - intravisit::walk_foreign_item(self, item); - } + hir::ForeignItemKind::Static(..) => intravisit::walk_foreign_item(self, item), + hir::ForeignItemKind::Type => intravisit::walk_foreign_item(self, item), } } #[instrument(level = "debug", skip(self))] - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow { match ty.kind { hir::TyKind::BareFn(c) => { let (mut bound_vars, binders): (FxIndexMap, Vec<_>) = c @@ -644,8 +639,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.with(scope, |this| { // a bare fn has no bounds, so everything // contained within is scoped within its binder. - intravisit::walk_ty(this, ty); - }); + intravisit::walk_ty(this, ty) + }) } hir::TyKind::TraitObject(bounds, lifetime, _) => { debug!(?bounds, ?lifetime, "TraitObject"); @@ -664,7 +659,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // use the object lifetime defaulting // rules. So e.g., `Box` becomes // `Box`. - self.resolve_object_lifetime_default(lifetime) + self.resolve_object_lifetime_default(lifetime); + Continue(()) } LifetimeName::Infer => { // If the user writes `'_`, we use the *ordinary* elision @@ -672,12 +668,13 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // resolved the same as the `'_` in `&'_ Foo`. // // cc #48468 + Continue(()) } LifetimeName::Param(..) | LifetimeName::Static => { // If the user wrote an explicit name, use that. - self.visit_lifetime(lifetime); + self.visit_lifetime(lifetime) } - LifetimeName::Error => {} + LifetimeName::Error => Continue(()), } } hir::TyKind::Ref(lifetime_ref, ref mt) => { @@ -686,7 +683,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { lifetime: self.map.defs.get(&lifetime_ref.hir_id).cloned(), s: self.scope, }; - self.with(scope, |this| this.visit_ty(&mt.ty)); + self.with(scope, |this| this.visit_ty(&mt.ty)) } hir::TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => { // Resolve the lifetimes in the bounds to the lifetime defs in the generics. @@ -707,12 +704,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { let scope = Scope::Elision { s: this.scope }; - this.with(scope, |this| { - intravisit::walk_item(this, opaque_ty); - }) + this.with(scope, |this| intravisit::walk_item(this, opaque_ty)) }); - return; + return Continue(()); } hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..), @@ -769,20 +764,19 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.uninsert_lifetime_on_error(lifetime, def.unwrap()); } } + Continue(()) } _ => intravisit::walk_ty(self, ty), } } #[instrument(level = "debug", skip(self))] - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { use self::hir::TraitItemKind::*; match trait_item.kind { - Fn(_, _) => { - self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| { - intravisit::walk_trait_item(this, trait_item) - }); - } + Fn(_, _) => self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| { + intravisit::walk_trait_item(this, trait_item) + }), Type(bounds, ty) => { let generics = &trait_item.generics; let bound_vars = generics.params.iter().map(ResolvedArg::early).collect(); @@ -806,17 +800,18 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } }) }); + Continue(()) } Const(_, _) => { // Only methods and types support generics. assert!(trait_item.generics.params.is_empty()); - intravisit::walk_trait_item(self, trait_item); + intravisit::walk_trait_item(self, trait_item) } } } #[instrument(level = "debug", skip(self))] - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { use self::hir::ImplItemKind::*; match impl_item.kind { Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| { @@ -838,20 +833,20 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let scope = Scope::TraitRefBoundary { s: this.scope }; this.with(scope, |this| { this.visit_generics(generics); - this.visit_ty(ty); + this.visit_ty(ty) }) - }); + }) } Const(_, _) => { // Only methods and types support generics. assert!(impl_item.generics.params.is_empty()); - intravisit::walk_impl_item(self, impl_item); + intravisit::walk_impl_item(self, impl_item) } } } #[instrument(level = "debug", skip(self))] - fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) -> ControlFlow { match lifetime_ref.res { hir::LifetimeName::Static => { self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime) @@ -864,9 +859,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // Those will be resolved by typechecking. hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {} } + Continue(()) } - fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: hir::HirId) { + fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: hir::HirId) -> ControlFlow { for (i, segment) in path.segments.iter().enumerate() { let depth = path.segments.len() - i - 1; if let Some(args) = segment.args { @@ -876,6 +872,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { if let Res::Def(DefKind::TyParam | DefKind::ConstParam, param_def_id) = path.res { self.resolve_type_ref(param_def_id.expect_local(), hir_id); } + Continue(()) } fn visit_fn( @@ -885,7 +882,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { body_id: hir::BodyId, _: Span, _: LocalDefId, - ) { + ) -> ControlFlow { let output = match fd.output { hir::FnRetTy::DefaultReturn(_) => None, hir::FnRetTy::Return(ty) => Some(ty), @@ -895,7 +892,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.visit_nested_body(body_id) } - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { + fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) -> ControlFlow { let scope = Scope::TraitRefBoundary { s: self.scope }; self.with(scope, |this| { for param in generics.params { @@ -949,7 +946,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { this.with(scope, |this| { this.visit_ty(&bounded_ty); walk_list!(this, visit_param_bound, bounds); - }) + Continue(()) + }); } &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { lifetime, @@ -997,10 +995,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } } + Continue(()) }) } - fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { + fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) -> ControlFlow { match bound { hir::GenericBound::LangItemTrait(_, _, hir_id, _) => { // FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go @@ -1018,16 +1017,15 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { scope_type, where_bound_origin: None, }; - self.with(scope, |this| { - intravisit::walk_param_bound(this, bound); - }); + self.with(scope, |this| intravisit::walk_param_bound(this, bound)) } _ => intravisit::walk_param_bound(self, bound), } } - fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) { + fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow { self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow); + Continue(()) } } @@ -1077,16 +1075,16 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifeti } impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { - fn with(&mut self, wrap_scope: Scope<'_>, f: F) + fn with(&mut self, wrap_scope: Scope<'_>, f: F) -> R where - F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>), + F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>) -> R, { let BoundVarContext { tcx, map, .. } = self; let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope }; let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); { let _enter = span.enter(); - f(&mut this); + f(&mut this) } } @@ -1117,13 +1115,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { /// already in scope (for a fn item, that will be 0, but for a method it might not be). Late /// bound lifetimes are resolved by name and associated with a binder ID (`binder_id`), so the /// ordering is not important there. - fn visit_early_late( + fn visit_early_late( &mut self, hir_id: hir::HirId, generics: &'tcx hir::Generics<'tcx>, walk: F, - ) where - F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>), + ) -> R + where + F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>) -> R, { let mut named_late_bound_vars = 0; let bound_vars: FxIndexMap = generics @@ -1166,7 +1165,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, where_bound_origin: None, }; - self.with(scope, walk); + self.with(scope, walk) } #[instrument(level = "debug", skip(self))] @@ -1823,7 +1822,6 @@ fn is_late_bound_map( arg_is_constrained: Box<[bool]>, } - use std::ops::ControlFlow; use ty::Ty; impl<'tcx> TypeVisitor> for ConstrainedCollectorPostAstConv { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { @@ -1857,7 +1855,7 @@ fn is_late_bound_map( } impl<'v> Visitor<'v> for ConstrainedCollector<'_> { - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> ControlFlow { match ty.kind { hir::TyKind::Path( hir::QPath::Resolved(Some(_), _) | hir::QPath::TypeRelative(..), @@ -1923,12 +1921,14 @@ fn is_late_bound_map( intravisit::walk_ty(self, ty); } } + Continue(()) } - fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) -> ControlFlow { if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { self.regions.insert(def_id); } + Continue(()) } } @@ -1938,10 +1938,11 @@ fn is_late_bound_map( } impl<'v> Visitor<'v> for AllCollector { - fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) -> ControlFlow { if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { self.regions.insert(def_id); } + Continue(()) } } } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 50073d94ea5c9..8cad207e46327 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{ }; use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; +use std::ops::ControlFlow::{self, Continue}; use super::ItemCtxt; use super::{bad_placeholder, is_suggestable_infer_ty}; @@ -635,32 +636,34 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Closure(closure) = ex.kind { self.check(closure.def_id); } - intravisit::walk_expr(self, ex); + intravisit::walk_expr(self, ex) } - fn visit_item(&mut self, it: &'tcx Item<'tcx>) { + fn visit_item(&mut self, it: &'tcx Item<'tcx>) -> ControlFlow { trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. if it.owner_id.def_id != self.def_id { self.check(it.owner_id.def_id); intravisit::walk_item(self, it); } + Continue(()) } - fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { + fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) -> ControlFlow { trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. if it.owner_id.def_id != self.def_id { self.check(it.owner_id.def_id); intravisit::walk_impl_item(self, it); } + Continue(()) } - fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { + fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) -> ControlFlow { trace!(?it.owner_id); self.check(it.owner_id.def_id); - intravisit::walk_trait_item(self, it); + intravisit::walk_trait_item(self, it) } } @@ -689,9 +692,15 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T // // requires us to explicitly process `foo()` in order // to notice the defining usage of `Blah`. - Node::Item(it) => locator.visit_item(it), - Node::ImplItem(it) => locator.visit_impl_item(it), - Node::TraitItem(it) => locator.visit_trait_item(it), + Node::Item(it) => { + locator.visit_item(it); + } + Node::ImplItem(it) => { + locator.visit_impl_item(it); + } + Node::TraitItem(it) => { + locator.visit_trait_item(it); + } other => bug!("{:?} is not a valid scope for an opaque type item", other), } } @@ -769,32 +778,34 @@ fn find_opaque_ty_constraints_for_rpit( fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Closure(closure) = ex.kind { self.check(closure.def_id); } - intravisit::walk_expr(self, ex); + intravisit::walk_expr(self, ex) } - fn visit_item(&mut self, it: &'tcx Item<'tcx>) { + fn visit_item(&mut self, it: &'tcx Item<'tcx>) -> ControlFlow { trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. if it.owner_id.def_id != self.def_id { self.check(it.owner_id.def_id); intravisit::walk_item(self, it); } + Continue(()) } - fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { + fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) -> ControlFlow { trace!(?it.owner_id); // The opaque type itself or its children are not within its reveal scope. if it.owner_id.def_id != self.def_id { self.check(it.owner_id.def_id); intravisit::walk_impl_item(self, it); } + Continue(()) } - fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { + fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) -> ControlFlow { trace!(?it.owner_id); self.check(it.owner_id.def_id); - intravisit::walk_trait_item(self, it); + intravisit::walk_trait_item(self, it) } } @@ -806,9 +817,15 @@ fn find_opaque_ty_constraints_for_rpit( let mut locator = ConstraintChecker { def_id, tcx, found: concrete }; match tcx.hir().get(scope) { - Node::Item(it) => intravisit::walk_item(&mut locator, it), - Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it), - Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it), + Node::Item(it) => { + intravisit::walk_item(&mut locator, it); + } + Node::ImplItem(it) => { + intravisit::walk_impl_item(&mut locator, it); + } + Node::TraitItem(it) => { + intravisit::walk_trait_item(&mut locator, it); + } other => bug!("{:?} is not a valid scope for an opaque type item", other), } } diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index e330fcc785770..9d403d2fe88ae 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits; +use std::ops::ControlFlow::{self, Continue}; pub fn provide(providers: &mut Providers) { *providers = Providers { diagnostic_hir_wf_check, ..*providers }; @@ -64,7 +65,7 @@ fn diagnostic_hir_wf_check<'tcx>( } impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow { let infcx = self.tcx.infer_ctxt().build(); let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( @@ -98,6 +99,7 @@ fn diagnostic_hir_wf_check<'tcx>( self.depth += 1; intravisit::walk_ty(self, ty); self.depth -= 1; + Continue(()) } } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 00b86890b33f4..1fd04c9b07ff5 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -67,6 +67,7 @@ use rustc_trait_selection::traits::{ }; use smallvec::{smallvec, SmallVec}; +use std::ops::ControlFlow; use std::ops::Deref; struct Coerce<'a, 'tcx> { @@ -96,11 +97,11 @@ struct CollectRetsVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Ret(_) = expr.kind { self.ret_exprs.push(expr); } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } } diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 34d62987c3b0a..b03c680c0867c 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -27,6 +27,7 @@ use super::method::probe; use std::cmp::min; use std::iter; +use std::ops::ControlFlow; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn emit_type_mismatch_suggestions( @@ -247,14 +248,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { uses: Vec<&'hir hir::Expr<'hir>>, } impl<'v> Visitor<'v> for FindExprs<'v> { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> ControlFlow { if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind && let hir::def::Res::Local(hir_id) = path.res && hir_id == self.hir_id { self.uses.push(ex); } - hir::intravisit::walk_expr(self, ex); + hir::intravisit::walk_expr(self, ex) } } diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 38445f2844052..85f38ba76f775 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::UserType; use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_trait_selection::traits; +use std::ops::ControlFlow::{self, Continue}; /// A declaration is an abstraction of [hir::Local] and [hir::Let]. /// @@ -103,24 +104,25 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // Add explicitly-declared locals. - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) -> ControlFlow { self.declare(local.into()); intravisit::walk_local(self, local) } - fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) { + fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) -> ControlFlow { self.declare(let_expr.into()); - intravisit::walk_let_expr(self, let_expr); + intravisit::walk_let_expr(self, let_expr) } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> ControlFlow { let old_outermost_fn_param_pat = self.outermost_fn_param_pat.replace(param.ty_span); intravisit::walk_param(self, param); self.outermost_fn_param_pat = old_outermost_fn_param_pat; + Continue(()) } // Add pattern bindings. - fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) -> ControlFlow { if let PatKind::Binding(_, _, ident, _) = p.kind { let var_ty = self.assign(p.span, p.hir_id, None); @@ -148,6 +150,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { let old_outermost_fn_param_pat = self.outermost_fn_param_pat.take(); intravisit::walk_pat(self, p); self.outermost_fn_param_pat = old_outermost_fn_param_pat; + Continue(()) } // Don't descend into the bodies of nested closures. @@ -158,6 +161,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { _: hir::BodyId, _: Span, _: LocalDefId, - ) { + ) -> ControlFlow { + Continue(()) } } diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs index 7c0402b1c7fb8..cbe63aed7e25f 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs @@ -15,6 +15,7 @@ use rustc_middle::{ ty::{ParamEnv, TyCtxt, TypeVisitableExt, TypeckResults}, }; use std::mem::swap; +use std::ops::ControlFlow::{self, Continue}; /// Traverses the body to find the control flow graph and locations for the /// relevant places are dropped or reinitialized. @@ -300,7 +301,7 @@ fn find_last_block_expression(block: &hir::Block<'_>) -> HirId { } impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { let mut reinit = None; match expr.kind { ExprKind::Assign(lhs, rhs, _) => { @@ -369,7 +370,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { self.visit_pat(pat); // B -> C and E -> F are added implicitly due to the traversal order. match guard { - Some(Guard::If(expr)) => self.visit_expr(expr), + Some(Guard::If(expr)) => { + self.visit_expr(expr); + }, Some(Guard::IfLet(let_expr)) => { self.visit_let_expr(let_expr); } @@ -496,7 +499,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { | ExprKind::Tup(..) | ExprKind::Type(..) | ExprKind::Unary(..) - | ExprKind::Yield(..) => intravisit::walk_expr(self, expr), + | ExprKind::Yield(..) => { + intravisit::walk_expr(self, expr); + }, } self.expr_index = self.expr_index + 1; @@ -505,9 +510,10 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { if let Some(expr) = reinit { self.reinit_expr(expr); } + Continue(()) } - fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) -> ControlFlow { intravisit::walk_pat(self, pat); // Increment expr_count here to match what InteriorVisitor expects. @@ -515,6 +521,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { // Save a node mapping to get better CFG visualization self.drop_ranges.add_node_mapping(pat.hir_id, self.expr_index); + Continue(()) } } diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs index 2e41c2041f888..fd7862f99f649 100644 --- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs +++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVi use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::{smallvec, SmallVec}; +use std::ops::ControlFlow::{self, Continue}; mod drop_ranges; @@ -337,7 +338,7 @@ pub fn resolve_interior<'a, 'tcx>( // librustc_middle/middle/region.rs since `expr_count` is compared against the results // there. impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { - fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) { + fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) -> ControlFlow { let Arm { guard, pat, body, .. } = arm; self.visit_pat(pat); if let Some(ref g) = guard { @@ -353,7 +354,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { } impl<'a, 'b, 'tcx> Visitor<'tcx> for ArmPatCollector<'a, 'b, 'tcx> { - fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { + fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) -> ControlFlow { intravisit::walk_pat(self, pat); if let PatKind::Binding(_, id, ident, ..) = pat.kind { let ty = @@ -373,6 +374,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { ident.span, ); } + Continue(()) } } @@ -392,10 +394,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { } } } - self.visit_expr(body); + self.visit_expr(body) } - fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { + fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) -> ControlFlow { intravisit::walk_pat(self, pat); self.expr_count += 1; @@ -405,36 +407,31 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { let ty = self.fcx.typeck_results.borrow().pat_ty(pat); self.record(ty, pat.hir_id, Some(scope), None, pat.span); } + Continue(()) } - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - match &expr.kind { - ExprKind::Call(callee, args) => match &callee.kind { - ExprKind::Path(qpath) => { - let res = self.fcx.typeck_results.borrow().qpath_res(qpath, callee.hir_id); - match res { - // Direct calls never need to keep the callee `ty::FnDef` - // ZST in a temporary, so skip its type, just in case it - // can significantly complicate the generator type. - Res::Def( - DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn), - _, - ) => { - // NOTE(eddyb) this assumes a path expression has - // no nested expressions to keep track of. - self.expr_count += 1; - - // Record the rest of the call expression normally. - for arg in *args { - self.visit_expr(arg); - } - } - _ => intravisit::walk_expr(self, expr), - } - } - _ => intravisit::walk_expr(self, expr), - }, - _ => intravisit::walk_expr(self, expr), + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { + if let ExprKind::Call(callee, args) = expr.kind + && let ExprKind::Path(qpath) = &callee.kind + && let res = self.fcx.typeck_results.borrow().qpath_res(qpath, callee.hir_id) + // Direct calls never need to keep the callee `ty::FnDef` + // ZST in a temporary, so skip its type, just in case it + // can significantly complicate the generator type. + && let Res::Def( + DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn), + _, + ) = res + { + // NOTE(eddyb) this assumes a path expression has + // no nested expressions to keep track of. + self.expr_count += 1; + + // Record the rest of the call expression normally. + for arg in args { + self.visit_expr(arg); + } + } else { + intravisit::walk_expr(self, expr); } self.expr_count += 1; @@ -525,6 +522,8 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { } else { self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node"); } + + Continue(()) } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 47a4d4e72dffd..c172e2940cb2e 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -44,6 +44,7 @@ use super::{CandidateSource, MethodError, NoMatchData}; use rustc_hir::intravisit::Visitor; use std::cmp::Ordering; use std::iter; +use std::ops::ControlFlow::{self, Continue}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { @@ -1628,14 +1629,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: This really should be taking scoping, etc into account. impl<'v> Visitor<'v> for LetVisitor<'v> { - fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { + fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> ControlFlow { if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind && let Binding(_, _, ident, ..) = pat.kind && ident.name == self.ident_name { self.result = *init; + Continue(()) } else { - hir::intravisit::walk_stmt(self, ex); + hir::intravisit::walk_stmt(self, ex) } } } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 3e27a78135e49..01b772122afb0 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -53,6 +53,7 @@ use rustc_index::vec::Idx; use rustc_target::abi::VariantIdx; use std::iter; +use std::ops::ControlFlow; /// Describe the relationship between the paths of two places /// eg: @@ -138,7 +139,7 @@ struct InferBorrowKindVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { match expr.kind { hir::ExprKind::Closure(&hir::Closure { capture_clause, body: body_id, .. }) => { let body = self.fcx.tcx.hir().body(body_id); @@ -152,7 +153,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { _ => {} } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 00348f3afdc44..92d71308f630f 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -21,7 +21,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use std::mem; -use std::ops::ControlFlow; +use std::ops::ControlFlow::{self, Continue}; /////////////////////////////////////////////////////////////////////////// // Entry point @@ -278,7 +278,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // traffic in node-ids or update typeck results in the type context etc. impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { - fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> ControlFlow { self.fix_scalar_builtin_expr(e); self.fix_index_builtin_expr(e); @@ -309,10 +309,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { } self.visit_node_id(e.span, e.hir_id); - intravisit::walk_expr(self, e); + intravisit::walk_expr(self, e) } - fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) -> ControlFlow { match &p.kind { hir::GenericParamKind::Lifetime { .. } => { // Nothing to write back here @@ -321,14 +321,15 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { self.tcx().sess.delay_span_bug(p.span, format!("unexpected generic param: {p:?}")); } } + Continue(()) } - fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { + fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> ControlFlow { self.visit_node_id(b.span, b.hir_id); - intravisit::walk_block(self, b); + intravisit::walk_block(self, b) } - fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) -> ControlFlow { match p.kind { hir::PatKind::Binding(..) => { let typeck_results = self.fcx.typeck_results.borrow(); @@ -349,17 +350,18 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { self.visit_pat_adjustments(p.span, p.hir_id); self.visit_node_id(p.span, p.hir_id); - intravisit::walk_pat(self, p); + intravisit::walk_pat(self, p) } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) -> ControlFlow { intravisit::walk_local(self, l); let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty; let var_ty = self.resolve(var_ty, &l.span); self.write_ty_to_typeck_results(l.hir_id, var_ty); + Continue(()) } - fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) -> ControlFlow { intravisit::walk_ty(self, hir_ty); // If there are type checking errors, Type privacy pass will stop, // so we may not get the type from hid_id, see #104513 @@ -367,15 +369,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { let ty = self.resolve(ty, &hir_ty.span); self.write_ty_to_typeck_results(hir_ty.hir_id, ty); } + Continue(()) } - fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) -> ControlFlow { intravisit::walk_inf(self, inf); // Ignore cases where the inference is a const. if let Some(ty) = self.fcx.node_ty_opt(inf.hir_id) { let ty = self.resolve(ty, &inf.span); self.write_ty_to_typeck_results(inf.hir_id, ty); } + Continue(()) } } diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 22bd12f2e6361..bbf8b3b446aab 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -52,6 +52,7 @@ use rustc_span::Span; use std::env; use std::fs::{self, File}; use std::io::{BufWriter, Write}; +use std::ops::ControlFlow; #[allow(missing_docs)] pub fn assert_dep_graph(tcx: TyCtxt<'_>) { @@ -176,24 +177,24 @@ impl<'tcx> Visitor<'tcx> for IfThisChanged<'tcx> { self.tcx.hir() } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { self.process_attrs(item.owner_id.def_id); - intravisit::walk_item(self, item); + intravisit::walk_item(self, item) } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { self.process_attrs(trait_item.owner_id.def_id); - intravisit::walk_trait_item(self, trait_item); + intravisit::walk_trait_item(self, trait_item) } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { self.process_attrs(impl_item.owner_id.def_id); - intravisit::walk_impl_item(self, impl_item); + intravisit::walk_impl_item(self, impl_item) } - fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) -> ControlFlow { self.process_attrs(s.def_id); - intravisit::walk_field_def(self, s); + intravisit::walk_field_def(self, s) } } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index b839416c91957..d1872c31bc125 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -32,6 +32,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::iter::FromIterator; +use std::ops::ControlFlow::{self, Continue}; use thin_vec::ThinVec; const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk; @@ -461,9 +462,10 @@ impl<'tcx> intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> { self.tcx.hir() } - fn visit_attribute(&mut self, attr: &'tcx Attribute) { + fn visit_attribute(&mut self, attr: &'tcx Attribute) -> ControlFlow { if self.is_active_attr(attr) { self.found_attrs.push(attr); } + Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 79efc1ce7bfc0..1d9c097692fcd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -76,7 +76,10 @@ use rustc_middle::ty::{ }; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; -use std::ops::{ControlFlow, Deref}; +use std::ops::{ + ControlFlow::{self, Break, Continue}, + Deref, +}; use std::path::PathBuf; use std::{cmp, fmt, iter}; @@ -2006,15 +2009,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .. })) => { let body = hir.body(*body_id); - struct LetVisitor<'v> { + struct LetVisitor { span: Span, - result: Option<&'v hir::Ty<'v>>, } - impl<'v> Visitor<'v> for LetVisitor<'v> { - fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { - if self.result.is_some() { - return; - } + impl<'v> Visitor<'v> for LetVisitor { + type BreakTy = &'v hir::Ty<'v>; + + fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> ControlFlow { // Find a local statement where the initializer has // the same span as the error and the type is specified. if let hir::Stmt { @@ -2029,13 +2030,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .. } = s && init_span == &self.span { - self.result = Some(*array_ty); + Break(*array_ty) + } else { + Continue(()) } } } - let mut visitor = LetVisitor {span, result: None}; - visitor.visit_body(body); - visitor.result.map(|r| &r.peel_refs().kind) + let mut visitor = LetVisitor {span }; + visitor.visit_body(body).break_value().map(|r| &r.peel_refs().kind) } Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index e242900fd2329..4959d23e2ff9d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -24,6 +24,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span}; use std::borrow::Cow; use std::iter; +use std::ops::ControlFlow::{self, Continue}; pub enum TypeAnnotationNeeded { /// ```compile_fail,E0282 @@ -1111,8 +1112,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { self.infcx.tcx.hir() } - fn visit_local(&mut self, local: &'tcx Local<'tcx>) { - intravisit::walk_local(self, local); + fn visit_local(&mut self, local: &'tcx Local<'tcx>) -> ControlFlow { + intravisit::walk_local(self, local)?; if let Some(ty) = self.opt_node_type(local.hir_id) { if self.generic_arg_contains_target(ty.into()) { @@ -1132,11 +1133,13 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { } } } + + Continue(()) } /// For closures, we first visit the parameters and then the content, /// as we prefer those. - fn visit_body(&mut self, body: &'tcx Body<'tcx>) { + fn visit_body(&mut self, body: &'tcx Body<'tcx>) -> ControlFlow { for param in body.params { debug!( "param: span {:?}, ty_span {:?}, pat.span {:?}", @@ -1161,22 +1164,22 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { }) } } - intravisit::walk_body(self, body); + intravisit::walk_body(self, body) } #[instrument(level = "debug", skip(self))] - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { let tcx = self.infcx.tcx; match expr.kind { // When encountering `func(arg)` first look into `arg` and then `func`, // as `arg` is "more specific". ExprKind::Call(func, args) => { for arg in args { - self.visit_expr(arg); + self.visit_expr(arg)?; } - self.visit_expr(func); + self.visit_expr(func)?; } - _ => intravisit::walk_expr(self, expr), + _ => intravisit::walk_expr(self, expr)?, } for args in self.expr_inferred_subst_iter(expr) { @@ -1268,5 +1271,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { } }) } + + Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index fec04af231393..8b34234a37597 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -4,6 +4,7 @@ use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::{self, Region, TyCtxt}; +use std::ops::ControlFlow::{self, Break, Continue}; /// This function calls the `visit_ty` method for the parameters /// corresponding to the anonymous regions. The `nested_visitor.found_type` @@ -79,19 +80,19 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { self.tcx.hir() } - fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> ControlFlow { match arg.kind { hir::TyKind::BareFn(_) => { self.current_index.shift_in(1); - intravisit::walk_ty(self, arg); + intravisit::walk_ty(self, arg)?; self.current_index.shift_out(1); - return; + return Continue(()); } hir::TyKind::TraitObject(bounds, ..) => { for bound in bounds { self.current_index.shift_in(1); - self.visit_poly_trait_ref(bound); + self.visit_poly_trait_ref(bound)?; self.current_index.shift_out(1); } } @@ -107,7 +108,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_type = Some(arg); - return; // we can stop visiting now + return Continue(()); // we can stop visiting now } } @@ -125,7 +126,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { debug!("LateBound id={:?} def_id={:?}", id, def_id); if debruijn_index == self.current_index && id == def_id { self.found_type = Some(arg); - return; // we can stop visiting now + return Continue(()); // we can stop visiting now } } @@ -148,13 +149,12 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { hir::TyKind::Path(_) => { let subvisitor = &mut TyPathVisitor { tcx: self.tcx, - found_it: false, bound_region: self.bound_region, current_index: self.current_index, }; - intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty, + // call walk_ty; as visit_ty is empty, // this will visit only outermost type - if subvisitor.found_it { + if intravisit::walk_ty(subvisitor, arg).is_break() { self.found_type = Some(arg); } } @@ -162,7 +162,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { } // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`, // go on to visit `&Foo` - intravisit::walk_ty(self, arg); + intravisit::walk_ty(self, arg) } } @@ -174,26 +174,25 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // specific part of the type in the error message. struct TyPathVisitor<'tcx> { tcx: TyCtxt<'tcx>, - found_it: bool, bound_region: ty::BoundRegionKind, current_index: ty::DebruijnIndex, } impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); fn nested_visit_map(&mut self) -> Map<'tcx> { self.tcx.hir() } - fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) -> ControlFlow<()> { match (self.tcx.named_bound_var(lifetime.hir_id), self.bound_region) { // the lifetime of the TyPath! (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { - self.found_it = true; - return; // we can stop visiting now + return Break(()); } } @@ -202,8 +201,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { debug!("id={:?}", id); debug!("def_id={:?}", def_id); if debruijn_index == self.current_index && id == def_id { - self.found_it = true; - return; // we can stop visiting now + return Break(()); } } @@ -221,9 +219,10 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { debug!("no arg found"); } } + Continue(()) } - fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> ControlFlow<()> { // ignore nested types // // If you have a type like `Foo<'a, &Ty>` we @@ -232,5 +231,6 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { // Making `visit_ty` empty will ignore the `&Ty` embedded // inside, it will get reached by the outer visitor. debug!("`Ty` corresponding to a struct is {:?}", arg); + Continue(()) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index b06ff10d86eb0..37ae4be2d0a4e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -557,7 +557,7 @@ impl<'tcx> TypeVisitor> for TraitObjectVisitor { pub struct HirTraitObjectVisitor<'a>(pub &'a mut Vec, pub DefId); impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { - fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> ControlFlow { if let TyKind::TraitObject( poly_trait_refs, Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. }, @@ -570,6 +570,6 @@ impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> { } } } - walk_ty(self, t); + walk_ty(self, t) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 2875448ee157c..f2704fec41b40 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -137,12 +137,11 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { self.tcx.hir() } - fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> ControlFlow { match arg.kind { hir::TyKind::Ref(_, ref mut_ty) => { // We don't want to suggest looking into borrowing `&T` or `&Self`. - hir::intravisit::walk_ty(self, mut_ty.ty); - return; + return hir::intravisit::walk_ty(self, mut_ty.ty); } hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { [segment] @@ -159,6 +158,6 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { }, _ => {} } - hir::intravisit::walk_ty(self, arg); + hir::intravisit::walk_ty(self, arg) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 55dcfd05e0ad3..ac78547423982 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -11,6 +11,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitableExt}; use rustc_span::{sym, BytePos, Span}; +use std::ops::ControlFlow::{self, Break, Continue}; + use crate::errors::{ ConsiderAddingAwait, SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding, }; @@ -504,51 +506,53 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { span: Span, ) { let hir = self.tcx.hir(); - if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) && - let hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_sig, _, body_id), .. - }) = node { - let body = hir.body(*body_id); - - /// Find the if expression with given span - struct IfVisitor { - pub result: bool, - pub found_if: bool, - pub err_span: Span, - } + if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) + && let hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_sig, _, body_id), .. + }) = node + { + let body = hir.body(*body_id); - impl<'v> Visitor<'v> for IfVisitor { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - if self.result { return; } - match ex.kind { - hir::ExprKind::If(cond, _, _) => { - self.found_if = true; - walk_expr(self, cond); - self.found_if = false; + /// Find the if expression with given span + struct IfVisitor { + pub found_if: bool, + pub err_span: Span, + } + + impl<'v> Visitor<'v> for IfVisitor { + type BreakTy = (); + + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> ControlFlow<()> { + match ex.kind { + hir::ExprKind::If(cond, _, _) => { + self.found_if = true; + walk_expr(self, cond)?; + self.found_if = false; + } + _ => walk_expr(self, ex)?, } - _ => walk_expr(self, ex), + Continue(()) } - } - fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { - if let hir::StmtKind::Local(hir::Local { - span, pat: hir::Pat{..}, ty: None, init: Some(_), .. - }) = &ex.kind - && self.found_if - && span.eq(&self.err_span) { - self.result = true; + fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> ControlFlow<()> { + if let hir::StmtKind::Local(hir::Local { + span, pat: hir::Pat{..}, ty: None, init: Some(_), .. + }) = &ex.kind + && self.found_if + && span.eq(&self.err_span) + { + return Break(()); + } + walk_stmt(self, ex) } - walk_stmt(self, ex); - } - fn visit_body(&mut self, body: &'v hir::Body<'v>) { - hir::intravisit::walk_body(self, body); + fn visit_body(&mut self, body: &'v hir::Body<'v>) -> ControlFlow<()> { + hir::intravisit::walk_body(self, body) + } } - } - let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; - visitor.visit_body(&body); - if visitor.result { + let mut visitor = IfVisitor { err_span: span, found_if: false }; + if visitor.visit_body(&body).is_break() { err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()}); } } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b42878a02ee02..03242a5601b1e 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -28,6 +28,7 @@ use rustc_span::Span; use std::any::Any; use std::cell::Cell; +use std::ops::ControlFlow::{self, Continue}; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the context. @@ -92,7 +93,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas self.context.tcx.hir() } - fn visit_nested_body(&mut self, body_id: hir::BodyId) { + fn visit_nested_body(&mut self, body_id: hir::BodyId) -> ControlFlow { let old_enclosing_body = self.context.enclosing_body.replace(body_id); let old_cached_typeck_results = self.context.cached_typeck_results.get(); @@ -111,21 +112,24 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas if old_enclosing_body != Some(body_id) { self.context.cached_typeck_results.set(old_cached_typeck_results); } + Continue(()) } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> ControlFlow { self.with_lint_attrs(param.hir_id, |cx| { hir_visit::walk_param(cx, param); }); + Continue(()) } - fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { + fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) -> ControlFlow { lint_callback!(self, check_body, body); hir_visit::walk_body(self, body); lint_callback!(self, check_body_post, body); + Continue(()) } - fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> ControlFlow { let generics = self.context.generics.take(); self.context.generics = it.kind.generics(); let old_cached_typeck_results = self.context.cached_typeck_results.take(); @@ -140,37 +144,40 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas self.context.enclosing_body = old_enclosing_body; self.context.cached_typeck_results.set(old_cached_typeck_results); self.context.generics = generics; + Continue(()) } - fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { self.with_lint_attrs(it.hir_id(), |cx| { cx.with_param_env(it.owner_id, |cx| { lint_callback!(cx, check_foreign_item, it); hir_visit::walk_foreign_item(cx, it); }); - }) + }); + Continue(()) } - fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) -> ControlFlow { lint_callback!(self, check_pat, p); - hir_visit::walk_pat(self, p); + hir_visit::walk_pat(self, p) } - fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> ControlFlow { self.with_lint_attrs(e.hir_id, |cx| { lint_callback!(cx, check_expr, e); hir_visit::walk_expr(cx, e); lint_callback!(cx, check_expr_post, e); - }) + }); + Continue(()) } - fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { + fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> ControlFlow { // See `EarlyContextAndPass::visit_stmt` for an explanation // of why we call `walk_stmt` outside of `with_lint_attrs` self.with_lint_attrs(s.hir_id, |cx| { lint_callback!(cx, check_stmt, s); }); - hir_visit::walk_stmt(self, s); + hir_visit::walk_stmt(self, s) } fn visit_fn( @@ -180,7 +187,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas body_id: hir::BodyId, span: Span, id: LocalDefId, - ) { + ) -> ControlFlow { // Wrap in typeck results here, not just in visit_nested_body, // in order for `check_fn` to be able to use them. let old_enclosing_body = self.context.enclosing_body.replace(body_id); @@ -190,80 +197,86 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_fn(self, fk, decl, body_id, id); self.context.enclosing_body = old_enclosing_body; self.context.cached_typeck_results.set(old_cached_typeck_results); + Continue(()) } - fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) { + fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) -> ControlFlow { lint_callback!(self, check_struct_def, s); - hir_visit::walk_struct_def(self, s); + hir_visit::walk_struct_def(self, s) } - fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) -> ControlFlow { self.with_lint_attrs(s.hir_id, |cx| { lint_callback!(cx, check_field_def, s); hir_visit::walk_field_def(cx, s); - }) + }); + Continue(()) } - fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) -> ControlFlow { self.with_lint_attrs(v.hir_id, |cx| { lint_callback!(cx, check_variant, v); hir_visit::walk_variant(cx, v); - }) + }); + Continue(()) } - fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> ControlFlow { lint_callback!(self, check_ty, t); - hir_visit::walk_ty(self, t); + hir_visit::walk_ty(self, t) } - fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { - hir_visit::walk_inf(self, inf); + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) -> ControlFlow { + hir_visit::walk_inf(self, inf) } - fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, n: hir::HirId) { + fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, n: hir::HirId) -> ControlFlow { if !self.context.only_module { self.process_mod(m, n); } + Continue(()) } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) -> ControlFlow { self.with_lint_attrs(l.hir_id, |cx| { lint_callback!(cx, check_local, l); hir_visit::walk_local(cx, l); - }) + }); + Continue(()) } - fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { + fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> ControlFlow { lint_callback!(self, check_block, b); hir_visit::walk_block(self, b); lint_callback!(self, check_block_post, b); + Continue(()) } - fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { + fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) -> ControlFlow { lint_callback!(self, check_arm, a); - hir_visit::walk_arm(self, a); + hir_visit::walk_arm(self, a) } - fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) -> ControlFlow { lint_callback!(self, check_generic_param, p); - hir_visit::walk_generic_param(self, p); + hir_visit::walk_generic_param(self, p) } - fn visit_generics(&mut self, g: &'tcx hir::Generics<'tcx>) { + fn visit_generics(&mut self, g: &'tcx hir::Generics<'tcx>) -> ControlFlow { lint_callback!(self, check_generics, g); - hir_visit::walk_generics(self, g); + hir_visit::walk_generics(self, g) } - fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate<'tcx>) { - hir_visit::walk_where_predicate(self, p); + fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate<'tcx>) -> ControlFlow { + hir_visit::walk_where_predicate(self, p) } - fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) { + fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow { lint_callback!(self, check_poly_trait_ref, t); - hir_visit::walk_poly_trait_ref(self, t); + hir_visit::walk_poly_trait_ref(self, t) } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { let generics = self.context.generics.take(); self.context.generics = Some(&trait_item.generics); self.with_lint_attrs(trait_item.hir_id(), |cx| { @@ -273,9 +286,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas }); }); self.context.generics = generics; + Continue(()) } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { let generics = self.context.generics.take(); self.context.generics = Some(&impl_item.generics); self.with_lint_attrs(impl_item.hir_id(), |cx| { @@ -286,19 +300,21 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas }); }); self.context.generics = generics; + Continue(()) } - fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { - hir_visit::walk_lifetime(self, lt); + fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow { + hir_visit::walk_lifetime(self, lt) } - fn visit_path(&mut self, p: &hir::Path<'tcx>, id: hir::HirId) { + fn visit_path(&mut self, p: &hir::Path<'tcx>, id: hir::HirId) -> ControlFlow { lint_callback!(self, check_path, p, id); - hir_visit::walk_path(self, p); + hir_visit::walk_path(self, p) } - fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) { + fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) -> ControlFlow { lint_callback!(self, check_attribute, attr); + Continue(()) } } @@ -376,7 +392,7 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( // Visit the crate attributes if hir_id == hir::CRATE_HIR_ID { for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() { - cx.visit_attribute(attr) + cx.visit_attribute(attr); } } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index bc7488fab4a5c..27d2873bcbd8f 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -31,6 +31,7 @@ use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use std::ops::ControlFlow; use crate::errors::{ MalformedAttribute, MalformedAttributeSub, OverruledAttribute, OverruledAttributeSub, @@ -172,13 +173,21 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe // a standard visit. // FIXME(#102522) Just iterate on attrs once that iteration order matches HIR's. _ => match tcx.hir().owner(owner) { - hir::OwnerNode::Item(item) => levels.visit_item(item), - hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item), - hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item), - hir::OwnerNode::ImplItem(item) => levels.visit_impl_item(item), + hir::OwnerNode::Item(item) => { + levels.visit_item(item); + } + hir::OwnerNode::ForeignItem(item) => { + levels.visit_foreign_item(item); + } + hir::OwnerNode::TraitItem(item) => { + levels.visit_trait_item(item); + } + hir::OwnerNode::ImplItem(item) => { + levels.visit_impl_item(item); + } hir::OwnerNode::Crate(mod_) => { levels.add_id(hir::CRATE_HIR_ID); - levels.visit_mod(mod_, mod_.spans.inner_span, hir::CRATE_HIR_ID) + levels.visit_mod(mod_, mod_.spans.inner_span, hir::CRATE_HIR_ID); } }, } @@ -295,61 +304,61 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { self.provider.tcx.hir() } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> ControlFlow { self.add_id(param.hir_id); - intravisit::walk_param(self, param); + intravisit::walk_param(self, param) } - fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> ControlFlow { self.add_id(it.hir_id()); - intravisit::walk_item(self, it); + intravisit::walk_item(self, it) } - fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { self.add_id(it.hir_id()); - intravisit::walk_foreign_item(self, it); + intravisit::walk_foreign_item(self, it) } - fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { + fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) -> ControlFlow { // We will call `add_id` when we walk // the `StmtKind`. The outer statement itself doesn't // define the lint levels. - intravisit::walk_stmt(self, e); + intravisit::walk_stmt(self, e) } - fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> ControlFlow { self.add_id(e.hir_id); - intravisit::walk_expr(self, e); + intravisit::walk_expr(self, e) } - fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) -> ControlFlow { self.add_id(s.hir_id); - intravisit::walk_field_def(self, s); + intravisit::walk_field_def(self, s) } - fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) -> ControlFlow { self.add_id(v.hir_id); - intravisit::walk_variant(self, v); + intravisit::walk_variant(self, v) } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) -> ControlFlow { self.add_id(l.hir_id); - intravisit::walk_local(self, l); + intravisit::walk_local(self, l) } - fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { + fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) -> ControlFlow { self.add_id(a.hir_id); - intravisit::walk_arm(self, a); + intravisit::walk_arm(self, a) } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { self.add_id(trait_item.hir_id()); - intravisit::walk_trait_item(self, trait_item); + intravisit::walk_trait_item(self, trait_item) } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { self.add_id(impl_item.hir_id()); - intravisit::walk_impl_item(self, impl_item); + intravisit::walk_impl_item(self, impl_item) } } @@ -367,61 +376,61 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<' self.provider.tcx.hir() } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> ControlFlow { self.add_id(param.hir_id); - intravisit::walk_param(self, param); + intravisit::walk_param(self, param) } - fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> ControlFlow { self.add_id(it.hir_id()); - intravisit::walk_item(self, it); + intravisit::walk_item(self, it) } - fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { self.add_id(it.hir_id()); - intravisit::walk_foreign_item(self, it); + intravisit::walk_foreign_item(self, it) } - fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { + fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) -> ControlFlow { // We will call `add_id` when we walk // the `StmtKind`. The outer statement itself doesn't // define the lint levels. - intravisit::walk_stmt(self, e); + intravisit::walk_stmt(self, e) } - fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> ControlFlow { self.add_id(e.hir_id); - intravisit::walk_expr(self, e); + intravisit::walk_expr(self, e) } - fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) -> ControlFlow { self.add_id(s.hir_id); - intravisit::walk_field_def(self, s); + intravisit::walk_field_def(self, s) } - fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) -> ControlFlow { self.add_id(v.hir_id); - intravisit::walk_variant(self, v); + intravisit::walk_variant(self, v) } - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) -> ControlFlow { self.add_id(l.hir_id); - intravisit::walk_local(self, l); + intravisit::walk_local(self, l) } - fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { + fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) -> ControlFlow { self.add_id(a.hir_id); - intravisit::walk_arm(self, a); + intravisit::walk_arm(self, a) } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { self.add_id(trait_item.hir_id()); - intravisit::walk_trait_item(self, trait_item); + intravisit::walk_trait_item(self, trait_item) } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { self.add_id(impl_item.hir_id()); - intravisit::walk_impl_item(self, impl_item); + intravisit::walk_impl_item(self, impl_item) } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 20ab0af585651..d46e07b509f1f 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{ }; use rustc_session::parse::ParseSess; use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol}; +use std::ops::ControlFlow; use crate::{ builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext, @@ -296,7 +297,7 @@ impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> { qpath: &rustc_hir::QPath<'_>, id: rustc_hir::HirId, span: Span, - ) { + ) -> ControlFlow { if TypeAliasBounds::is_type_variable_assoc(qpath) { self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f0dafe73c004e..1bfa322bf0a9b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -44,6 +44,7 @@ use std::hash::Hash; use std::io::{Read, Seek, Write}; use std::iter; use std::num::NonZeroUsize; +use std::ops::ControlFlow::{self, Continue}; use std::path::{Path, PathBuf}; pub(super) struct EncodeContext<'a, 'tcx> { @@ -2014,24 +2015,28 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() } - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> ControlFlow { intravisit::walk_expr(self, ex); self.encode_info_for_expr(ex); + Continue(()) } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { intravisit::walk_item(self, item); match item.kind { hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these _ => self.encode_info_for_item(item.owner_id.to_def_id(), item), } + Continue(()) } - fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { intravisit::walk_foreign_item(self, ni); self.encode_info_for_foreign_item(ni.owner_id.to_def_id(), ni); + Continue(()) } - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { + fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) -> ControlFlow { intravisit::walk_generics(self, generics); self.encode_info_for_generics(generics); + Continue(()) } } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 4b5bacac8149c..e85146888f06e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -16,6 +16,7 @@ use rustc_span::def_id::StableCrateId; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::spec::abi::Abi; +use std::ops::ControlFlow::{self, Continue}; #[inline] pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> { @@ -540,23 +541,27 @@ impl<'hir> Map<'hir> { } /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`. - pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) { + pub fn walk_toplevel_module>( + self, + visitor: &mut V, + ) -> ControlFlow { let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID); - visitor.visit_mod(top_mod, span, hir_id); + visitor.visit_mod(top_mod, span, hir_id) } /// Walks the attributes in a crate. - pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) { + pub fn walk_attributes>(self, visitor: &mut V) -> ControlFlow { let krate = self.krate(); for info in krate.owners.iter() { if let MaybeOwner::Owner(info) = info { for attrs in info.attrs.map.values() { for a in *attrs { - visitor.visit_attribute(a) + visitor.visit_attribute(a)?; } } } } + Continue(()) } /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you @@ -1380,7 +1385,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { self.tcx.hir() } - fn visit_item(&mut self, item: &'hir Item<'hir>) { + fn visit_item(&mut self, item: &'hir Item<'hir>) -> ControlFlow { if associated_body(Node::Item(item)).is_some() { self.body_owners.push(item.owner_id.def_id); } @@ -1392,31 +1397,32 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { self.submodules.push(item.owner_id); // A module collector does not recurse inside nested modules. if self.crate_collector { - intravisit::walk_mod(self, module, item.hir_id()); + intravisit::walk_mod(self, module, item.hir_id())?; } } else { - intravisit::walk_item(self, item) + intravisit::walk_item(self, item)?; } + Continue(()) } - fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) { + fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) -> ControlFlow { self.foreign_items.push(item.foreign_item_id()); intravisit::walk_foreign_item(self, item) } - fn visit_anon_const(&mut self, c: &'hir AnonConst) { + fn visit_anon_const(&mut self, c: &'hir AnonConst) -> ControlFlow { self.body_owners.push(c.def_id); intravisit::walk_anon_const(self, c) } - fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { + fn visit_expr(&mut self, ex: &'hir Expr<'hir>) -> ControlFlow { if let ExprKind::Closure(closure) = ex.kind { self.body_owners.push(closure.def_id); } intravisit::walk_expr(self, ex) } - fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) { + fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) -> ControlFlow { if associated_body(Node::TraitItem(item)).is_some() { self.body_owners.push(item.owner_id.def_id); } @@ -1425,7 +1431,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { intravisit::walk_trait_item(self, item) } - fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) { + fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) -> ControlFlow { if associated_body(Node::ImplItem(item)).is_some() { self.body_owners.push(item.owner_id.def_id); } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index e894e1aaf3695..ec2d01a009586 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -1,6 +1,6 @@ //! Diagnostics related methods for `Ty`. -use std::ops::ControlFlow; +use std::ops::ControlFlow::{self, Continue}; use crate::ty::{ AliasTy, Const, ConstKind, DefIdTree, FallibleTypeFolder, InferConst, InferTy, Opaque, @@ -419,7 +419,7 @@ pub fn suggest_constraining_type_params<'a>( pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>); impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> ControlFlow { match ty.kind { hir::TyKind::TraitObject( _, @@ -435,11 +435,11 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { hir::TyKind::OpaqueDef(item_id, _, _) => { self.0.push(ty); let item = self.1.item(item_id); - hir::intravisit::walk_item(self, item); + hir::intravisit::walk_item(self, item)?; } _ => {} } - hir::intravisit::walk_ty(self, ty); + hir::intravisit::walk_ty(self, ty) } } @@ -447,11 +447,12 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { pub struct StaticLifetimeVisitor<'tcx>(pub Vec, pub crate::hir::map::Map<'tcx>); impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { - fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) { + fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) -> ControlFlow { if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res { self.0.push(lt.ident.span); } + Continue(()) } } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index e10a264d385d0..538e31815df89 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -8,6 +8,7 @@ #![feature(if_let_guard)] #![feature(let_chains)] #![feature(min_specialization)] +#![feature(never_type)] #![feature(once_cell)] #![feature(try_blocks)] #![recursion_limit = "256"] 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 2640ca56b00e9..5b56633d02cf8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -26,6 +26,7 @@ use rustc_session::lint::builtin::{ use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_span::{BytePos, Span}; +use std::ops::ControlFlow::{self, Continue}; pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match def_id.as_local() { @@ -66,7 +67,7 @@ struct MatchVisitor<'a, 'p, 'tcx> { } impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> ControlFlow { intravisit::walk_expr(self, ex); match &ex.kind { hir::ExprKind::Match(scrut, arms, source) => { @@ -77,9 +78,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { } _ => {} } + Continue(()) } - fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) -> ControlFlow { intravisit::walk_local(self, loc); let els = loc.els; if let Some(init) = loc.init && els.is_some() { @@ -98,11 +100,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { if els.is_none() { self.check_irrefutable(&loc.pat, msg, sp); } + Continue(()) } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> ControlFlow { intravisit::walk_param(self, param); self.check_irrefutable(¶m.pat, "function argument", None); + Continue(()) } } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index d00ee1f4babe8..e51df66fef3f3 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -14,6 +14,7 @@ use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; use std::ops::Bound; +use std::ops::ControlFlow::{self, Continue}; pub struct UnsafetyChecker<'a, 'tcx> { body: &'a Body<'tcx>, @@ -413,7 +414,7 @@ struct UnusedUnsafeVisitor<'a, 'tcx> { } impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { - fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { + fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) -> ControlFlow { if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules { let used = match self.tcx.lint_level_at_node(UNUSED_UNSAFE, block.hir_id) { (Level::Allow, _) => true, @@ -426,19 +427,20 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { self.context = Context::UnsafeBlock(block.hir_id); intravisit::walk_block(self, block); self.context = previous_context; - return; + return Continue(()); } (Context::UnsafeBlock(hir_id), true) => UnusedUnsafe::InUnsafeBlock(hir_id), }; self.unused_unsafes.push((block.hir_id, unused_unsafe)); } - intravisit::walk_block(self, block); + intravisit::walk_block(self, block) } - fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) -> ControlFlow { if matches!(self.tcx.def_kind(c.def_id), DefKind::InlineConst) { - self.visit_body(self.tcx.hir().body(c.body)) + self.visit_body(self.tcx.hir().body(c.body)); } + Continue(()) } fn visit_fn( @@ -448,10 +450,11 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { b: hir::BodyId, _s: rustc_span::Span, _id: LocalDefId, - ) { + ) -> ControlFlow { if matches!(fk, intravisit::FnKind::Closure) { - self.visit_body(self.tcx.hir().body(b)) + self.visit_body(self.tcx.hir().body(b)); } + Continue(()) } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4193eb7d6e878..313271089f173 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -37,6 +37,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; +use std::ops::ControlFlow; #[macro_use] mod pass_manager; @@ -226,7 +227,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { set: &'a mut FxIndexSet, } impl<'tcx> Visitor<'tcx> for GatherCtors<'_> { - fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) { + fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) -> ControlFlow { if let hir::VariantData::Tuple(_, _, def_id) = *v { self.set.insert(def_id); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5ef3e13eff801..d08bea34eca4d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -32,6 +32,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use std::cell::Cell; use std::collections::hash_map::Entry; +use std::ops::ControlFlow; pub(crate) fn target_from_impl_item<'tcx>( tcx: TyCtxt<'tcx>, @@ -2293,7 +2294,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { self.tcx.hir() } - fn visit_item(&mut self, item: &'tcx Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx Item<'tcx>) -> ControlFlow { // Historically we've run more checks on non-exported than exported macros, // so this lets us continue to run them while maintaining backwards compatibility. // In the long run, the checks should be harmonized. @@ -2309,41 +2310,44 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_item(self, item) } - fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) { + fn visit_generic_param( + &mut self, + generic_param: &'tcx hir::GenericParam<'tcx>, + ) -> ControlFlow { let target = Target::from_generic_param(generic_param); self.check_attributes(generic_param.hir_id, generic_param.span, target, None); intravisit::walk_generic_param(self, generic_param) } - fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) { + fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) -> ControlFlow { let target = Target::from_trait_item(trait_item); self.check_attributes(trait_item.hir_id(), trait_item.span, target, None); intravisit::walk_trait_item(self, trait_item) } - fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) { + fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) -> ControlFlow { self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None); - intravisit::walk_field_def(self, struct_field); + intravisit::walk_field_def(self, struct_field) } - fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { + fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ControlFlow { self.check_attributes(arm.hir_id, arm.span, Target::Arm, None); - intravisit::walk_arm(self, arm); + intravisit::walk_arm(self, arm) } - fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) -> ControlFlow { let target = Target::from_foreign_item(f_item); self.check_attributes(f_item.hir_id(), f_item.span, target, Some(ItemLike::ForeignItem)); intravisit::walk_foreign_item(self, f_item) } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { let target = target_from_impl_item(self.tcx, impl_item); self.check_attributes(impl_item.hir_id(), impl_item.span, target, None); intravisit::walk_impl_item(self, impl_item) } - fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) -> ControlFlow { // When checking statements ignore expressions, they will be checked later. if let hir::StmtKind::Local(ref l) = stmt.kind { self.check_attributes(l.hir_id, stmt.span, Target::Statement, None); @@ -2351,7 +2355,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_stmt(self, stmt) } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { let target = match expr.kind { hir::ExprKind::Closure { .. } => Target::Closure, _ => Target::Expression, @@ -2361,25 +2365,25 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_expr(self, expr) } - fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { + fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) -> ControlFlow { self.check_attributes(field.hir_id, field.span, Target::ExprField, None); intravisit::walk_expr_field(self, field) } - fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) { + fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) -> ControlFlow { self.check_attributes(variant.hir_id, variant.span, Target::Variant, None); intravisit::walk_variant(self, variant) } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> ControlFlow { self.check_attributes(param.hir_id, param.span, Target::Param, None); - intravisit::walk_param(self, param); + intravisit::walk_param(self, param) } - fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) { + fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) -> ControlFlow { self.check_attributes(field.hir_id, field.span, Target::PatField, None); - intravisit::walk_pat_field(self, field); + intravisit::walk_pat_field(self, field) } } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 526b829bf676a..bd91a9c845ed6 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -17,6 +17,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; +use std::ops::ControlFlow::{self, Continue}; + use crate::errors::{ExprNotAllowedInContext, SkippingConstChecks}; /// An expression that is not *always* legal in a const context. @@ -177,7 +179,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { &mut self, kind: Option, def_id: Option, - f: impl FnOnce(&mut Self), + f: impl FnOnce(&mut Self) -> ControlFlow, ) { let parent_def_id = self.def_id; let parent_kind = self.const_kind; @@ -196,18 +198,20 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.tcx.hir() } - fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { + fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) -> ControlFlow { let kind = Some(hir::ConstContext::Const); self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); + Continue(()) } - fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { + fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) -> ControlFlow { let owner = self.tcx.hir().body_owner_def_id(body.id()); let kind = self.tcx.hir().body_const_context(owner); self.recurse_into(kind, Some(owner), |this| intravisit::walk_body(this, body)); + Continue(()) } - fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> ControlFlow { match &e.kind { // Skip the following checks if we are not currently in a const context. _ if self.const_kind.is_none() => {} @@ -232,6 +236,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { _ => {} } - intravisit::walk_expr(self, e); + intravisit::walk_expr(self, e) } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index e2f858a34b6f8..8a947a567ddce 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -17,6 +17,7 @@ use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{sym, Symbol}; use std::mem; +use std::ops::ControlFlow::{self, Continue}; use crate::errors::{ ChangeFieldsToBeOfUnitType, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, @@ -300,10 +301,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { self.repr_has_repr_c = def.repr().c(); self.repr_has_repr_simd = def.repr().simd(); - intravisit::walk_item(self, &item) + intravisit::walk_item(self, &item); } hir::ItemKind::ForeignMod { .. } => {} - _ => intravisit::walk_item(self, &item), + _ => { + intravisit::walk_item(self, &item); + } }, Node::TraitItem(trait_item) => { intravisit::walk_trait_item(self, trait_item); @@ -349,15 +352,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { - fn visit_nested_body(&mut self, body: hir::BodyId) { + fn visit_nested_body(&mut self, body: hir::BodyId) -> ControlFlow { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); let body = self.tcx.hir().body(body); self.visit_body(body); self.maybe_typeck_results = old_maybe_typeck_results; + Continue(()) } - fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) { + fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) -> ControlFlow { let tcx = self.tcx; let has_repr_c = self.repr_has_repr_c; let has_repr_simd = self.repr_has_repr_simd; @@ -373,10 +377,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { }); self.live_symbols.extend(live_fields); - intravisit::walk_struct_def(self, def); + intravisit::walk_struct_def(self, def) } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { match expr.kind { hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); @@ -401,10 +405,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { _ => (), } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } - fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { + fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ControlFlow { // Inside the body, ignore constructions of variants // necessary for the pattern to match. Those construction sites // can't be reached unless the variant is constructed elsewhere. @@ -412,9 +416,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.ignore_variant_stack.extend(arm.pat.necessary_variants()); intravisit::walk_arm(self, arm); self.ignore_variant_stack.truncate(len); + Continue(()) } - fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) -> ControlFlow { self.in_pat = true; match pat.kind { PatKind::Struct(ref path, ref fields, _) => { @@ -434,22 +439,23 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { intravisit::walk_pat(self, pat); self.in_pat = false; + Continue(()) } - fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) { + fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) -> ControlFlow { self.handle_res(path.res); - intravisit::walk_path(self, path); + intravisit::walk_path(self, path) } - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow { if let TyKind::OpaqueDef(item_id, _, _) = ty.kind { let item = self.tcx.hir().item(item_id); intravisit::walk_item(self, item); } - intravisit::walk_ty(self, ty); + intravisit::walk_ty(self, ty) } - fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) -> ControlFlow { // When inline const blocks are used in pattern position, paths // referenced by it should be considered as used. let in_pat = mem::replace(&mut self.in_pat, false); @@ -458,6 +464,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { intravisit::walk_anon_const(self, c); self.in_pat = in_pat; + Continue(()) } } diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index de0e50a65de6e..3bb7f95f190c1 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -7,6 +7,8 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{DefIdTree, TyCtxt}; +use std::ops::ControlFlow::{self, Continue}; + pub fn check_crate(tcx: TyCtxt<'_>) { tcx.dep_graph.assert_ignored(); @@ -56,7 +58,11 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { self.errors.lock().push(f()); } - fn check)>(&mut self, owner: hir::OwnerId, walk: F) { + fn check) -> ControlFlow>( + &mut self, + owner: hir::OwnerId, + walk: F, + ) { assert!(self.owner.is_none()); self.owner = Some(owner); walk(self); @@ -124,28 +130,33 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { self.tcx.hir() } - fn visit_nested_item(&mut self, id: hir::ItemId) { + fn visit_nested_item(&mut self, id: hir::ItemId) -> ControlFlow { self.check_nested_id(id.owner_id.def_id); + Continue(()) } - fn visit_nested_trait_item(&mut self, id: hir::TraitItemId) { + fn visit_nested_trait_item(&mut self, id: hir::TraitItemId) -> ControlFlow { self.check_nested_id(id.owner_id.def_id); + Continue(()) } - fn visit_nested_impl_item(&mut self, id: hir::ImplItemId) { + fn visit_nested_impl_item(&mut self, id: hir::ImplItemId) -> ControlFlow { self.check_nested_id(id.owner_id.def_id); + Continue(()) } - fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) { + fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) -> ControlFlow { self.check_nested_id(id.owner_id.def_id); + Continue(()) } - fn visit_item(&mut self, i: &'hir hir::Item<'hir>) { + fn visit_item(&mut self, i: &'hir hir::Item<'hir>) -> ControlFlow { let mut inner_visitor = self.new_visitor(self.tcx); inner_visitor.check(i.owner_id, |this| intravisit::walk_item(this, i)); + Continue(()) } - fn visit_id(&mut self, hir_id: HirId) { + fn visit_id(&mut self, hir_id: HirId) -> ControlFlow { let owner = self.owner.expect("no owner"); if owner != hir_id.owner { @@ -160,20 +171,24 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { } self.hir_ids_seen.insert(hir_id.local_id); + Continue(()) } - fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) { + fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) -> ControlFlow { let mut inner_visitor = self.new_visitor(self.tcx); inner_visitor.check(i.owner_id, |this| intravisit::walk_foreign_item(this, i)); + Continue(()) } - fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) { + fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) -> ControlFlow { let mut inner_visitor = self.new_visitor(self.tcx); inner_visitor.check(i.owner_id, |this| intravisit::walk_trait_item(this, i)); + Continue(()) } - fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) { + fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) -> ControlFlow { let mut inner_visitor = self.new_visitor(self.tcx); inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i)); + Continue(()) } } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 51a19c8e3c02b..b5ed241f690d8 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::util::common::to_readable_str; use rustc_span::def_id::LocalDefId; use rustc_span::Span; +use std::ops::ControlFlow::{self, Continue}; #[derive(Copy, Clone, PartialEq, Eq, Hash)] enum Id { @@ -186,37 +187,37 @@ macro_rules! record_variants { } impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { - fn visit_param(&mut self, param: &'v hir::Param<'v>) { + fn visit_param(&mut self, param: &'v hir::Param<'v>) -> ControlFlow { self.record("Param", Id::Node(param.hir_id), param); hir_visit::walk_param(self, param) } - fn visit_nested_item(&mut self, id: hir::ItemId) { + fn visit_nested_item(&mut self, id: hir::ItemId) -> ControlFlow { let nested_item = self.krate.unwrap().item(id); self.visit_item(nested_item) } - fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) { + fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) -> ControlFlow { let nested_trait_item = self.krate.unwrap().trait_item(trait_item_id); self.visit_trait_item(nested_trait_item) } - fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) { + fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) -> ControlFlow { let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id); self.visit_impl_item(nested_impl_item) } - fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) { + fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) -> ControlFlow { let nested_foreign_item = self.krate.unwrap().foreign_item(id); - self.visit_foreign_item(nested_foreign_item); + self.visit_foreign_item(nested_foreign_item) } - fn visit_nested_body(&mut self, body_id: hir::BodyId) { + fn visit_nested_body(&mut self, body_id: hir::BodyId) -> ControlFlow { let nested_body = self.krate.unwrap().body(body_id); self.visit_body(nested_body) } - fn visit_item(&mut self, i: &'v hir::Item<'v>) { + fn visit_item(&mut self, i: &'v hir::Item<'v>) -> ControlFlow { record_variants!( (self, i, i.kind, Id::Node(i.hir_id()), hir, Item, ItemKind), [ @@ -242,17 +243,17 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_item(self, i) } - fn visit_body(&mut self, b: &'v hir::Body<'v>) { + fn visit_body(&mut self, b: &'v hir::Body<'v>) -> ControlFlow { self.record("Body", Id::None, b); - hir_visit::walk_body(self, b); + hir_visit::walk_body(self, b) } - fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) { + fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) -> ControlFlow { self.record("Mod", Id::None, m); hir_visit::walk_mod(self, m, n) } - fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) { + fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) -> ControlFlow { record_variants!( (self, i, i.kind, Id::Node(i.hir_id()), hir, ForeignItem, ForeignItemKind), [Fn, Static, Type] @@ -260,17 +261,17 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_foreign_item(self, i) } - fn visit_local(&mut self, l: &'v hir::Local<'v>) { + fn visit_local(&mut self, l: &'v hir::Local<'v>) -> ControlFlow { self.record("Local", Id::Node(l.hir_id), l); hir_visit::walk_local(self, l) } - fn visit_block(&mut self, b: &'v hir::Block<'v>) { + fn visit_block(&mut self, b: &'v hir::Block<'v>) -> ControlFlow { self.record("Block", Id::Node(b.hir_id), b); hir_visit::walk_block(self, b) } - fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { + fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> ControlFlow { record_variants!( (self, s, s.kind, Id::Node(s.hir_id), hir, Stmt, StmtKind), [Local, Item, Expr, Semi] @@ -278,12 +279,12 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_stmt(self, s) } - fn visit_arm(&mut self, a: &'v hir::Arm<'v>) { + fn visit_arm(&mut self, a: &'v hir::Arm<'v>) -> ControlFlow { self.record("Arm", Id::Node(a.hir_id), a); hir_visit::walk_arm(self, a) } - fn visit_pat(&mut self, p: &'v hir::Pat<'v>) { + fn visit_pat(&mut self, p: &'v hir::Pat<'v>) -> ControlFlow { record_variants!( (self, p, p.kind, Id::Node(p.hir_id), hir, Pat, PatKind), [Wild, Binding, Struct, TupleStruct, Or, Path, Tuple, Box, Ref, Lit, Range, Slice] @@ -291,12 +292,12 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_pat(self, p) } - fn visit_pat_field(&mut self, f: &'v hir::PatField<'v>) { + fn visit_pat_field(&mut self, f: &'v hir::PatField<'v>) -> ControlFlow { self.record("PatField", Id::Node(f.hir_id), f); hir_visit::walk_pat_field(self, f) } - fn visit_expr(&mut self, e: &'v hir::Expr<'v>) { + fn visit_expr(&mut self, e: &'v hir::Expr<'v>) -> ControlFlow { record_variants!( (self, e, e.kind, Id::Node(e.hir_id), hir, Expr, ExprKind), [ @@ -308,17 +309,17 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_expr(self, e) } - fn visit_let_expr(&mut self, lex: &'v hir::Let<'v>) { + fn visit_let_expr(&mut self, lex: &'v hir::Let<'v>) -> ControlFlow { self.record("Let", Id::Node(lex.hir_id), lex); hir_visit::walk_let_expr(self, lex) } - fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) { + fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) -> ControlFlow { self.record("ExprField", Id::Node(f.hir_id), f); hir_visit::walk_expr_field(self, f) } - fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { + fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> ControlFlow { record_variants!( (self, t, t.kind, Id::Node(t.hir_id), hir, Ty, TyKind), [ @@ -340,17 +341,17 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_ty(self, t) } - fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { + fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> ControlFlow { self.record("GenericParam", Id::Node(p.hir_id), p); hir_visit::walk_generic_param(self, p) } - fn visit_generics(&mut self, g: &'v hir::Generics<'v>) { + fn visit_generics(&mut self, g: &'v hir::Generics<'v>) -> ControlFlow { self.record("Generics", Id::None, g); hir_visit::walk_generics(self, g) } - fn visit_where_predicate(&mut self, p: &'v hir::WherePredicate<'v>) { + fn visit_where_predicate(&mut self, p: &'v hir::WherePredicate<'v>) -> ControlFlow { record_variants!( (self, p, p, Id::None, hir, WherePredicate, WherePredicate), [BoundPredicate, RegionPredicate, EqPredicate] @@ -365,18 +366,18 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { b: hir::BodyId, _: Span, id: LocalDefId, - ) { + ) -> ControlFlow { self.record("FnDecl", Id::None, fd); hir_visit::walk_fn(self, fk, fd, b, id) } - fn visit_use(&mut self, p: &'v hir::UsePath<'v>, hir_id: hir::HirId) { + fn visit_use(&mut self, p: &'v hir::UsePath<'v>, hir_id: hir::HirId) -> ControlFlow { // This is `visit_use`, but the type is `Path` so record it that way. self.record("Path", Id::None, p); hir_visit::walk_use(self, p, hir_id) } - fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) { + fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) -> ControlFlow { record_variants!( (self, ti, ti.kind, Id::Node(ti.hir_id()), hir, TraitItem, TraitItemKind), [Const, Fn, Type] @@ -384,12 +385,12 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_trait_item(self, ti) } - fn visit_trait_item_ref(&mut self, ti: &'v hir::TraitItemRef) { + fn visit_trait_item_ref(&mut self, ti: &'v hir::TraitItemRef) -> ControlFlow { self.record("TraitItemRef", Id::Node(ti.id.hir_id()), ti); hir_visit::walk_trait_item_ref(self, ti) } - fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { + fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) -> ControlFlow { record_variants!( (self, ii, ii.kind, Id::Node(ii.hir_id()), hir, ImplItem, ImplItemKind), [Const, Fn, Type] @@ -397,17 +398,17 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_impl_item(self, ii) } - fn visit_foreign_item_ref(&mut self, fi: &'v hir::ForeignItemRef) { + fn visit_foreign_item_ref(&mut self, fi: &'v hir::ForeignItemRef) -> ControlFlow { self.record("ForeignItemRef", Id::Node(fi.id.hir_id()), fi); hir_visit::walk_foreign_item_ref(self, fi) } - fn visit_impl_item_ref(&mut self, ii: &'v hir::ImplItemRef) { + fn visit_impl_item_ref(&mut self, ii: &'v hir::ImplItemRef) -> ControlFlow { self.record("ImplItemRef", Id::Node(ii.id.hir_id()), ii); hir_visit::walk_impl_item_ref(self, ii) } - fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) { + fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) -> ControlFlow { record_variants!( (self, b, b, Id::None, hir, GenericBound, GenericBound), [Trait, LangItemTrait, Outlives] @@ -415,17 +416,17 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_param_bound(self, b) } - fn visit_field_def(&mut self, s: &'v hir::FieldDef<'v>) { + fn visit_field_def(&mut self, s: &'v hir::FieldDef<'v>) -> ControlFlow { self.record("FieldDef", Id::Node(s.hir_id), s); hir_visit::walk_field_def(self, s) } - fn visit_variant(&mut self, v: &'v hir::Variant<'v>) { + fn visit_variant(&mut self, v: &'v hir::Variant<'v>) -> ControlFlow { self.record("Variant", Id::None, v); hir_visit::walk_variant(self, v) } - fn visit_generic_arg(&mut self, ga: &'v hir::GenericArg<'v>) { + fn visit_generic_arg(&mut self, ga: &'v hir::GenericArg<'v>) -> ControlFlow { record_variants!( (self, ga, ga, Id::Node(ga.hir_id()), hir, GenericArg, GenericArg), [Lifetime, Type, Const, Infer] @@ -438,38 +439,42 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } } - fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) -> ControlFlow { self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime); hir_visit::walk_lifetime(self, lifetime) } - fn visit_path(&mut self, path: &hir::Path<'v>, _id: hir::HirId) { + fn visit_path(&mut self, path: &hir::Path<'v>, _id: hir::HirId) -> ControlFlow { self.record("Path", Id::None, path); hir_visit::walk_path(self, path) } - fn visit_path_segment(&mut self, path_segment: &'v hir::PathSegment<'v>) { + fn visit_path_segment(&mut self, path_segment: &'v hir::PathSegment<'v>) -> ControlFlow { self.record("PathSegment", Id::None, path_segment); hir_visit::walk_path_segment(self, path_segment) } - fn visit_generic_args(&mut self, ga: &'v hir::GenericArgs<'v>) { + fn visit_generic_args(&mut self, ga: &'v hir::GenericArgs<'v>) -> ControlFlow { self.record("GenericArgs", Id::None, ga); hir_visit::walk_generic_args(self, ga) } - fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding<'v>) { + fn visit_assoc_type_binding( + &mut self, + type_binding: &'v hir::TypeBinding<'v>, + ) -> ControlFlow { self.record("TypeBinding", Id::Node(type_binding.hir_id), type_binding); hir_visit::walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, attr: &'v ast::Attribute) { + fn visit_attribute(&mut self, attr: &'v ast::Attribute) -> ControlFlow { self.record("Attribute", Id::Attr(attr.id), attr); + Continue(()) } - fn visit_inline_asm(&mut self, asm: &'v hir::InlineAsm<'v>, id: HirId) { + fn visit_inline_asm(&mut self, asm: &'v hir::InlineAsm<'v>, id: HirId) -> ControlFlow { self.record("InlineAsm", Id::None, asm); - hir_visit::walk_inline_asm(self, asm, id); + hir_visit::walk_inline_asm(self, asm, id) } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 0cb8424082c3e..6218f4cd28094 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -10,6 +10,7 @@ #![feature(let_chains)] #![feature(map_try_insert)] #![feature(min_specialization)] +#![feature(never_type)] #![feature(try_blocks)] #![recursion_limit = "256"] diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index f4da1aaec1130..00f38811ac334 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; +use std::ops::ControlFlow::{self, Continue}; use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice}; @@ -128,10 +129,11 @@ impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { self.tcx.hir() } - fn visit_attribute(&mut self, attr: &'tcx Attribute) { + fn visit_attribute(&mut self, attr: &'tcx Attribute) -> ControlFlow { if let Some((feature, stable, span)) = self.extract(attr) { self.collect_feature(feature, stable, span); } + Continue(()) } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index df5c8f53ec1c5..b608d28119a2f 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -103,6 +103,7 @@ use rustc_span::{BytePos, Span}; use std::collections::VecDeque; use std::io; use std::io::prelude::*; +use std::ops::ControlFlow; use std::rc::Rc; mod rwu_table; @@ -233,11 +234,11 @@ struct CollectLitsVisitor<'tcx> { } impl<'tcx> Visitor<'tcx> for CollectLitsVisitor<'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Lit(_) = expr.kind { self.lit_exprs.push(expr); } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } } @@ -369,23 +370,23 @@ impl<'tcx> IrMaps<'tcx> { } impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) -> ControlFlow { self.add_from_pat(&local.pat); if local.els.is_some() { self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id)); } - intravisit::walk_local(self, local); + intravisit::walk_local(self, local) } - fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { + fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ControlFlow { self.add_from_pat(&arm.pat); if let Some(hir::Guard::IfLet(ref let_expr)) = arm.guard { self.add_from_pat(let_expr.pat); } - intravisit::walk_arm(self, arm); + intravisit::walk_arm(self, arm) } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> ControlFlow { let shorthand_field_ids = self.collect_shorthand_field_ids(param.pat); param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = match param.pat.kind { @@ -398,10 +399,10 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { }; self.add_variable(var); }); - intravisit::walk_param(self, param); + intravisit::walk_param(self, param) } - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { match expr.kind { // live nodes required for uses or definitions of variables: hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { @@ -409,7 +410,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { if let Res::Local(_var_hir_id) = path.res { self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); } - intravisit::walk_expr(self, expr); } hir::ExprKind::Closure(closure) => { // Interesting control flow (for loops can contain labeled @@ -429,12 +429,10 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { })); } self.set_captures(expr.hir_id, call_caps); - intravisit::walk_expr(self, expr); } hir::ExprKind::Let(let_expr) => { self.add_from_pat(let_expr.pat); - intravisit::walk_expr(self, expr); } // live nodes required for interesting control flow: @@ -443,11 +441,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Loop(..) | hir::ExprKind::Yield(..) => { self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); - intravisit::walk_expr(self, expr); } hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => { self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); - intravisit::walk_expr(self, expr); } // otherwise, live nodes are not required: @@ -477,10 +473,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Type(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) - | hir::ExprKind::Path(hir::QPath::LangItem(..)) => { - intravisit::walk_expr(self, expr); - } + | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {} } + intravisit::walk_expr(self, expr) } } @@ -1341,24 +1336,24 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Checking for error conditions impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> { - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) -> ControlFlow { self.check_unused_vars_in_pat(&local.pat, None, None, |spans, hir_id, ln, var| { if local.init.is_some() { self.warn_about_dead_assign(spans, hir_id, ln, var); } }); - intravisit::walk_local(self, local); + intravisit::walk_local(self, local) } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow { check_expr(self, ex); - intravisit::walk_expr(self, ex); + intravisit::walk_expr(self, ex) } - fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { + fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ControlFlow { self.check_unused_vars_in_pat(&arm.pat, None, None, |_, _, _, _| {}); - intravisit::walk_arm(self, arm); + intravisit::walk_arm(self, arm) } } diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index b4cf19e4a34f6..02bb6c81f1ff1 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -12,6 +12,8 @@ use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; use rustc_span::Span; +use std::ops::ControlFlow::{self, Continue}; + use crate::errors::{ BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, @@ -52,11 +54,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.hir_map } - fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) -> ControlFlow { self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c)); + Continue(()) } - fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) -> ControlFlow { match e.kind { hir::ExprKind::Loop(ref b, _, source, _) => { self.with_context(Loop(source), |v| v.visit_block(&b)); @@ -73,7 +76,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } else { Closure(fn_decl_span) }; - self.visit_fn_decl(&fn_decl); + self.visit_fn_decl(&fn_decl)?; self.with_context(cx, |v| v.visit_nested_body(body)); } hir::ExprKind::Block(ref b, Some(_label)) => { @@ -81,13 +84,13 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } hir::ExprKind::Break(break_label, ref opt_expr) => { if let Some(e) = opt_expr { - self.visit_expr(e); + self.visit_expr(e)?; } if self.require_label_in_labeled_block(e.span, &break_label, "break") { // If we emitted an error about an unlabeled break in a labeled // block, we don't need any further checking for this break any more - return; + return Continue(()); } let loop_id = match break_label.target_id { @@ -104,7 +107,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { }; if let Some(Node::Block(_)) = loop_id.and_then(|id| self.hir_map.find(id)) { - return; + return Continue(()); } if let Some(break_expr) = opt_expr { @@ -167,15 +170,16 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } self.require_break_cx("continue", e.span) } - _ => intravisit::walk_expr(self, e), + _ => intravisit::walk_expr(self, e)?, } + Continue(()) } } impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { fn with_context(&mut self, cx: Context, f: F) where - F: FnOnce(&mut CheckLoopVisitor<'a, 'hir>), + F: FnOnce(&mut CheckLoopVisitor<'a, 'hir>) -> ControlFlow, { let old_cx = self.cx; self.cx = cx; diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index c5b5cf7f5a963..dcc1621796591 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -13,6 +13,8 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; +use std::ops::ControlFlow::{self, Continue}; + use crate::errors::{ CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, @@ -109,7 +111,7 @@ struct CheckParameters<'tcx> { } impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Path(hir::QPath::Resolved( _, hir::Path { res: hir::def::Res::Local(var_hir_id), .. }, @@ -117,10 +119,10 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { { if self.params.contains(var_hir_id) { self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span }); - return; + return Continue(()); } } - hir::intravisit::walk_expr(self, expr); + hir::intravisit::walk_expr(self, expr) } } @@ -275,7 +277,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { } impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> { - fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) -> ControlFlow { match stmt.kind { StmtKind::Item(..) => {} StmtKind::Local(..) => { @@ -285,9 +287,11 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> { self.check_expr(expr, stmt.span); } } + Continue(()) } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { self.check_expr(&expr, expr.span); + Continue(()) } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 051100c56f813..cd0f3b50a117c 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -17,6 +17,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::config::CrateType; use rustc_target::spec::abi::Abi; +use std::ops::ControlFlow::{self, Continue}; // Returns true if the given item must be inlined because it may be // monomorphized or it was marked with `#[inline]`. This will only return @@ -73,15 +74,16 @@ struct ReachableContext<'tcx> { } impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { - fn visit_nested_body(&mut self, body: hir::BodyId) { + fn visit_nested_body(&mut self, body: hir::BodyId) -> ControlFlow { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); let body = self.tcx.hir().body(body); - self.visit_body(body); + self.visit_body(body)?; self.maybe_typeck_results = old_maybe_typeck_results; + Continue(()) } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { let res = match expr.kind { hir::ExprKind::Path(ref qpath) => { Some(self.typeck_results().qpath_res(qpath, expr.hir_id)) @@ -117,7 +119,11 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { intravisit::walk_expr(self, expr) } - fn visit_inline_asm(&mut self, asm: &'tcx hir::InlineAsm<'tcx>, id: hir::HirId) { + fn visit_inline_asm( + &mut self, + asm: &'tcx hir::InlineAsm<'tcx>, + id: hir::HirId, + ) -> ControlFlow { for (op, _) in asm.operands { if let hir::InlineAsmOperand::SymStatic { def_id, .. } = op { if let Some(def_id) = def_id.as_local() { @@ -125,7 +131,7 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { } } } - intravisit::walk_inline_asm(self, asm, id); + intravisit::walk_inline_asm(self, asm, id) } } @@ -279,7 +285,7 @@ impl<'tcx> ReachableContext<'tcx> { hir::ImplItemKind::Fn(_, body) => { let impl_def_id = self.tcx.local_parent(search_item); if method_might_be_inlined(self.tcx, impl_item, impl_def_id) { - self.visit_nested_body(body) + self.visit_nested_body(body); } } hir::ImplItemKind::Type(_) => {} diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 16194a6f196ea..f2df179849255 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -28,6 +28,7 @@ use std::cmp::Ordering; use std::iter; use std::mem::replace; use std::num::NonZeroU32; +use std::ops::ControlFlow::{self, Break, Continue}; #[derive(PartialEq)] enum AnnotationKind { @@ -109,8 +110,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { inherit_const_stability: InheritConstStability, inherit_from_parent: InheritStability, visit_children: F, - ) where - F: FnOnce(&mut Self), + ) -> ControlFlow + where + F: FnOnce(&mut Self) -> ControlFlow, { let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); @@ -150,13 +152,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - self.recurse_with_stability_attrs( + return self.recurse_with_stability_attrs( depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), None, None, visit_children, ); - return; } let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp); @@ -283,7 +284,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { stab, inherit_const_stability.yes().then_some(const_stab).flatten(), visit_children, - ); + ) } fn recurse_with_stability_attrs( @@ -291,8 +292,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr: Option, stab: Option, const_stab: Option, - f: impl FnOnce(&mut Self), - ) { + f: impl FnOnce(&mut Self) -> ControlFlow, + ) -> ControlFlow { // These will be `Some` if this item changes the corresponding stability attribute. let mut replaced_parent_depr = None; let mut replaced_parent_stab = None; @@ -309,7 +310,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { Some(replace(&mut self.parent_const_stab, Some(const_stab))); } - f(self); + f(self)?; if let Some(orig_parent_depr) = replaced_parent_depr { self.parent_depr = orig_parent_depr; @@ -320,6 +321,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(orig_parent_const_stab) = replaced_parent_const_stab { self.parent_const_stab = orig_parent_const_stab; } + + Continue(()) } } @@ -333,7 +336,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { self.tcx.hir() } - fn visit_item(&mut self, i: &'tcx Item<'tcx>) { + fn visit_item(&mut self, i: &'tcx Item<'tcx>) -> ControlFlow { let orig_in_trait_impl = self.in_trait_impl; let mut kind = AnnotationKind::Required; let mut const_stab_inherit = InheritConstStability::No; @@ -364,8 +367,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, - |_| {}, - ) + |_| Continue(()), + )?; } } hir::ItemKind::Fn(ref item_fn_sig, _, _) => { @@ -383,11 +386,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { const_stab_inherit, InheritStability::No, |v| intravisit::walk_item(v, i), - ); + )?; self.in_trait_impl = orig_in_trait_impl; + Continue(()) } - fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { let fn_sig = match ti.kind { hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig), _ => None, @@ -401,13 +405,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, - |v| { - intravisit::walk_trait_item(v, ti); - }, - ); + |v| intravisit::walk_trait_item(v, ti), + ) } - fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { let kind = if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required }; @@ -424,13 +426,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, - |v| { - intravisit::walk_impl_item(v, ii); - }, - ); + |v| intravisit::walk_impl_item(v, ii), + ) } - fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { + fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) -> ControlFlow { self.annotate( var.def_id, var.span, @@ -449,8 +449,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, - |_| {}, - ); + |_| Continue(()), + )?; } intravisit::walk_variant(v, var) @@ -458,7 +458,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ) } - fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { + fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) -> ControlFlow { self.annotate( s.def_id, s.span, @@ -467,13 +467,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { InheritDeprecation::Yes, InheritConstStability::No, InheritStability::Yes, - |v| { - intravisit::walk_field_def(v, s); - }, - ); + |v| intravisit::walk_field_def(v, s), + ) } - fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { self.annotate( i.owner_id.def_id, i.span, @@ -482,13 +480,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { InheritDeprecation::Yes, InheritConstStability::No, InheritStability::No, - |v| { - intravisit::walk_foreign_item(v, i); - }, - ); + |v| intravisit::walk_foreign_item(v, i), + ) } - fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) -> ControlFlow { let kind = match &p.kind { // Allow stability attributes on default generic arguments. hir::GenericParamKind::Type { default: Some(_), .. } @@ -504,10 +500,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { InheritDeprecation::No, InheritConstStability::No, InheritStability::No, - |v| { - intravisit::walk_generic_param(v, p); - }, - ); + |v| intravisit::walk_generic_param(v, p), + ) } } @@ -564,7 +558,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { self.tcx.hir() } - fn visit_item(&mut self, i: &'tcx Item<'tcx>) { + fn visit_item(&mut self, i: &'tcx Item<'tcx>) -> ControlFlow { // Inherent impls and foreign modules serve only as containers for other items, // they don't have their own stability. They still can be annotated as unstable // and propagate this instability to children, but this annotation is completely @@ -583,36 +577,36 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { intravisit::walk_item(self, i) } - fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { self.check_missing_stability(ti.owner_id.def_id, ti.span); - intravisit::walk_trait_item(self, ti); + intravisit::walk_trait_item(self, ti) } - fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { self.check_missing_stability(ii.owner_id.def_id, ii.span); self.check_missing_const_stability(ii.owner_id.def_id, ii.span); } - intravisit::walk_impl_item(self, ii); + intravisit::walk_impl_item(self, ii) } - fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { + fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) -> ControlFlow { self.check_missing_stability(var.def_id, var.span); if let Some(ctor_def_id) = var.data.ctor_def_id() { self.check_missing_stability(ctor_def_id, var.span); } - intravisit::walk_variant(self, var); + intravisit::walk_variant(self, var) } - fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { + fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) -> ControlFlow { self.check_missing_stability(s.def_id, s.span); - intravisit::walk_field_def(self, s); + intravisit::walk_field_def(self, s) } - fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { self.check_missing_stability(i.owner_id.def_id, i.span); - intravisit::walk_foreign_item(self, i); + intravisit::walk_foreign_item(self, i) } // Note that we don't need to `check_missing_stability` for default generic parameters, // as we assume that any default generic parameters without attributes are automatically @@ -657,7 +651,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { annotator.parent_stab = Some(stability); } - annotator.annotate( + let _ = annotator.annotate( CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), None, @@ -708,17 +702,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { self.tcx.hir() } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { match item.kind { hir::ItemKind::ExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. // `std` is still checked for the `restricted-std` feature. if item.span.is_dummy() && item.ident.name != sym::std { - return; + return Continue(()); } let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else { - return; + return Continue(()); }; let def_id = cnum.as_def_id(); self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None); @@ -745,13 +739,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // it will have no effect. // See: https://github.com/rust-lang/rust/issues/55436 if let Some((Stability { level: attr::Unstable { .. }, .. }, span)) = stab { - let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true }; - c.visit_ty(self_ty); - c.visit_trait_ref(t); + let mut c = CheckTraitImplUnstable { tcx: self.tcx }; + let is_unstable = + c.visit_ty(self_ty).is_break() || c.visit_trait_ref(t).is_break(); // do not lint when the trait isn't resolved, since resolution error should // be fixed first - if t.path.res != Res::Err && c.fully_stable { + if t.path.res != Res::Err && !is_unstable { self.tcx.struct_span_lint_hir( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), @@ -784,10 +778,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { _ => (/* pass */), } - intravisit::walk_item(self, item); + intravisit::walk_item(self, item) } - fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) { + fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) -> ControlFlow { if let Some(def_id) = path.res.opt_def_id() { let method_span = path.segments.last().map(|s| s.ident.span); let item_is_allowed = self.tcx.check_stability_allow_unstable( @@ -875,52 +869,57 @@ fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { true } -struct CheckTraitImplStable<'tcx> { +struct CheckTraitImplUnstable<'tcx> { tcx: TyCtxt<'tcx>, - fully_stable: bool, } -impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> { - fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) { - if let Some(def_id) = path.res.opt_def_id() { - if let Some(stab) = self.tcx.lookup_stability(def_id) { - self.fully_stable &= stab.level.is_stable(); - } +impl<'tcx> Visitor<'tcx> for CheckTraitImplUnstable<'tcx> { + type BreakTy = (); + + fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) -> ControlFlow<()> { + if let Some(def_id) = path.res.opt_def_id() + && let Some(stab) = self.tcx.lookup_stability(def_id) + && !stab.level.is_stable() + { + return Break(()); } intravisit::walk_path(self, path) } - fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) { - if let Res::Def(DefKind::Trait, trait_did) = t.path.res { - if let Some(stab) = self.tcx.lookup_stability(trait_did) { - self.fully_stable &= stab.level.is_stable(); - } + fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) -> ControlFlow<()> { + if let Res::Def(DefKind::Trait, trait_did) = t.path.res + && let Some(stab) = self.tcx.lookup_stability(trait_did) + && !stab.level.is_stable() + { + return Break(()) } intravisit::walk_trait_ref(self, t) } - fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { + fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) -> ControlFlow<()> { if let TyKind::Never = t.kind { - self.fully_stable = false; + return Break(()); } - if let TyKind::BareFn(f) = t.kind { - if rustc_target::spec::abi::is_stable(f.abi.name()).is_err() { - self.fully_stable = false; - } + if let TyKind::BareFn(f) = t.kind + && rustc_target::spec::abi::is_stable(f.abi.name()).is_err() + { + return Break(()); } + intravisit::walk_ty(self, t) } - fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) { + fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) -> ControlFlow<()> { for ty in fd.inputs { - self.visit_ty(ty) + self.visit_ty(ty)?; } if let hir::FnRetTy::Return(output_ty) = fd.output { match output_ty.kind { TyKind::Never => {} // `-> !` is stable - _ => self.visit_ty(output_ty), + _ => self.visit_ty(output_ty)?, } } + Continue(()) } } diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs index 605cf0a93b877..061d3862f7f82 100644 --- a/compiler/rustc_passes/src/upvars.rs +++ b/compiler/rustc_passes/src/upvars.rs @@ -8,6 +8,7 @@ use rustc_hir::{self, HirId}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::Span; +use std::ops::ControlFlow; pub fn provide(providers: &mut Providers) { providers.upvars_mentioned = |tcx, def_id| { @@ -43,11 +44,11 @@ struct LocalCollector { } impl<'tcx> Visitor<'tcx> for LocalCollector { - fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) -> ControlFlow { if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind { self.locals.insert(hir_id); } - intravisit::walk_pat(self, pat); + intravisit::walk_pat(self, pat) } } @@ -66,15 +67,15 @@ impl CaptureCollector<'_, '_> { } impl<'tcx> Visitor<'tcx> for CaptureCollector<'_, 'tcx> { - fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) { + fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) -> ControlFlow { if let Res::Local(var_id) = path.res { self.visit_local_use(var_id, path.span); } - intravisit::walk_path(self, path); + intravisit::walk_path(self, path) } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Closure(closure) = expr.kind { if let Some(upvars) = self.tcx.upvars_mentioned(closure.def_id) { // Every capture of a closure expression is a local in scope, @@ -91,6 +92,6 @@ impl<'tcx> Visitor<'tcx> for CaptureCollector<'_, 'tcx> { } } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 50176c8023288..2305914ab6194 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,5 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(associated_type_defaults)] +#![feature(never_type)] #![feature(rustc_private)] #![feature(try_blocks)] #![feature(let_chains)] @@ -37,7 +38,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use std::marker::PhantomData; -use std::ops::ControlFlow; +use std::ops::ControlFlow::{self, Break, Continue}; use std::{cmp, fmt, mem}; use errors::{ @@ -629,7 +630,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { self.tcx.hir() } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { let item_level = match item.kind { hir::ItemKind::Impl { .. } => { let impl_level = Option::::of_impl( @@ -838,15 +839,17 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { let orig_level = mem::replace(&mut self.prev_level, item_level); intravisit::walk_item(self, item); self.prev_level = orig_level; + Continue(()) } - fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { + fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> ControlFlow { // Blocks can have public items, for example impls, but they always // start as completely private regardless of publicity of a function, // constant, type, field, etc., in which this block resides. let orig_level = mem::replace(&mut self.prev_level, None); intravisit::walk_block(self, b); self.prev_level = orig_level; + Continue(()) } } @@ -951,7 +954,7 @@ impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { } impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { self.effective_visibility_diagnostic(item.owner_id.def_id); match item.kind { @@ -976,16 +979,20 @@ impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { } _ => {} } + Continue(()) } - fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) { + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) -> ControlFlow { self.effective_visibility_diagnostic(item.owner_id.def_id); + Continue(()) } - fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) { + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) -> ControlFlow { self.effective_visibility_diagnostic(item.owner_id.def_id); + Continue(()) } - fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { self.effective_visibility_diagnostic(item.owner_id.def_id); + Continue(()) } } @@ -1054,26 +1061,29 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { self.tcx.hir() } - fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { + fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) -> ControlFlow { // Don't visit nested modules, since we run a separate visitor walk // for each module in `effective_visibilities` + Continue(()) } - fn visit_nested_body(&mut self, body: hir::BodyId) { + fn visit_nested_body(&mut self, body: hir::BodyId) -> ControlFlow { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); let body = self.tcx.hir().body(body); self.visit_body(body); self.maybe_typeck_results = old_maybe_typeck_results; + Continue(()) } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); intravisit::walk_item(self, item); self.current_item = orig_current_item; + Continue(()) } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap(); @@ -1101,10 +1111,10 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { } } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } - fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) -> ControlFlow { if let PatKind::Struct(ref qpath, fields, _) = pat.kind { let res = self.typeck_results().qpath_res(qpath, pat.hir_id); let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap(); @@ -1116,7 +1126,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { } } - intravisit::walk_pat(self, pat); + intravisit::walk_pat(self, pat) } } @@ -1179,52 +1189,54 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { self.tcx.hir() } - fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { + fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) -> ControlFlow { // Don't visit nested modules, since we run a separate visitor walk // for each module in `effective_visibilities` + Continue(()) } - fn visit_nested_body(&mut self, body: hir::BodyId) { + fn visit_nested_body(&mut self, body: hir::BodyId) -> ControlFlow { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); let body = self.tcx.hir().body(body); self.visit_body(body); self.maybe_typeck_results = old_maybe_typeck_results; + Continue(()) } - fn visit_generic_arg(&mut self, generic_arg: &'tcx hir::GenericArg<'tcx>) { + fn visit_generic_arg(&mut self, generic_arg: &'tcx hir::GenericArg<'tcx>) -> ControlFlow { match generic_arg { hir::GenericArg::Type(t) => self.visit_ty(t), hir::GenericArg::Infer(inf) => self.visit_infer(inf), - hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {} + hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => Continue(()), } } - fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) -> ControlFlow { self.span = hir_ty.span; if let Some(typeck_results) = self.maybe_typeck_results { // Types in bodies. if self.visit(typeck_results.node_type(hir_ty.hir_id)).is_break() { - return; + return Continue(()); } } else { // Types in signatures. // FIXME: This is very ineffective. Ideally each HIR type should be converted // into a semantic type only once and the result should be cached somehow. if self.visit(rustc_hir_analysis::hir_ty_to_ty(self.tcx, hir_ty)).is_break() { - return; + return Continue(()); } } - intravisit::walk_ty(self, hir_ty); + intravisit::walk_ty(self, hir_ty) } - fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) -> ControlFlow { self.span = inf.span; if let Some(typeck_results) = self.maybe_typeck_results { if let Some(ty) = typeck_results.node_type_opt(inf.hir_id) { if self.visit(ty).is_break() { - return; + return Continue(()); } } else { // We don't do anything for const infers here. @@ -1232,10 +1244,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } else { bug!("visit_infer without typeck_results"); } - intravisit::walk_inf(self, inf); + intravisit::walk_inf(self, inf) } - fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) { + fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) -> ControlFlow { self.span = trait_ref.path.span; if self.maybe_typeck_results.is_none() { // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE. @@ -1252,7 +1264,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { match pred.kind().skip_binder() { ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { if self.visit_trait(trait_predicate.trait_ref).is_break() { - return; + return Continue(()); } } ty::PredicateKind::Clause(ty::Clause::Projection(proj_predicate)) => { @@ -1260,7 +1272,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { if term.is_break() || self.visit_projection_ty(proj_predicate.projection_ty).is_break() { - return; + return Continue(()); } } _ => {} @@ -1268,20 +1280,20 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } } - intravisit::walk_trait_ref(self, trait_ref); + intravisit::walk_trait_ref(self, trait_ref) } // Check types of expressions - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { if self.check_expr_pat_type(expr.hir_id, expr.span) { // Do not check nested expressions if the error already happened. - return; + return Continue(()); } match expr.kind { hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => { // Do not report duplicate errors for `x = y` and `match x { ... }`. if self.check_expr_pat_type(rhs.hir_id, rhs.span) { - return; + return Continue(()); } } hir::ExprKind::MethodCall(segment, ..) => { @@ -1289,7 +1301,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { self.span = segment.ident.span; if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) { if self.visit(self.tcx.type_of(def_id).subst_identity()).is_break() { - return; + return Continue(()); } } else { self.tcx @@ -1300,7 +1312,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { _ => {} } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } // Prohibit access to associated items with insufficient nominal visibility. @@ -1309,7 +1321,12 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { // we prohibit access to private statics from other crates, this allows to give // more code internal visibility at link time. (Access to private functions // is already prohibited by type privacy for function types.) - fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) { + fn visit_qpath( + &mut self, + qpath: &'tcx hir::QPath<'tcx>, + id: hir::HirId, + span: Span, + ) -> ControlFlow { let def = match qpath { hir::QPath::Resolved(_, path) => match path.res { Res::Def(kind, def_id) => Some((kind, def_id)), @@ -1344,41 +1361,42 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } None => sess.emit_err(UnnamedItemIsPrivate { span, kind }), }; - return; + return Continue(()); } } - intravisit::walk_qpath(self, qpath, id); + intravisit::walk_qpath(self, qpath, id) } // Check types of patterns. - fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) -> ControlFlow { if self.check_expr_pat_type(pattern.hir_id, pattern.span) { // Do not check nested patterns if the error already happened. - return; + return Continue(()); } - intravisit::walk_pat(self, pattern); + intravisit::walk_pat(self, pattern) } - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) -> ControlFlow { if let Some(init) = local.init { if self.check_expr_pat_type(init.hir_id, init.span) { // Do not report duplicate errors for `let x = y`. - return; + return Continue(()); } } - intravisit::walk_local(self, local); + intravisit::walk_local(self, local) } // Check types in item interfaces. - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); let old_maybe_typeck_results = self.maybe_typeck_results.take(); intravisit::walk_item(self, item); self.maybe_typeck_results = old_maybe_typeck_results; self.current_item = orig_current_item; + Continue(()) } } @@ -1417,8 +1435,6 @@ struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>, - /// Whether the type refers to private types. - contains_private: bool, /// Whether we've recurred at all (i.e., if we're pointing at the /// first type on which `visit_ty` was called). at_outer_type: bool, @@ -1469,20 +1485,20 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { - fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) { + type BreakTy = (); + fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) -> ControlFlow<()> { match generic_arg { hir::GenericArg::Type(t) => self.visit_ty(t), hir::GenericArg::Infer(inf) => self.visit_ty(&inf.to_ty()), - hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {} + hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => Continue(()), } } - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + fn visit_ty(&mut self, ty: &hir::Ty<'_>) -> ControlFlow<()> { if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind { if self.inner.path_is_private_type(path) { - self.contains_private = true; // Found what we're looking for, so let's stop working. - return; + return Break(()); } } if let hir::TyKind::Path(_) = ty.kind { @@ -1495,7 +1511,9 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a } // Don't want to recurse into `[, .. expr]`. - fn visit_expr(&mut self, _: &hir::Expr<'_>) {} + fn visit_expr(&mut self, _: &hir::Expr<'_>) -> ControlFlow<()> { + Continue(()) + } } impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { @@ -1507,7 +1525,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { self.tcx.hir() } - fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) -> ControlFlow { match item.kind { // Contents of a private mod can be re-exported, so we need // to check internals. @@ -1519,7 +1537,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { hir::ItemKind::Trait(.., bounds, _) => { if !self.trait_is_public(item.owner_id.def_id) { - return; + return Continue(()); } for bound in bounds.iter() { @@ -1543,12 +1561,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { { let mut visitor = ObsoleteCheckTypeForPrivatenessVisitor { inner: self, - contains_private: false, at_outer_type: true, outer_type_is_public_path: false, }; - visitor.visit_ty(impl_.self_ty); - self_contains_private = visitor.contains_private; + self_contains_private = visitor.visit_ty(impl_.self_ty).is_break(); self_is_public_path = visitor.outer_type_is_public_path; } @@ -1601,10 +1617,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) if self.item_is_public(impl_item.owner_id.def_id) => { - intravisit::walk_impl_item(self, impl_item) + intravisit::walk_impl_item(self, impl_item); } hir::ImplItemKind::Type(..) => { - intravisit::walk_impl_item(self, impl_item) + intravisit::walk_impl_item(self, impl_item); } _ => {} } @@ -1660,19 +1676,19 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } } if found_pub_static { - intravisit::walk_generics(self, &impl_.generics) + intravisit::walk_generics(self, &impl_.generics); } } - return; + return Continue(()); } // `type ... = ...;` can contain private types, because // we're introducing a new name. - hir::ItemKind::TyAlias(..) => return, + hir::ItemKind::TyAlias(..) => return Continue(()), // Not at all public, so we don't care. _ if !self.item_is_public(item.owner_id.def_id) => { - return; + return Continue(()); } _ => {} @@ -1682,10 +1698,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // any `visit_ty`'s will be called on things that are in // public signatures, i.e., things that we're interested in for // this visitor. - intravisit::walk_item(self, item); + intravisit::walk_item(self, item) } - fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { + fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) -> ControlFlow { for predicate in generics.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { @@ -1699,15 +1715,17 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } } } + Continue(()) } - fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) -> ControlFlow { if self.effective_visibilities.is_reachable(item.owner_id.def_id) { - intravisit::walk_foreign_item(self, item) + intravisit::walk_foreign_item(self, item); } + Continue(()) } - fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> ControlFlow { if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = t.kind { if self.path_is_private_type(path) { self.old_error_set.insert(t.hir_id); @@ -1716,27 +1734,33 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { intravisit::walk_ty(self, t) } - fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) -> ControlFlow { if self.effective_visibilities.is_reachable(v.def_id) { self.in_variant = true; intravisit::walk_variant(self, v); self.in_variant = false; } + Continue(()) } - fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { + fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) -> ControlFlow { let vis = self.tcx.visibility(s.def_id); if vis.is_public() || self.in_variant { intravisit::walk_field_def(self, s); } + Continue(()) } // We don't need to introspect into these at all: an // expression/block context can't possibly contain exported things. // (Making them no-ops stops us from traversing the whole AST without // having to be super careful about our `walk_...` calls above.) - fn visit_block(&mut self, _: &'tcx hir::Block<'tcx>) {} - fn visit_expr(&mut self, _: &'tcx hir::Expr<'tcx>) {} + fn visit_block(&mut self, _: &'tcx hir::Block<'tcx>) -> ControlFlow { + Continue(()) + } + fn visit_expr(&mut self, _: &'tcx hir::Expr<'tcx>) -> ControlFlow { + Continue(()) + } } /////////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index d3eba43b47e95..bf2ff68dd2a7b 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -25,3 +25,4 @@ rustc_target = { path = "../rustc_target" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } itertools = "0.10.1" +either = "1.7.0" diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index a844a1494e262..9cfc2434f2b24 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -15,6 +15,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::QueryNormalizeExt as _; use crate::traits::specialize::to_pretty_impl_header; use crate::traits::NormalizeExt; +use either::Either; use on_unimplemented::OnUnimplementedNote; use on_unimplemented::TypeErrCtxtExt as _; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -47,7 +48,7 @@ use rustc_span::symbol::sym; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; use std::iter; -use std::ops::ControlFlow; +use std::ops::ControlFlow::{self, Break, Continue}; use suggestions::TypeErrCtxtExt as _; pub use rustc_infer::traits::error_reporting::*; @@ -2378,12 +2379,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) = (body_id, subst.map(|subst| subst.unpack())) { - let mut expr_finder = FindExprBySpan::new(span); - expr_finder.visit_expr(&self.tcx.hir().body(body_id).value); + let mut expr_finder = FindExprBySpan { span }; - if let Some(hir::Expr { + if let Break(Either::Left(hir::Expr { kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), .. } - ) = expr_finder.result + )) = expr_finder.visit_expr(&self.tcx.hir().body(body_id).value) && let [ .., trait_path_segment @ hir::PathSegment { @@ -2866,31 +2866,25 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } /// Crude way of getting back an `Expr` from a `Span`. -pub struct FindExprBySpan<'hir> { +pub struct FindExprBySpan { pub span: Span, - pub result: Option<&'hir hir::Expr<'hir>>, - pub ty_result: Option<&'hir hir::Ty<'hir>>, } -impl<'hir> FindExprBySpan<'hir> { - pub fn new(span: Span) -> Self { - Self { span, result: None, ty_result: None } - } -} +impl<'v> Visitor<'v> for FindExprBySpan { + type BreakTy = Either<&'v hir::Expr<'v>, &'v hir::Ty<'v>>; -impl<'v> Visitor<'v> for FindExprBySpan<'v> { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> ControlFlow { if self.span == ex.span { - self.result = Some(ex); + Break(Either::Left(ex)) } else { - hir::intravisit::walk_expr(self, ex); + hir::intravisit::walk_expr(self, ex) } } - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> ControlFlow { if self.span == ty.span { - self.ty_result = Some(ty); + Break(Either::Right(ty)) } else { - hir::intravisit::walk_ty(self, ty); + hir::intravisit::walk_ty(self, ty) } } } @@ -2904,11 +2898,12 @@ struct FindTypeParam { } impl<'v> Visitor<'v> for FindTypeParam { - fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) { + fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) -> ControlFlow { // Skip where-clauses, to avoid suggesting indirection for type parameters found there. + Continue(()) } - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + fn visit_ty(&mut self, ty: &hir::Ty<'_>) -> ControlFlow { // We collect the spans of all uses of the "bare" type param, like in `field: T` or // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized` @@ -2935,6 +2930,7 @@ impl<'v> Visitor<'v> for FindTypeParam { hir::intravisit::walk_ty(self, ty); } } + Continue(()) } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 66d74fd05a67f..dd38f4eeab353 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -8,6 +8,7 @@ use super::{ use crate::infer::InferCtxt; use crate::traits::{NormalizeExt, ObligationCtxt}; +use either::Either; use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -39,7 +40,10 @@ use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; -use std::ops::Deref; +use std::ops::{ + ControlFlow::{self, Break, Continue}, + Deref, +}; use super::method_chain::CollectAllMismatches; use super::InferCtxtPrivExt; @@ -1002,11 +1006,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Remove all the desugaring and macro contexts. span.remove_mark(); } - let mut expr_finder = FindExprBySpan::new(span); + let mut expr_finder = FindExprBySpan { span }; let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return; }; let body = self.tcx.hir().body(body_id); - expr_finder.visit_expr(body.value); - let Some(expr) = expr_finder.result else { return; }; + let Break(Either::Left(expr)) = expr_finder.visit_expr(body.value) else { return; }; let Some(typeck) = &self.typeck_results else { return; }; let Some(ty) = typeck.expr_ty_adjusted_opt(expr) else { return; }; if !ty.is_unit() { @@ -1354,9 +1357,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // should be `x.starts_with(&("hi".to_string() + "you"))` let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; let body = self.tcx.hir().body(body_id); - let mut expr_finder = FindExprBySpan::new(span); - expr_finder.visit_expr(body.value); - let Some(expr) = expr_finder.result else { return false; }; + let mut expr_finder = FindExprBySpan { span }; + let Break(Either::Left(expr)) = expr_finder.visit_expr(body.value) else { return false; }; let needs_parens = match expr.kind { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, @@ -1456,12 +1458,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Remove all the hir desugaring contexts while maintaining the macro contexts. span.remove_mark(); } - let mut expr_finder = super::FindExprBySpan::new(span); + let mut expr_finder = super::FindExprBySpan { span }; let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; }; let body = self.tcx.hir().body(body_id); - expr_finder.visit_expr(body.value); + let found_expr = expr_finder.visit_expr(body.value); let mut maybe_suggest = |suggested_ty, count, suggestions| { // Remapping bound vars here let trait_pred_and_suggested_ty = @@ -1496,7 +1498,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut suggestions = vec![]; // Skipping binder here, remapping below let mut suggested_ty = trait_pred.self_ty().skip_binder(); - if let Some(mut hir_ty) = expr_finder.ty_result { + if let Break(Either::Right(mut hir_ty)) = found_expr { while let hir::TyKind::Ref(_, mut_ty) = &hir_ty.kind { count += 1; let span = hir_ty.span.until(mut_ty.ty.span); @@ -1516,7 +1518,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } // Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`. - let Some(mut expr) = expr_finder.result else { return false; }; + let Break(Either::Left(mut expr)) = found_expr else { return false; }; let mut count = 0; let mut suggestions = vec![]; // Skipping binder here, remapping below @@ -3932,7 +3934,7 @@ pub struct ReturnsVisitor<'v> { } impl<'v> Visitor<'v> for ReturnsVisitor<'v> { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> ControlFlow { // Visit every expression to detect `return` paths, either through the function's tail // expression or `return` statements. We walk all nodes to find `return` statements, but // we only care about tail expressions when `in_block_tail` is `true`, which means that @@ -3963,12 +3965,15 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> { } } // We need to walk to find `return`s in the entire body. - _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex), + _ if !self.in_block_tail => { + hir::intravisit::walk_expr(self, ex); + } _ => self.returns.push(ex), } + Continue(()) } - fn visit_body(&mut self, body: &'v hir::Body<'v>) { + fn visit_body(&mut self, body: &'v hir::Body<'v>) -> ControlFlow { assert!(!self.in_block_tail); if body.generator_kind().is_none() { if let hir::ExprKind::Block(block, None) = body.value.kind { @@ -3977,7 +3982,7 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> { } } } - hir::intravisit::walk_body(self, body); + hir::intravisit::walk_body(self, body) } } @@ -3988,7 +3993,7 @@ struct AwaitsVisitor { } impl<'v> Visitor<'v> for AwaitsVisitor { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> ControlFlow { if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind { self.awaits.push(id) } @@ -4060,7 +4065,7 @@ struct ReplaceImplTraitVisitor<'a> { } impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { - fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) { + fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) -> ControlFlow { if let hir::TyKind::Path(hir::QPath::Resolved( None, hir::Path { res: hir::def::Res::Def(_, segment_did), .. }, @@ -4072,11 +4077,11 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { // There might be more than one `impl Trait`. self.ty_spans.push(t.span); - return; + return Continue(()); } } - hir::intravisit::walk_ty(self, t); + hir::intravisit::walk_ty(self, t) } } diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index d4866b5dbdd49..23ec7612ea6c0 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -5,6 +5,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, DefIdTree, TyCtxt}; +use std::ops::ControlFlow; pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { @@ -134,7 +135,7 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) - } impl<'v> Visitor<'v> for RPITVisitor { - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> ControlFlow { if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind { self.rpits.push(item_id.owner_id.def_id) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0e8f0cfc5185d..c10e3d26c254c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -37,6 +37,7 @@ use std::collections::BTreeMap; use std::default::Default; use std::hash::Hash; use std::mem; +use std::ops::ControlFlow::{self, Break, Continue}; use thin_vec::ThinVec; use crate::core::{self, DocContext, ImplTraitParam}; @@ -2069,36 +2070,36 @@ fn clean_bare_fn_ty<'tcx>( /// item while looking for a given `Ident` which is stored into `item` if found. struct OneLevelVisitor<'hir> { map: rustc_middle::hir::map::Map<'hir>, - item: Option<&'hir hir::Item<'hir>>, looking_for: Ident, target_def_id: LocalDefId, } impl<'hir> OneLevelVisitor<'hir> { fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self { - Self { map, item: None, looking_for: Ident::empty(), target_def_id } + Self { map, looking_for: Ident::empty(), target_def_id } } fn reset(&mut self, looking_for: Ident) { self.looking_for = looking_for; - self.item = None; } } impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> { type NestedFilter = rustc_middle::hir::nested_filter::All; + type BreakTy = &'hir hir::Item<'hir>; fn nested_visit_map(&mut self) -> Self::Map { self.map } - fn visit_item(&mut self, item: &'hir hir::Item<'hir>) { - if self.item.is_none() - && item.ident == self.looking_for + fn visit_item(&mut self, item: &'hir hir::Item<'hir>) -> ControlFlow { + if item.ident == self.looking_for && (matches!(item.kind, hir::ItemKind::Use(_, _)) || item.owner_id.def_id == self.target_def_id) { - self.item = Some(item); + Break(item) + } else { + Continue(()) } } } @@ -2150,20 +2151,20 @@ fn get_all_import_attributes<'hir>( let looking_for = path.segments[path.segments.len() - 1].ident; visitor.reset(looking_for); - match parent { + let res = match parent { hir::Node::Item(parent_item) => { - hir::intravisit::walk_item(&mut visitor, parent_item); + hir::intravisit::walk_item(&mut visitor, parent_item) } hir::Node::Crate(m) => { hir::intravisit::walk_mod( &mut visitor, m, tcx.local_def_id_to_hir_id(def_id.as_local().unwrap()), - ); + ) } _ => break, - } - if let Some(i) = visitor.item { + }; + if let Break(i) = res { item = i; } else { break; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fbfc58a436b9b..d7b5a22c3ca36 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -20,6 +20,7 @@ use rustc_span::{source_map, Span}; use std::cell::RefCell; use std::mem; +use std::ops::ControlFlow; use std::rc::Rc; use std::sync::LazyLock; @@ -465,7 +466,7 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { self.tcx.hir() } - fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> ControlFlow { debug!("visiting path {:?}", path); if path.res == Res::Err { // We have less context here than in rustc_resolve, @@ -494,7 +495,7 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { // We could have an outer resolution that succeeded, // but with generic parameters that failed. // Recurse into the segments so we catch those too. - intravisit::walk_path(self, path); + intravisit::walk_path(self, path) } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 8a73d25d3f000..3fdccaa22bce7 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -22,6 +22,7 @@ use tempfile::Builder as TempFileBuilder; use std::env; use std::io::{self, Write}; +use std::ops::ControlFlow::{self, Continue}; use std::panic; use std::path::PathBuf; use std::process::{self, Command, Stdio}; @@ -141,7 +142,9 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { "".to_string(), CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), - |this| tcx.hir().walk_toplevel_module(this), + |this| { + tcx.hir().walk_toplevel_module(this); + }, ); collector @@ -1269,7 +1272,7 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> self.map } - fn visit_item(&mut self, item: &'hir hir::Item<'_>) { + fn visit_item(&mut self, item: &'hir hir::Item<'_>) -> ControlFlow { let name = match &item.kind { hir::ItemKind::Impl(impl_) => { rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id) @@ -1280,36 +1283,42 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> self.visit_testable(name, item.owner_id.def_id, item.span, |this| { intravisit::walk_item(this, item); }); + Continue(()) } - fn visit_trait_item(&mut self, item: &'hir hir::TraitItem<'_>) { + fn visit_trait_item(&mut self, item: &'hir hir::TraitItem<'_>) -> ControlFlow { self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { intravisit::walk_trait_item(this, item); }); + Continue(()) } - fn visit_impl_item(&mut self, item: &'hir hir::ImplItem<'_>) { + fn visit_impl_item(&mut self, item: &'hir hir::ImplItem<'_>) -> ControlFlow { self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { intravisit::walk_impl_item(this, item); }); + Continue(()) } - fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) { + fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) -> ControlFlow { self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { intravisit::walk_foreign_item(this, item); }); + Continue(()) } - fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) { + fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) -> ControlFlow { self.visit_testable(v.ident.to_string(), v.def_id, v.span, |this| { intravisit::walk_variant(this, v); }); + Continue(()) } - fn visit_field_def(&mut self, f: &'hir hir::FieldDef<'_>) { + fn visit_field_def(&mut self, f: &'hir hir::FieldDef<'_>) -> ControlFlow { self.visit_testable(f.ident.to_string(), f.def_id, f.span, |this| { intravisit::walk_field_def(this, f); }); + Continue(()) } } diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 4514894cabe0f..05736ff46396e 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::MacroKind; use rustc_span::{BytePos, ExpnKind, Span}; +use std::ops::ControlFlow::{self, Continue}; use std::path::{Path, PathBuf}; /// This enum allows us to store two different kinds of information: @@ -140,15 +141,15 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { self.tcx.hir() } - fn visit_path(&mut self, path: &rustc_hir::Path<'tcx>, _id: HirId) { + fn visit_path(&mut self, path: &rustc_hir::Path<'tcx>, _id: HirId) -> ControlFlow { if self.handle_macro(path.span) { - return; + return Continue(()); } self.handle_path(path); - intravisit::walk_path(self, path); + intravisit::walk_path(self, path) } - fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) { + fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) -> ControlFlow { // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another // file, we want to link to it. Otherwise no need to create a link. if !span.overlaps(m.spans.inner_span) { @@ -161,10 +162,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { ); } } - intravisit::walk_mod(self, m, id); + intravisit::walk_mod(self, m, id) } - fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) -> ControlFlow { if let ExprKind::MethodCall(segment, ..) = expr.kind { let hir = self.tcx.hir(); let body_id = hir.enclosing_body_owner(segment.hir_id); @@ -186,8 +187,8 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { } } else if self.handle_macro(expr.span) { // We don't want to go deeper into the macro. - return; + return Continue(()); } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index f28c164d61dad..96af271daaac1 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -28,6 +28,7 @@ use rustc_span::{ }; use std::fs; +use std::ops::ControlFlow::{self, Continue}; use std::path::PathBuf; #[derive(Debug, Clone)] @@ -136,7 +137,7 @@ where self.map } - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> ControlFlow { intravisit::walk_expr(self, ex); let tcx = self.tcx; @@ -146,7 +147,7 @@ where // test/run-make/rustdoc-scrape-examples-invalid-expr for an example. let hir = tcx.hir(); if hir.maybe_body_owned_by(ex.hir_id.owner.def_id).is_none() { - return; + return Continue(()); } // Get type of function if expression is a function call @@ -158,21 +159,21 @@ where (ty, ex.span, f.span) } else { trace!("node_type_opt({}) = None", f.hir_id); - return; + return Continue(()); } } hir::ExprKind::MethodCall(path, _, _, call_span) => { let types = tcx.typeck(ex.hir_id.owner.def_id); let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else { trace!("type_dependent_def_id({}) = None", ex.hir_id); - return; + return Continue(()); }; let ident_span = path.ident.span; (tcx.type_of(def_id).subst_identity(), call_span, ident_span) } _ => { - return; + return Continue(()); } }; @@ -180,7 +181,7 @@ where // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros. if call_span.from_expansion() { trace!("Rejecting expr from macro: {call_span:?}"); - return; + return Continue(()); } // If the enclosing item has a span coming from a proc macro, then we also don't want to include @@ -189,7 +190,7 @@ where tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id).into()); if enclosing_item_span.from_expansion() { trace!("Rejecting expr ({call_span:?}) from macro item: {enclosing_item_span:?}"); - return; + return Continue(()); } // If the enclosing item doesn't actually enclose the call, this means we probably have a weird @@ -198,7 +199,7 @@ where warn!( "Attempted to scrape call at [{call_span:?}] whose enclosing item [{enclosing_item_span:?}] doesn't contain the span of the call." ); - return; + return Continue(()); } // Similarly for the call w/ the function ident. @@ -206,14 +207,14 @@ where warn!( "Attempted to scrape call at [{call_span:?}] whose identifier [{ident_span:?}] was not contained in the span of the call." ); - return; + return Continue(()); } // Save call site if the function resolves to a concrete definition if let ty::FnDef(def_id, _) = ty.kind() { if self.target_crates.iter().all(|krate| *krate != def_id.krate) { trace!("Rejecting expr from crate not being documented: {call_span:?}"); - return; + return Continue(()); } let source_map = tcx.sess.source_map(); @@ -228,7 +229,7 @@ where Ok(abs_path) => abs_path, Err(_) => { trace!("Could not canonicalize file path: {}", file_path.display()); - return; + return Continue(()); } }; @@ -240,7 +241,7 @@ where trace!( "Rejecting expr ({call_span:?}) whose clean span ({clean_span:?}) cannot be turned into a link" ); - return; + return Continue(()); } }; @@ -263,12 +264,13 @@ where Some(location) => location, None => { trace!("Could not get serializable call location for {call_span:?}"); - return; + return Continue(()); } }; fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location); } } + Continue(()) } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 277201e4de978..dfcb5cd4438b5 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -14,6 +14,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::mem; +use std::ops::ControlFlow::{self, Continue}; use crate::clean::{cfg::Cfg, AttributesExt, NestedAttributesExt}; use crate::core; @@ -455,33 +456,40 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> { self.cx.tcx.hir() } - fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { + fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) -> ControlFlow { if self.visit_item_inner(i, None, None) { walk_item(self, i); } + Continue(()) } - fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) { + fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) -> ControlFlow { // Handled in `visit_item_inner` + Continue(()) } - fn visit_use(&mut self, _: &hir::UsePath<'tcx>, _: hir::HirId) { + fn visit_use(&mut self, _: &hir::UsePath<'tcx>, _: hir::HirId) -> ControlFlow { // Handled in `visit_item_inner` + Continue(()) } - fn visit_path(&mut self, _: &hir::Path<'tcx>, _: hir::HirId) { + fn visit_path(&mut self, _: &hir::Path<'tcx>, _: hir::HirId) -> ControlFlow { // Handled in `visit_item_inner` + Continue(()) } - fn visit_label(&mut self, _: &rustc_ast::Label) { + fn visit_label(&mut self, _: &rustc_ast::Label) -> ControlFlow { // Unneeded. + Continue(()) } - fn visit_infer(&mut self, _: &hir::InferArg) { + fn visit_infer(&mut self, _: &hir::InferArg) -> ControlFlow { // Unneeded. + Continue(()) } - fn visit_lifetime(&mut self, _: &hir::Lifetime) { + fn visit_lifetime(&mut self, _: &hir::Lifetime) -> ControlFlow { // Unneeded. + Continue(()) } } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index e8106beec3742..fd99640e97d41 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::eq_expr_value; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -464,7 +465,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow { if !e.span.from_expansion() { match &e.kind { ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => { @@ -478,7 +479,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { _ => {}, } } - walk_expr(self, e); + walk_expr(self, e) } } @@ -494,7 +495,7 @@ struct NotSimplificationVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind { if let Some(suggestion) = simplify_not(self.cx, inner) { span_lint_and_sugg( @@ -509,6 +510,6 @@ impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> { } } - walk_expr(self, expr); + walk_expr(self, expr) } } diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index dfa949d1af2f4..2e375888300fb 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -2,6 +2,7 @@ use clippy_utils::{ diagnostics::span_lint_and_sugg, get_parent_node, is_default_equivalent, macros::macro_backtrace, match_path, path_def_id, paths, ty::expr_sig, }; +use core::ops::ControlFlow::{self, Break}; use rustc_errors::Applicability; use rustc_hir::{ intravisit::{walk_ty, Visitor}, @@ -83,14 +84,15 @@ fn is_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { .map_or(false, |call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id)) } -#[derive(Default)] -struct InferVisitor(bool); +struct InferVisitor; impl<'tcx> Visitor<'tcx> for InferVisitor { - fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) { - self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..)); - if !self.0 { - walk_ty(self, t); + type BreakTy = (); + fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) -> ControlFlow<()> { + if matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..)) { + Break(()) + } else { + walk_ty(self, t) } } } @@ -98,9 +100,8 @@ impl<'tcx> Visitor<'tcx> for InferVisitor { fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match get_parent_node(cx.tcx, expr.hir_id) { Some(Node::Local(Local { ty: Some(ty), .. })) => { - let mut v = InferVisitor::default(); - v.visit_ty(ty); - !v.0 + let mut v = InferVisitor; + !v.visit_ty(ty).is_break() }, Some( Node::Expr(Expr { diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index f10c35cde52a1..d9d0f38bb9ed7 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -525,24 +525,18 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo .iter() .filter(|&&(_, name)| !name.as_str().starts_with('_')) .any(|&(_, name)| { - let mut walker = ContainsName { - name, - result: false, - cx, - }; - - // Scan block - block + let mut walker = ContainsName { name, cx }; + let found = block .stmts .iter() .filter(|stmt| !ignore_span.overlaps(stmt.span)) - .for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt)); + .any(|stmt| intravisit::walk_stmt(&mut walker, stmt).is_break()); - if let Some(expr) = block.expr { - intravisit::walk_expr(&mut walker, expr); + if !found && let Some(expr) = block.expr { + intravisit::walk_expr(&mut walker, expr).is_break() + } else { + found } - - walker.result }) }) } diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 4e1a6cd4d7355..b8b1e1b3a34ec 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet_opt; use clippy_utils::{get_parent_node, numeric_literal}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; @@ -125,7 +126,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { match &expr.kind { ExprKind::Call(func, args) => { if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) { @@ -135,7 +136,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { self.visit_expr(expr); self.ty_bounds.pop(); } - return; + return Continue(()); } }, @@ -147,7 +148,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { self.visit_expr(expr); self.ty_bounds.pop(); } - return; + return Continue(()); } }, @@ -181,7 +182,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { self.visit_expr(base); self.ty_bounds.pop(); } - return; + return Continue(()); } } }, @@ -189,16 +190,16 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { ExprKind::Lit(lit) => { let ty = self.cx.typeck_results().expr_ty(expr); self.check_lit(lit, ty, expr.hir_id); - return; + return Continue(()); }, _ => {}, } - walk_expr(self, expr); + walk_expr(self, expr) } - fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { + fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) -> ControlFlow { match stmt.kind { // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric` StmtKind::Local(local) => self.ty_bounds.push(ExplicitTyBound(local.ty.is_some())), @@ -208,6 +209,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { walk_stmt(self, stmt); self.ty_bounds.pop(); + Continue(()) } } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 47501980e6640..ea24e843ed1ea 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -8,6 +8,7 @@ use clippy_utils::{ fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage, }; +use core::ops::ControlFlow::{self, Break, Continue}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch}; @@ -1059,32 +1060,32 @@ fn binding_ty_auto_deref_stability<'tcx>( // Checks whether a type is inferred at some point. // e.g. `_`, `Box<_>`, `[_]` fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { - struct V(bool); + struct V; impl Visitor<'_> for V { - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { - if self.0 - || matches!( - ty.kind, - TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err(_) - ) - { - self.0 = true; + type BreakTy = (); + fn visit_ty(&mut self, ty: &hir::Ty<'_>) -> ControlFlow<()> { + if matches!( + ty.kind, + TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(_) | TyKind::Err(_) + ) { + Break(()) } else { - walk_ty(self, ty); + walk_ty(self, ty) } } - fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) { - if self.0 || matches!(arg, GenericArg::Infer(_)) { - self.0 = true; + fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) -> ControlFlow<()> { + if matches!(arg, GenericArg::Infer(_)) { + Break(()) } else if let GenericArg::Type(ty) = arg { - self.visit_ty(ty); + self.visit_ty(ty) + } else { + Continue(()) } } } - let mut v = V(false); - v.visit_ty(ty); - v.0 + let mut v = V; + v.visit_ty(ty).is_break() } fn call_is_qualified(expr: &Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index b8428d66a5dc8..991fa425f9e66 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lin use clippy_utils::paths; use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy}; use clippy_utils::{is_lint_allowed, match_def_path}; +use core::ops::ControlFlow::{self, Break}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; @@ -389,9 +390,8 @@ fn check_unsafe_derive_deserialize<'tcx>( ty: Ty<'tcx>, ) { fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool { - let mut visitor = UnsafeVisitor { cx, has_unsafe: false }; - walk_item(&mut visitor, item); - visitor.has_unsafe + let mut visitor = UnsafeVisitor { cx }; + walk_item(&mut visitor, item).is_break() } if_chain! { @@ -420,40 +420,37 @@ fn check_unsafe_derive_deserialize<'tcx>( struct UnsafeVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - has_unsafe: bool, } impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { type NestedFilter = nested_filter::All; - - fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) { - if self.has_unsafe { - return; - } - - if_chain! { - if let Some(header) = kind.header(); - if header.unsafety == Unsafety::Unsafe; - then { - self.has_unsafe = true; - } + type BreakTy = (); + + fn visit_fn( + &mut self, + kind: FnKind<'tcx>, + decl: &'tcx FnDecl<'_>, + body_id: BodyId, + _: Span, + id: LocalDefId, + ) -> ControlFlow<()> { + if let Some(header) = kind.header() + && header.unsafety == Unsafety::Unsafe + { + Break(()) + } else { + walk_fn(self, kind, decl, body_id, id) } - - walk_fn(self, kind, decl, body_id, id); } - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.has_unsafe { - return; - } - - if let ExprKind::Block(block, _) = expr.kind { - if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { - self.has_unsafe = true; - } + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow<()> { + if let ExprKind::Block(block, _) = expr.kind + && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + { + Break(()) + } else { + walk_expr(self, expr) } - - walk_expr(self, expr); } fn nested_visit_map(&mut self) -> Self::Map { diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index 384aca7feadd6..f97e375e262ff 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -4,6 +4,7 @@ use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::source::{first_line_of_span, snippet_with_applicability}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty}; +use core::ops::ControlFlow::{self, Break, Continue}; use if_chain::if_chain; use itertools::Itertools; use pulldown_cmark::Event::{ @@ -303,10 +304,9 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { let mut fpu = FindPanicUnwrap { cx, typeck_results: cx.tcx.typeck(item.owner_id.def_id), - panic_span: None, }; - fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span); + let panic_span = fpu.visit_expr(body.value).break_value(); + lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), panic_span); } }, hir::ItemKind::Impl(impl_) => { @@ -358,10 +358,9 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown { let mut fpu = FindPanicUnwrap { cx, typeck_results: cx.tcx.typeck(item.owner_id.def_id), - panic_span: None, }; - fpu.visit_expr(body.value); - lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), fpu.panic_span); + let panic_span = fpu.visit_expr(body.value).break_value(); + lint_for_missing_headers(cx, item.owner_id, sig, headers, Some(body_id), panic_span); } } } @@ -890,18 +889,14 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span) { struct FindPanicUnwrap<'a, 'tcx> { cx: &'a LateContext<'tcx>, - panic_span: Option, typeck_results: &'tcx ty::TypeckResults<'tcx>, } impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = Span; - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.panic_span.is_some() { - return; - } - + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { if let Some(macro_call) = root_macro_call_first_node(self.cx, expr) { if is_panic(self.cx, macro_call.def_id) || matches!( @@ -909,7 +904,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { "assert" | "assert_eq" | "assert_ne" | "todo" ) { - self.panic_span = Some(macro_call.span); + return Break(macro_call.span); } } @@ -919,16 +914,18 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result) { - self.panic_span = Some(expr.span); + return Break(expr.span); } } // and check sub-expressions - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } // Panics in const blocks will cause compilation to fail. - fn visit_anon_const(&mut self, _: &'tcx AnonConst) {} + fn visit_anon_const(&mut self, _: &'tcx AnonConst) -> ControlFlow { + Continue(()) + } fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 48a54f60253c8..6acf27b49d687 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -7,6 +7,7 @@ use clippy_utils::{ SpanlessEq, }; use core::fmt::{self, Write}; +use core::ops::ControlFlow::{self, Break, Continue}; use rustc_errors::Applicability; use rustc_hir::{ hir_id::HirIdSet, @@ -316,8 +317,6 @@ struct InsertSearcher<'cx, 'tcx> { ctxt: SyntaxContext, /// Whether this expression can be safely moved into a closure. allow_insert_closure: bool, - /// Whether this expression can use the entry api. - can_use_entry: bool, /// Whether this expression is the final expression in this code path. This may be a statement. in_tail_pos: bool, // Is this expression a single insert. A slightly better suggestion can be made in this case. @@ -335,30 +334,33 @@ impl<'tcx> InsertSearcher<'_, 'tcx> { /// Visit the expression as a branch in control flow. Multiple insert calls can be used, but /// only if they are on separate code paths. This will return whether the map was used in the /// given expression. - fn visit_cond_arm(&mut self, e: &'tcx Expr<'_>) -> bool { + fn visit_cond_arm(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<(), bool> { let is_map_used = self.is_map_used; let in_tail_pos = self.in_tail_pos; - self.visit_expr(e); + self.visit_expr(e)?; let res = self.is_map_used; self.is_map_used = is_map_used; self.in_tail_pos = in_tail_pos; - res + Continue(res) } /// Visits an expression which is not itself in a tail position, but other sibling expressions /// may be. e.g. if conditions - fn visit_non_tail_expr(&mut self, e: &'tcx Expr<'_>) { + fn visit_non_tail_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { let in_tail_pos = self.in_tail_pos; self.in_tail_pos = false; - self.visit_expr(e); + self.visit_expr(e)?; self.in_tail_pos = in_tail_pos; + Continue(()) } } impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { - fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { + type BreakTy = (); + + fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) -> ControlFlow<()> { match stmt.kind { StmtKind::Semi(e) => { - self.visit_expr(e); + self.visit_expr(e)?; if self.in_tail_pos && self.allow_insert_closure { // The spans are used to slice the top level expression into multiple parts. This requires that @@ -371,14 +373,14 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { } } }, - StmtKind::Expr(e) => self.visit_expr(e), + StmtKind::Expr(e) => self.visit_expr(e)?, StmtKind::Local(l) => { - self.visit_pat(l.pat); + self.visit_pat(l.pat)?; if let Some(e) = l.init { self.allow_insert_closure &= !self.in_tail_pos; self.in_tail_pos = false; self.is_single_insert = false; - self.visit_expr(e); + self.visit_expr(e)?; } }, StmtKind::Item(_) => { @@ -386,42 +388,40 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { self.is_single_insert = false; }, } + Continue(()) } - fn visit_block(&mut self, block: &'tcx Block<'_>) { + fn visit_block(&mut self, block: &'tcx Block<'_>) -> ControlFlow<()> { // If the block is in a tail position, then the last expression (possibly a statement) is in the // tail position. The rest, however, are not. match (block.stmts, block.expr) { ([], None) => { self.allow_insert_closure &= !self.in_tail_pos; }, - ([], Some(expr)) => self.visit_expr(expr), + ([], Some(expr)) => self.visit_expr(expr)?, (stmts, Some(expr)) => { let in_tail_pos = self.in_tail_pos; self.in_tail_pos = false; for stmt in stmts { - self.visit_stmt(stmt); + self.visit_stmt(stmt)?; } self.in_tail_pos = in_tail_pos; - self.visit_expr(expr); + self.visit_expr(expr)?; }, ([stmts @ .., stmt], None) => { let in_tail_pos = self.in_tail_pos; self.in_tail_pos = false; for stmt in stmts { - self.visit_stmt(stmt); + self.visit_stmt(stmt)?; } self.in_tail_pos = in_tail_pos; - self.visit_stmt(stmt); + self.visit_stmt(stmt)?; }, } + Continue(()) } - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if !self.can_use_entry { - return; - } - + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow<()> { match try_parse_insert(self.cx, expr) { Some(insert_expr) if SpanlessEq::new(self.cx).eq_expr(self.map, insert_expr.map) => { // Multiple inserts, inserts with a different key, and inserts from a macro can't use the entry api. @@ -429,8 +429,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { || !SpanlessEq::new(self.cx).eq_expr(self.key, insert_expr.key) || expr.span.ctxt() != self.ctxt { - self.can_use_entry = false; - return; + return Break(()); } self.edits.push(Edit::Insertion(Insertion { @@ -442,7 +441,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { // The value doesn't affect whether there is only a single insert expression. let is_single_insert = self.is_single_insert; - self.visit_non_tail_expr(insert_expr.value); + self.visit_non_tail_expr(insert_expr.value)?; self.is_single_insert = is_single_insert; }, _ if SpanlessEq::new(self.cx).eq_expr(self.map, expr) => { @@ -451,23 +450,23 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { _ => match expr.kind { ExprKind::If(cond_expr, then_expr, Some(else_expr)) => { self.is_single_insert = false; - self.visit_non_tail_expr(cond_expr); + self.visit_non_tail_expr(cond_expr)?; // Each branch may contain it's own insert expression. - let mut is_map_used = self.visit_cond_arm(then_expr); - is_map_used |= self.visit_cond_arm(else_expr); + let mut is_map_used = self.visit_cond_arm(then_expr)?; + is_map_used |= self.visit_cond_arm(else_expr)?; self.is_map_used = is_map_used; }, ExprKind::Match(scrutinee_expr, arms, _) => { self.is_single_insert = false; - self.visit_non_tail_expr(scrutinee_expr); + self.visit_non_tail_expr(scrutinee_expr)?; // Each branch may contain it's own insert expression. let mut is_map_used = self.is_map_used; for arm in arms { - self.visit_pat(arm.pat); + self.visit_pat(arm.pat)?; if let Some(Guard::If(guard) | Guard::IfLet(&Let { init: guard, .. })) = arm.guard { - self.visit_non_tail_expr(guard); + self.visit_non_tail_expr(guard)?; } - is_map_used |= self.visit_cond_arm(arm.body); + is_map_used |= self.visit_cond_arm(arm.body)?; } self.is_map_used = is_map_used; }, @@ -477,16 +476,14 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { self.allow_insert_closure &= !self.in_tail_pos; // Don't allow insertions inside of a loop. let edit_len = self.edits.len(); - self.visit_block(block); + self.visit_block(block)?; if self.edits.len() != edit_len { - self.can_use_entry = false; + return Break(()); } self.loops.pop(); }, - ExprKind::Block(block, _) => self.visit_block(block), - ExprKind::InlineAsm(_) => { - self.can_use_entry = false; - }, + ExprKind::Block(block, _) => self.visit_block(block)?, + ExprKind::InlineAsm(_) => return Break(()), _ => { self.allow_insert_closure &= !self.in_tail_pos; self.allow_insert_closure &= @@ -494,16 +491,18 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { // Sub expressions are no longer in the tail position. self.is_single_insert = false; self.in_tail_pos = false; - walk_expr(self, expr); + walk_expr(self, expr)?; }, }, } + Continue(()) } - fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) { + fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) -> ControlFlow<()> { p.each_binding_or_first(&mut |_, id, _, _| { self.locals.insert(id); }); + Continue(()) } } @@ -626,19 +625,15 @@ fn find_insert_calls<'tcx>( edits: Vec::new(), is_map_used: false, allow_insert_closure: true, - can_use_entry: true, in_tail_pos: true, is_single_insert: true, loops: Vec::new(), locals: HirIdSet::default(), }; - s.visit_expr(expr); - let allow_insert_closure = s.allow_insert_closure; - let is_single_insert = s.is_single_insert; - let edits = s.edits; - s.can_use_entry.then_some(InsertSearchResults { - edits, - allow_insert_closure, - is_single_insert, + let can_use_entry = s.visit_expr(expr).is_continue(); + can_use_entry.then_some(InsertSearchResults { + edits: s.edits, + allow_insert_closure: s.allow_insert_closure, + is_single_insert: s.is_single_insert, }) } diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index 20565e1d232ee..8366f73e91b87 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::trait_ref_of_method; +use core::ops::ControlFlow::{self, Continue}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor}; @@ -160,21 +161,22 @@ fn bound_to_trait_def_id(bound: &GenericBound<'_>) -> Option { impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { + fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) -> ControlFlow { if let Some((def_id, _)) = t.peel_refs().as_generic_param() { self.mark_param_used(def_id); + Continue(()) } else if let TyKind::OpaqueDef(id, _, _) = t.kind { // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked. let item = self.nested_visit_map().item(id); - walk_item(self, item); + walk_item(self, item) } else { - walk_ty(self, t); + walk_ty(self, t) } } - fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) { + fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) -> ControlFlow { if let WherePredicate::BoundPredicate(predicate) = predicate { // Collect spans for any bounds on type parameters. We only keep bounds that appear in // the list of generics (not in a where-clause). @@ -197,6 +199,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> { walk_param_bound(self, bound); } } + Continue(()) } fn nested_visit_map(&mut self) -> Self::Map { diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index 2ef547526d4f7..3fd5e669439ff 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; use clippy_utils::method_chain_args; use clippy_utils::ty::is_type_diagnostic_item; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -75,7 +76,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl } impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) { if is_panic(self.lcx, macro_call.def_id) { self.result.push(expr.span); @@ -93,7 +94,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl } // and check sub-expressions - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } } diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index bd66ace4500a8..43803b1abca8d 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -3,6 +3,7 @@ use clippy_utils::macros::span_is_local; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::path_def_id; use clippy_utils::source::snippet_opt; +use core::ops::ControlFlow::{self, Continue}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::{ @@ -127,7 +128,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> { self.cx.tcx.hir() } - fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> ControlFlow { for segment in path.segments { match segment.ident.name { kw::SelfLower => self.lower.push(segment.ident.span), @@ -140,12 +141,14 @@ impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> { if !self.invalid { walk_path(self, path); } + Continue(()) } - fn visit_name(&mut self, name: Symbol) { + fn visit_name(&mut self, name: Symbol) -> ControlFlow { if name == sym::val { self.invalid = true; } + Continue(()) } } 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 9ea8c494cfcda..ca2cb67ec8006 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::SpanlessEq; +use core::ops::ControlFlow::{self, Break, Continue}; use if_chain::if_chain; use rustc_errors::Diagnostic; use rustc_hir::intravisit::{self as visit, Visitor}; @@ -46,8 +47,7 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]); impl<'tcx> LateLintPass<'tcx> for IfLetMutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - let mut arm_visit = ArmVisitor { found_mutex: None, cx }; - let mut op_visit = OppVisitor { found_mutex: None, cx }; + let mut visitor = LockVisitor { cx }; if let Some(higher::IfLet { let_expr, if_then, @@ -55,12 +55,15 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { .. }) = higher::IfLet::hir(cx, expr) { - op_visit.visit_expr(let_expr); - if let Some(op_mutex) = op_visit.found_mutex { - arm_visit.visit_expr(if_then); - arm_visit.visit_expr(if_else); + if let Break(op_mutex) = visitor.visit_expr(let_expr) { + let arm_mutex = match visitor.visit_expr(if_then) { + Continue(()) => visitor.visit_expr(if_else).break_value(), + Break(x) => Some(x), + }; - if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) { + if let Some(arm_mutex) = arm_mutex + && SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex) + { let diag = |diag: &mut Diagnostic| { diag.span_label( op_mutex.span, @@ -85,45 +88,19 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { } } -/// Checks if `Mutex::lock` is called in the `if let` expr. -pub struct OppVisitor<'a, 'tcx> { - found_mutex: Option<&'tcx Expr<'tcx>>, +/// Checks if `Mutex::lock` is called. +pub struct LockVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, } -impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { +impl<'tcx> Visitor<'tcx> for LockVisitor<'_, 'tcx> { + type BreakTy = &'tcx Expr<'tcx>; + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { - self.found_mutex = Some(mutex); - return; - } - visit::walk_expr(self, expr); - } -} - -/// Checks if `Mutex::lock` is called in any of the branches. -pub struct ArmVisitor<'a, 'tcx> { - found_mutex: Option<&'tcx Expr<'tcx>>, - cx: &'a LateContext<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { - self.found_mutex = Some(mutex); - return; + Break(mutex) + } else { + visit::walk_expr(self, expr) } - visit::walk_expr(self, expr); - } -} - -impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { - fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> { - self.found_mutex.and_then(|arm_mutex| { - SpanlessEq::new(self.cx) - .eq_expr(op_mutex, arm_mutex) - .then_some(arm_mutex) - }) } } diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index 64a4a3fa741bc..f13e5dbcab730 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::collections::BTreeMap; +use std::ops::ControlFlow::{self, Continue}; use rustc_errors::Diagnostic; use rustc_hir as hir; @@ -292,20 +293,20 @@ impl<'a, 'tcx> ImplicitHasherTypeVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> { - fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) { + fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) -> ControlFlow { if let Some(target) = ImplicitHasherType::new(self.cx, t) { self.found.push(target); } - walk_ty(self, t); + walk_ty(self, t) } - fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) -> ControlFlow { if let Some(target) = ImplicitHasherType::new(self.cx, &inf.to_ty()) { self.found.push(target); } - walk_inf(self, inf); + walk_inf(self, inf) } } @@ -331,13 +332,14 @@ impl<'a, 'b, 'tcx> ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_body(&mut self, body: &'tcx Body<'_>) { + fn visit_body(&mut self, body: &'tcx Body<'_>) -> ControlFlow { let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id())); walk_body(self, body); self.maybe_typeck_results = old_maybe_typeck_results; + Continue(()) } - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow { if_chain! { if let ExprKind::Call(fun, args) = e.kind; if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind; @@ -345,7 +347,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't if let Some(ty_did) = ty_path.res.opt_def_id(); then { if self.target.ty() != self.maybe_typeck_results.unwrap().expr_ty(e) { - return; + return Continue(()); } if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { @@ -378,7 +380,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't } } - walk_expr(self, e); + walk_expr(self, e) } fn nested_visit_map(&mut self) -> Self::Map { diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index bdeddf44df7bd..fa650885003b6 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -4,6 +4,7 @@ use clippy_utils::higher::IfLet; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_copy; use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Applicability; @@ -236,7 +237,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { self.cx.tcx.hir() } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { if let Some(local_id) = path_to_local(expr) { let Self { cx, @@ -264,13 +265,13 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { if let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind; then { use_info.index_use.push((index_value, map.span(parent_expr.hir_id))); - return; + return Continue(()); } } // The slice was used for something other than indexing self.slice_lint_info.remove(&local_id); } - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 145cf524652f1..45f9fb5277064 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -1,8 +1,10 @@ #![feature(array_windows)] #![feature(binary_heap_into_iter_sorted)] #![feature(box_patterns)] +#![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(if_let_guard)] +#![feature(is_some_and)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(lint_reasons)] diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 986ffcad883db..631c52afdda76 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::trait_ref_of_method; +use core::ops::ControlFlow::{self, Break, Continue}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; @@ -373,11 +374,8 @@ fn could_use_elision<'tcx>( return None; } - let mut checker = BodyLifetimeChecker { - lifetimes_used_in_body: false, - }; - checker.visit_expr(body.value); - if checker.lifetimes_used_in_body { + let mut checker = BodyLifetimeChecker; + if checker.visit_expr(body.value).is_break() { return None; } } @@ -497,11 +495,12 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { // for lifetimes as parameters of generics - fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow { self.lts.push(*lifetime); + Continue(()) } - fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) { + fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) -> ControlFlow { let trait_ref = &poly_tref.trait_ref; if let Some(id) = trait_ref.trait_def_id() && lang_items::FN_TRAITS.iter().any(|&item| { self.cx.tcx.lang_items().get(item) == Some(id) @@ -512,9 +511,10 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { } else { walk_poly_trait_ref(self, poly_tref); } + Continue(()) } - fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { + fn visit_ty(&mut self, ty: &'tcx Ty<'_>) -> ControlFlow { match ty.kind { TyKind::OpaqueDef(item, bounds, _) => { let map = self.cx.tcx.hir(); @@ -540,8 +540,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { self.visit_poly_trait_ref(bound); } }, - _ => walk_ty(self, ty), + _ => { + walk_ty(self, ty); + }, } + Continue(()) } } @@ -611,11 +614,12 @@ where type NestedFilter = F; // for lifetimes as parameters of generics - fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow { self.map.remove(&lifetime.ident.name); + Continue(()) } - fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) { + fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) -> ControlFlow { // don't actually visit `<'a>` or `<'a: 'b>` // we've already visited the `'a` declarations and // don't want to spuriously remove them @@ -624,6 +628,7 @@ where if let GenericParamKind::Type { .. } = param.kind { walk_generic_param(self, param); } + Continue(()) } fn nested_visit_map(&mut self) -> Self::Map { @@ -685,15 +690,16 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<' } } -struct BodyLifetimeChecker { - lifetimes_used_in_body: bool, -} +struct BodyLifetimeChecker; impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { + type BreakTy = (); // for lifetimes as parameters of generics - fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { + fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow<()> { if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime { - self.lifetimes_used_in_body = true; + Break(()) + } else { + Continue(()) } } } diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 4dae93f6028d4..a1276d8c2b62c 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -1,6 +1,7 @@ use super::MUT_RANGE_BOUND; use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::{get_enclosing_block, higher, path_to_local}; +use core::ops::ControlFlow::{self, Break, Continue}; use if_chain::if_chain; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind}; @@ -125,8 +126,6 @@ impl MutatePairDelegate<'_, '_> { struct BreakAfterExprVisitor { hir_id: HirId, past_expr: bool, - past_candidate: bool, - break_after_expr: bool, } impl BreakAfterExprVisitor { @@ -134,33 +133,22 @@ impl BreakAfterExprVisitor { let mut visitor = BreakAfterExprVisitor { hir_id, past_expr: false, - past_candidate: false, - break_after_expr: false, }; - get_enclosing_block(cx, hir_id).map_or(false, |block| { - visitor.visit_block(block); - visitor.break_after_expr - }) + get_enclosing_block(cx, hir_id).map_or(false, |block| visitor.visit_block(block).break_value().unwrap_or(false)) } } impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor { - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if self.past_candidate { - return; - } - + type BreakTy = bool; + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { if expr.hir_id == self.hir_id { self.past_expr = true; + Continue(()) } else if self.past_expr { - if matches!(&expr.kind, ExprKind::Break(..)) { - self.break_after_expr = true; - } - - self.past_candidate = true; + Break(matches!(&expr.kind, ExprKind::Break(..))) } else { - intravisit::walk_expr(self, expr); + intravisit::walk_expr(self, expr) } } } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 5c317c2a5bbb6..a70a2a12c9413 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -4,6 +4,7 @@ use clippy_utils::source::snippet; use clippy_utils::ty::has_iter_method; use clippy_utils::visitors::is_local_used; use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -300,7 +301,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { if_chain! { // a range index op if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind; @@ -313,7 +314,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id)); if !self.check(args_1, args_0, expr); then { - return; + return Continue(()); } } @@ -322,7 +323,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if let ExprKind::Index(seqexpr, idx) = expr.kind; if !self.check(idx, seqexpr, expr); then { - return; + return Continue(()); } } @@ -386,8 +387,9 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { let body = self.cx.tcx.hir().body(body); self.visit_expr(body.value); }, - _ => walk_expr(self, expr), + _ => walk_expr(self, expr)?, } self.prefer_mutable = old; + Continue(()) } } diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 540656a2cd991..74112e57563ef 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -3,6 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::path_to_local; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -130,11 +131,11 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { match &expr.kind { // Non-determinism may occur ... don't give a lint ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::If(..) => self.non_deterministic_expr = true, - ExprKind::Block(block, _) => self.visit_block(block), + ExprKind::Block(block, _) => self.visit_block(block)?, _ => { if let Some(hir_id) = path_to_local(expr) { self.used_locals.insert(hir_id); @@ -142,20 +143,22 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { walk_expr(self, expr); }, } + Continue(()) } - fn visit_block(&mut self, b: &'tcx Block<'_>) { + fn visit_block(&mut self, b: &'tcx Block<'_>) -> ControlFlow { for stmt in b.stmts.iter() { self.visit_stmt(stmt); } + Continue(()) } - fn visit_stmt(&mut self, s: &'tcx Stmt<'_>) { + fn visit_stmt(&mut self, s: &'tcx Stmt<'_>) -> ControlFlow { let vec_push_option = get_vec_push(self.cx, s); if vec_push_option.is_none() { // Current statement is not a push so visit inside match &s.kind { - StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(expr), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(expr)?, _ => {}, } } else { @@ -168,6 +171,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { self.multiple_pushes = true; } } + Continue(()) } } diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 28ee24309cc46..e654f2579cc74 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -1,5 +1,6 @@ use clippy_utils::ty::{has_iter_method, implements_trait}; use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; @@ -48,14 +49,14 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { // If node is a variable if let Some(def_id) = path_to_local(expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial); if *state == IncrementVisitorVarState::IncrOnce { *state = IncrementVisitorVarState::DontWarn; - return; + return Continue(()); } match parent.kind { @@ -95,6 +96,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } else { walk_expr(self, expr); } + Continue(()) } } @@ -144,7 +146,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_local(&mut self, l: &'tcx Local<'_>) { + fn visit_local(&mut self, l: &'tcx Local<'_>) -> ControlFlow { // Look for declarations of the variable if_chain! { if l.pat.hir_id == self.var_id; @@ -162,28 +164,28 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } } - walk_local(self, l); + walk_local(self, l) } - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { if matches!(self.state, InitializeVisitorState::DontWarn) { - return; + return Continue(()); } if expr.hir_id == self.end_expr.hir_id { self.past_loop = true; - return; + return Continue(()); } // No need to visit expressions before the variable is // declared if matches!(self.state, InitializeVisitorState::Initial) { - return; + return Continue(()); } // If node is the desired variable, see how it's used if path_to_local_id(expr, self.var_id) { if self.past_loop { self.state = InitializeVisitorState::DontWarn; - return; + return Continue(()); } if let Some(parent) = get_parent_expr(self.cx, expr) { @@ -243,6 +245,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } else { walk_expr(self, expr); } + Continue(()) } fn nested_visit_map(&mut self) -> Self::Map { @@ -274,43 +277,45 @@ pub(super) struct LoopNestVisitor { } impl<'tcx> Visitor<'tcx> for LoopNestVisitor { - fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { + fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) -> ControlFlow { if stmt.hir_id == self.hir_id { self.nesting = LookFurther; } else if self.nesting == Unknown { walk_stmt(self, stmt); } + Continue(()) } - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { if self.nesting != Unknown { - return; + return Continue(()); } if expr.hir_id == self.hir_id { self.nesting = LookFurther; - return; + return Continue(()); } match expr.kind { ExprKind::Assign(path, _, _) | ExprKind::AssignOp(_, path, _) => { if path_to_local_id(path, self.iterator) { self.nesting = RuledOut; } + Continue(()) }, _ => walk_expr(self, expr), } } - fn visit_pat(&mut self, pat: &'tcx Pat<'_>) { + fn visit_pat(&mut self, pat: &'tcx Pat<'_>) -> ControlFlow { if self.nesting != Unknown { - return; + return Continue(()); } if let PatKind::Binding(_, id, ..) = pat.kind { if id == self.iterator { self.nesting = RuledOut; - return; + return Continue(()); } } - walk_pat(self, pat); + walk_pat(self, pat) } } diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs index d1a1f773f87b3..dceb53d9311e2 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs @@ -2,6 +2,7 @@ use super::WHILE_IMMUTABLE_CONDITION; use clippy_utils::consts::constant; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::usage::mutated_variables; +use core::ops::ControlFlow::{self, Break, Continue}; use if_chain::if_chain; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; @@ -20,10 +21,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &' cx, ids: HirIdSet::default(), def_ids: DefIdMap::default(), - skip: false, }; - var_visitor.visit_expr(cond); - if var_visitor.skip { + if var_visitor.visit_expr(cond).is_break() { return; } let used_in_condition = &var_visitor.ids; @@ -37,11 +36,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &' }; let mutable_static_in_cond = var_visitor.def_ids.items().any(|(_, v)| *v); - let mut has_break_or_return_visitor = HasBreakOrReturnVisitor { - has_break_or_return: false, - }; - has_break_or_return_visitor.visit_expr(expr); - let has_break_or_return = has_break_or_return_visitor.has_break_or_return; + let mut has_break_or_return_visitor = HasBreakOrReturnVisitor; + let has_break_or_return = has_break_or_return_visitor.visit_expr(expr).is_break(); if no_cond_variable_mutated && !mutable_static_in_cond { span_lint_and_then( @@ -61,25 +57,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &' } } -struct HasBreakOrReturnVisitor { - has_break_or_return: bool, -} - +struct HasBreakOrReturnVisitor; impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.has_break_or_return { - return; - } - + type BreakTy = (); + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow<()> { match expr.kind { - ExprKind::Ret(_) | ExprKind::Break(_, _) => { - self.has_break_or_return = true; - return; - }, - _ => {}, + ExprKind::Ret(_) | ExprKind::Break(_, _) => Break(()), + _ => walk_expr(self, expr), } - - walk_expr(self, expr); } } @@ -91,7 +76,6 @@ struct VarCollectorVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, ids: HirIdSet, def_ids: DefIdMap, - skip: bool, } impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { @@ -116,11 +100,15 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { + type BreakTy = (); + fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> ControlFlow<()> { match ex.kind { - ExprKind::Path(_) => self.insert_def_id(ex), + ExprKind::Path(_) => { + self.insert_def_id(ex); + Continue(()) + }, // If there is any function/method call… we just stop analysis - ExprKind::Call(..) | ExprKind::MethodCall(..) => self.skip = true, + ExprKind::Call(..) | ExprKind::MethodCall(..) => Break(()), _ => walk_expr(self, ex), } diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index 55989f8a44650..23794cc0c618f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -5,6 +5,7 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::{ get_enclosing_loop_or_multi_call_closure, is_refutable, is_res_lang_ctor, is_trait_method, visitors::is_res_used, }; +use core::ops::ControlFlow::{self, Break, Continue}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -208,35 +209,29 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc struct V<'a, 'b, 'tcx> { cx: &'a LateContext<'tcx>, iter_expr: &'b IterExpr, - uses_iter: bool, } impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if self.uses_iter { - // return - } else if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { - self.uses_iter = true; + type BreakTy = (); + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { + if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { + return Break(()); } else if let (e, true) = skip_fields_and_path(e) { if let Some(e) = e { - self.visit_expr(e); + self.visit_expr(e)?; } } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind { if is_res_used(self.cx, self.iter_expr.path, id) { - self.uses_iter = true; + return Break(()); } } else { - walk_expr(self, e); + walk_expr(self, e)?; } + Continue(()) } } - let mut v = V { - cx, - iter_expr, - uses_iter: false, - }; - v.visit_expr(container); - v.uses_iter + let mut v = V { cx, iter_expr }; + v.visit_expr(container).is_break() } #[expect(clippy::too_many_lines)] @@ -246,35 +241,36 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & iter_expr: &'b IterExpr, loop_id: HirId, after_loop: bool, - used_iter: bool, } impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> { type NestedFilter = OnlyBodies; + type BreakTy = (); + fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if self.used_iter { - return; - } + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { if self.after_loop { if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { - self.used_iter = true; + return Break(()); } else if let (e, true) = skip_fields_and_path(e) { if let Some(e) = e { - self.visit_expr(e); + self.visit_expr(e)?; } } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind { - self.used_iter = is_res_used(self.cx, self.iter_expr.path, id); + if is_res_used(self.cx, self.iter_expr.path, id) { + return Break(()); + } } else { - walk_expr(self, e); + walk_expr(self, e)?; } } else if self.loop_id == e.hir_id { self.after_loop = true; } else { - walk_expr(self, e); + walk_expr(self, e)?; } + Continue(()) } } @@ -285,15 +281,16 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & loop_id: HirId, after_loop: bool, found_local: bool, - used_after: bool, } impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { type NestedFilter = OnlyBodies; + type BreakTy = (); + fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_local(&mut self, l: &'tcx Local<'_>) { + fn visit_local(&mut self, l: &'tcx Local<'_>) -> ControlFlow<()> { if !self.after_loop { l.pat.each_binding_or_first(&mut |_, id, _, _| { if id == self.local_id { @@ -302,31 +299,33 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & }); } if let Some(e) = l.init { - self.visit_expr(e); + self.visit_expr(e) + } else { + Continue(()) } } - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if self.used_after { - return; - } + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { if self.after_loop { if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { - self.used_after = true; + return Break(()); } else if let (e, true) = skip_fields_and_path(e) { if let Some(e) = e { - self.visit_expr(e); + self.visit_expr(e)?; } } else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind { - self.used_after = is_res_used(self.cx, self.iter_expr.path, id); + if is_res_used(self.cx, self.iter_expr.path, id) { + return Break(()); + } } else { - walk_expr(self, e); + walk_expr(self, e)?; } } else if e.hir_id == self.loop_id { self.after_loop = true; } else { - walk_expr(self, e); + walk_expr(self, e)?; } + Continue(()) } } @@ -341,19 +340,17 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: & loop_id: loop_expr.hir_id, after_loop: false, found_local: false, - used_after: false, }; - v.visit_expr(e); - v.used_after || !v.found_local + let used_after = v.visit_expr(e).is_break(); + used_after || !v.found_local } else { let mut v = AfterLoopVisitor { cx, iter_expr, loop_id: loop_expr.hir_id, after_loop: false, - used_iter: false, }; - v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value); - v.used_iter + v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value) + .is_break() } } diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 98e698c6c2a0c..db01bbbf198e0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -4,7 +4,6 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::peel_blocks; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::visitors::{Descend, Visitable}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -16,7 +15,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; use rustc_span::Span; use serde::Deserialize; -use std::ops::ControlFlow; +use std::ops::ControlFlow::{self, Break, Continue}; declare_clippy_lint! { /// ### What it does @@ -174,50 +173,36 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: fn expr_diverges(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { struct V<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, - res: ControlFlow<(), Descend>, } impl<'tcx> Visitor<'tcx> for V<'_, '_> { - fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { - fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { - if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) { - return ty.is_never(); - } - false - } + type BreakTy = (); - if self.res.is_break() { - return; + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> ControlFlow<()> { + fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { + cx.typeck_results().expr_ty_opt(expr).is_some_and(|ty| ty.is_never()) } // We can't just call is_never on expr and be done, because the type system // sometimes coerces the ! type to something different before we can get // our hands on it. So instead, we do a manual search. We do fall back to // is_never in some places when there is no better alternative. - self.res = match e.kind { - ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()), + match e.kind { + ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => return Break(()), ExprKind::Call(call, _) => { if is_never(self.cx, e) || is_never(self.cx, call) { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(Descend::Yes) + return Break(()); } }, ExprKind::MethodCall(..) => { if is_never(self.cx, e) { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(Descend::Yes) + return Break(()); } }, ExprKind::If(if_expr, if_then, if_else) => { let else_diverges = if_else.map_or(false, |ex| expr_diverges(self.cx, ex)); let diverges = expr_diverges(self.cx, if_expr) || (else_diverges && expr_diverges(self.cx, if_then)); - if diverges { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(Descend::No) - } + return if diverges { Break(()) } else { Continue(()) }; }, ExprKind::Match(match_expr, match_arms, _) => { let diverges = expr_diverges(self.cx, match_expr) @@ -225,47 +210,47 @@ fn expr_diverges(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(self.cx, g.body())); guard_diverges || expr_diverges(self.cx, arm.body) }); - if diverges { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(Descend::No) - } + return if diverges { Break(()) } else { Continue(()) }; }, // Don't continue into loops or labeled blocks, as they are breakable, // and we'd have to start checking labels. - ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No), + ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => return Continue(()), // Default: descend - _ => ControlFlow::Continue(Descend::Yes), + _ => {}, }; - if let ControlFlow::Continue(Descend::Yes) = self.res { - walk_expr(self, e); - } + walk_expr(self, e) } - fn visit_local(&mut self, local: &'tcx Local<'_>) { + fn visit_local(&mut self, local: &'tcx Local<'_>) -> ControlFlow<()> { // Don't visit the else block of a let/else statement as it will not make // the statement divergent even though the else block is divergent. if let Some(init) = local.init { - self.visit_expr(init); + self.visit_expr(init) + } else { + Continue(()) } } // Avoid unnecessary `walk_*` calls. - fn visit_ty(&mut self, _: &'tcx Ty<'tcx>) {} - fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {} - fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {} + fn visit_ty(&mut self, _: &'tcx Ty<'tcx>) -> ControlFlow<()> { + Continue(()) + } + fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> ControlFlow<()> { + Continue(()) + } + fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> ControlFlow<()> { + Continue(()) + } // Avoid monomorphising all `visit_*` functions. - fn visit_nested_item(&mut self, _: ItemId) {} + fn visit_nested_item(&mut self, _: ItemId) -> ControlFlow<()> { + Continue(()) + } } - let mut v = V { - cx, - res: ControlFlow::Continue(Descend::Yes), - }; - expr.visit(&mut v); - v.res.is_break() + let mut v = V { cx }; + v.visit_expr(expr).is_break() } fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: bool) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index c795c1d9a16c3..1a66c2f137ca5 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -4,6 +4,7 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; use clippy_utils::{eq_expr_value, higher, match_def_path, paths}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::def::Res; @@ -201,7 +202,7 @@ fn find_stripping<'tcx>( } impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> ControlFlow { if_chain! { if is_ref_str(self.cx, ex); let unref = peel_ref(ex); @@ -214,7 +215,7 @@ fn find_stripping<'tcx>( (StripKind::Prefix, Some(start), None) => { if eq_pattern_length(self.cx, self.pattern, start) { self.results.push(ex.span); - return; + return Continue(()); } }, (StripKind::Suffix, None, Some(end)) => { @@ -226,7 +227,7 @@ fn find_stripping<'tcx>( if eq_pattern_length(self.cx, self.pattern, right); then { self.results.push(ex.span); - return; + return Continue(()); } } }, @@ -235,7 +236,7 @@ fn find_stripping<'tcx>( } } - walk_expr(self, ex); + walk_expr(self, ex) } } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 675a85ae5553a..fe425d55276bc 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::ty::is_type_lang_item; +use core::ops::ControlFlow::{self, Continue}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -46,9 +47,11 @@ struct MatchExprVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> ControlFlow { match ex.kind { - ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {}, + ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => { + Continue(()) + }, _ => walk_expr(self, ex), } } diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index b33a247817292..228c7292651d3 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -2,6 +2,7 @@ use crate::FxHashSet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{indent_of, snippet}; use clippy_utils::{get_attr, is_lint_allowed}; +use core::ops::ControlFlow::{self, Continue}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; @@ -279,14 +280,14 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> ControlFlow { if !self.is_chain_end && self .sig_drop_checker .has_sig_drop_attr(self.cx, self.sig_drop_checker.get_type(ex)) { self.has_significant_drop = true; - return; + return Continue(()); } self.is_chain_end = false; @@ -331,7 +332,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { ExprKind::Index(..) | ExprKind::Ret(..) | ExprKind::Repeat(..) | - ExprKind::Yield(..) => walk_expr(self, ex), + ExprKind::Yield(..) => {walk_expr(self, ex);}, ExprKind::AddrOf(_, _, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) | @@ -349,7 +350,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { ExprKind::Path(_) | ExprKind::Struct(_, _, _) | ExprKind::Type(_, _) => { - return; + return Continue(()); } } @@ -360,6 +361,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { if self.has_significant_drop && !self.special_handling_for_binary_op { self.try_setting_current_suggestion(ex, false); } + Continue(()) } } @@ -386,14 +388,15 @@ fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<' } impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow { if self .sig_drop_checker .has_sig_drop_attr(self.sig_drop_checker.cx, self.sig_drop_checker.get_type(ex)) { self.found_sig_drop_spans.insert(ex.span); - return; + Continue(()) + } else { + walk_expr(self, ex) } - walk_expr(self, ex); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 0b0c6adc5045a..25cb979a0ff36 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -8,6 +8,7 @@ use clippy_utils::{ can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id, CaptureKind, }; +use core::ops::ControlFlow::{self, Continue}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; @@ -238,7 +239,7 @@ struct IterFunctionVisitor<'a, 'tcx> { target: HirId, } impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { - fn visit_block(&mut self, block: &'tcx Block<'tcx>) { + fn visit_block(&mut self, block: &'tcx Block<'tcx>) -> ControlFlow { for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) { if check_loop_kind(expr).is_some() { continue; @@ -254,15 +255,16 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { self.visit_block_expr(expr, None); } } + Continue(()) } - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { // Check function calls on our collection if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind { if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); self.visit_expr(recv); - return; + return Continue(()); } if path_to_local_id(recv, self.target) { @@ -300,7 +302,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { }, } } - return; + return Continue(()); } if let Some(hir_id) = path_to_local(recv) { @@ -326,6 +328,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { } else { walk_expr(self, expr); } + Continue(()) } } @@ -382,11 +385,12 @@ struct UsedCountVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { if path_to_local_id(expr, self.id) { self.count += 1; + Continue(()) } else { - walk_expr(self, expr); + walk_expr(self, expr) } } diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs index 4c6328481e438..1170377c95ab3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; +use core::ops::ControlFlow::{self, Break}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_path, Visitor}; @@ -38,11 +39,9 @@ pub(super) fn check<'tcx>( let mut map_expr_visitor = MapExprVisitor { cx, identifiers: unwrap_visitor.identifiers, - found_identifier: false, }; - map_expr_visitor.visit_expr(map_arg); - if map_expr_visitor.found_identifier { + if map_expr_visitor.visit_expr(map_arg).is_break() { return; } } @@ -97,9 +96,9 @@ struct UnwrapVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> { type NestedFilter = nested_filter::All; - fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> ControlFlow { self.identifiers.insert(ident(path)); - walk_path(self, path); + walk_path(self, path) } fn nested_visit_map(&mut self) -> Self::Map { @@ -110,18 +109,18 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> { struct MapExprVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, identifiers: FxHashSet, - found_identifier: bool, } impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> { type NestedFilter = nested_filter::All; + type BreakTy = (); - fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> ControlFlow<()> { if self.identifiers.contains(&ident(path)) { - self.found_identifier = true; - return; + Break(()) + } else { + walk_path(self, path) } - walk_path(self, path); } fn nested_visit_map(&mut self) -> Self::Map { diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index c96d69226972f..b8f42dcc595c0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -1,6 +1,7 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{get_parent_expr, path_to_local_id, usage}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; @@ -130,14 +131,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { self.cx.tcx.hir() } - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> ControlFlow { walk_expr(self, expr); if self.is_binding(expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { match parent.kind { ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) => { self.addr_of_exprs.push(parent); - return; + return Continue(()); }, ExprKind::MethodCall(.., args, _) => { if_chain! { @@ -147,7 +148,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder(); if matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Not)); then { - return; + return Continue(()); } } }, @@ -156,6 +157,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { } self.clone_or_copy_needed = true; } + Continue(()) } } 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 f0be7771bb1a6..acbcb4b8d9f40 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,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_note}; use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; @@ -125,7 +126,9 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { self.maybe_walk_expr(arm.body); } }, - _ => walk_expr(self, e), + _ => { + walk_expr(self, e); + }, } } fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { @@ -134,7 +137,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow { match e.kind { ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e), ExprKind::Call(func, _) => { @@ -162,9 +165,11 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { }, } self.maybe_walk_expr(e); + Continue(()) } - fn visit_block(&mut self, _: &'tcx Block<'_>) { + fn visit_block(&mut self, _: &'tcx Block<'_>) -> ControlFlow { // don't continue over blocks, LateLintPass already does that + Continue(()) } } @@ -292,9 +297,9 @@ struct ReadVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { if expr.hir_id == self.last_expr.hir_id { - return; + return Continue(()); } if path_to_local_id(expr, self.var) { @@ -327,12 +332,12 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { // // TODO: fix this ExprKind::AddrOf(_, _, _) => { - return; + return Continue(()); } _ => {} } - walk_expr(self, expr); + walk_expr(self, expr) } } diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index 64d8333a093b1..8eb73ed3d6028 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::higher; +use core::ops::ControlFlow::{self, Continue}; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -46,9 +47,9 @@ pub struct MutVisitor<'a, 'tcx> { } impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) -> ControlFlow { if in_external_macro(self.cx.sess(), expr.span) { - return; + return Continue(()); } if let Some(higher::ForLoop { arg, body, .. }) = higher::ForLoop::hir(expr) { @@ -79,11 +80,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { } } } + Continue(()) } - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) -> ControlFlow { if in_external_macro(self.cx.sess(), ty.span) { - return; + return Continue(()); } if let hir::TyKind::Ref( @@ -111,6 +113,6 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { } } - intravisit::walk_ty(self, ty); + intravisit::walk_ty(self, ty) } } diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs index d8647a9910585..2b537c813f020 100644 --- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs +++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node}; +use core::ops::ControlFlow::{self, Break, Continue}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability}; use rustc_lint::{LateContext, LateLintPass}; @@ -50,8 +51,9 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) else { return }; for arg in [lhs, rhs] { let mut visitor = MutArgVisitor::new(cx); - visitor.visit_expr(arg); - if let Some(span) = visitor.expr_span() { + if visitor.visit_expr(arg).is_break() + && let Some(span) = visitor.expr_span + { span_lint( cx, DEBUG_ASSERT_WITH_MUT_CALL, @@ -66,53 +68,36 @@ impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall { struct MutArgVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, expr_span: Option, - found: bool, } impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> { fn new(cx: &'a LateContext<'tcx>) -> Self { - Self { - cx, - expr_span: None, - found: false, - } - } - - fn expr_span(&self) -> Option { - if self.found { self.expr_span } else { None } + Self { cx, expr_span: None } } } impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow<()> { match expr.kind { - ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => { - self.found = true; - return; - }, - ExprKind::If(..) => { - self.found = true; - return; - }, + ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) | ExprKind::If(..) => return Break(()), ExprKind::Path(_) => { if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) { if adj .iter() .any(|a| matches!(a.target.kind(), ty::Ref(_, _, Mutability::Mut))) { - self.found = true; - return; + return Break(()); } } }, // Don't check await desugars - ExprKind::Match(_, _, MatchSource::AwaitDesugar) => return, - _ if !self.found => self.expr_span = Some(expr.span), - _ => return, + ExprKind::Match(_, _, MatchSource::AwaitDesugar) => return Continue(()), + _ => self.expr_span = Some(expr.span), } - walk_expr(self, expr); + walk_expr(self, expr) } fn nested_visit_map(&mut self) -> Self::Map { diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index c3b633fd6a038..5a36a45f986c4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -1,3 +1,4 @@ +use core::ops::ControlFlow::{self, Continue}; use rustc_errors::Applicability; use rustc_hir::{ intravisit::{walk_expr, Visitor}, @@ -134,7 +135,7 @@ struct RetCollector { } impl<'tcx> Visitor<'tcx> for RetCollector { - fn visit_expr(&mut self, expr: &Expr<'_>) { + fn visit_expr(&mut self, expr: &Expr<'_>) -> ControlFlow { match expr.kind { ExprKind::Ret(..) => { if self.loop_depth > 0 && !self.ret_in_loop { @@ -148,12 +149,12 @@ impl<'tcx> Visitor<'tcx> for RetCollector { self.loop_depth += 1; walk_expr(self, expr); self.loop_depth -= 1; - return; + return Continue(()); }, _ => {}, } - walk_expr(self, expr); + walk_expr(self, expr) } } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index fc550936165e6..9b140a0c9d8cc 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -28,6 +28,7 @@ use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::fmt; use std::iter; +use std::ops::ControlFlow::{self, Break, Continue}; declare_clippy_lint! { /// ### What it does @@ -550,17 +551,16 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: } impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_anon_const(&mut self, _: &'tcx AnonConst) {} - - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if self.skip_count == self.args.len() { - return; - } + fn visit_anon_const(&mut self, _: &'tcx AnonConst) -> ControlFlow<()> { + Continue(()) + } + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { // Check if this is local we care about let Some(&args_idx) = path_to_local(e).and_then(|id| self.bindings.get(&id)) else { return walk_expr(self, e); @@ -571,9 +571,13 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: // Helper function to handle early returns. let mut set_skip_flag = || { if !result.skip { + result.skip = true; self.skip_count += 1; + if self.skip_count == self.args.len() { + return Break(()); + } } - result.skip = true; + Continue(()) }; match get_expr_use_or_unification_node(self.cx.tcx, e) { @@ -583,7 +587,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind { self.bindings.insert(id, args_idx); } else { - set_skip_flag(); + set_skip_flag()?; } }, Some((Node::Expr(e), child_id)) => match e.kind { @@ -598,7 +602,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: } }) { // Passed to a function taking the non-dereferenced type. - set_skip_flag(); + set_skip_flag()?; } }, ExprKind::MethodCall(name, self_arg, expr_args, _) => { @@ -615,13 +619,12 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: self_span: self_arg.span, replacement, }); - return; + return Continue(()); } } let Some(id) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) else { - set_skip_flag(); - return; + return set_skip_flag(); }; match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i] @@ -629,25 +632,26 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: .kind() { ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => { - set_skip_flag(); + set_skip_flag()?; }, ty::Param(_) => { - set_skip_flag(); + set_skip_flag()?; }, // If the types match check for methods which exist on both types. e.g. `Vec::len` and // `slice::len` ty::Adt(def, _) if def.did() == args.ty_did => { - set_skip_flag(); + set_skip_flag()?; }, _ => (), } }, // Indexing is fine for currently supported types. ExprKind::Index(e, _) if e.hir_id == child_id => (), - _ => set_skip_flag(), + _ => set_skip_flag()?, }, - _ => set_skip_flag(), + _ => set_skip_flag()?, } + Continue(()) } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 2a42e73488f19..8766fb1f6474b 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::sugg::Sugg; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit as ast_visit; @@ -118,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow { if_chain! { if let hir::ExprKind::Call(closure, _) = expr.kind; if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind; @@ -128,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { self.count += 1; } } - hir_visit::walk_expr(self, expr); + hir_visit::walk_expr(self, expr) } fn nested_visit_map(&mut self) -> Self::Map { diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs index e2d90edec5a4c..9a9fc399f0b8b 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -4,6 +4,7 @@ use clippy_utils::{ get_attr, source::{indent_of, snippet}, }; +use core::ops::ControlFlow::{self, Break, Continue}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::{ self as hir, @@ -119,8 +120,7 @@ impl<'tcx> SignificantDropTightening<'tcx> { cb: impl Fn(&mut SigDropAuxParams), ) { let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types); - sig_drop_finder.visit_expr(expr); - if sig_drop_finder.has_sig_drop { + if sig_drop_finder.visit_expr(expr).is_break() { cb(sdap); if sdap.number_of_stmts > 0 { sdap.last_use_stmt_idx = idx; @@ -348,7 +348,6 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { /// Performs recursive calls to find any inner type marked with `#[has_significant_drop]`. struct SigDropFinder<'cx, 'sdt, 'tcx> { cx: &'cx LateContext<'tcx>, - has_sig_drop: bool, sig_drop_checker: SigDropChecker<'cx, 'sdt, 'tcx>, } @@ -356,26 +355,23 @@ impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> { fn new(cx: &'cx LateContext<'tcx>, seen_types: &'sdt mut FxHashSet>) -> Self { Self { cx, - has_sig_drop: false, sig_drop_checker: SigDropChecker::new(cx, seen_types), } } } impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'_>) { + type BreakTy = (); + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'_>) -> ControlFlow<()> { if self .sig_drop_checker .has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex)) { - self.has_sig_drop = true; - return; + return Break(()); } match ex.kind { - hir::ExprKind::MethodCall(_, expr, ..) => { - self.visit_expr(expr); - }, + hir::ExprKind::MethodCall(_, expr, ..) => self.visit_expr(expr), hir::ExprKind::Array(..) | hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) @@ -390,10 +386,8 @@ impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> { | hir::ExprKind::Ret(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Unary(..) - | hir::ExprKind::Yield(..) => { - walk_expr(self, ex); - }, - _ => {}, + | hir::ExprKind::Yield(..) => walk_expr(self, ex), + _ => Continue(()), } } } diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index a2109038a0578..5fcf21bfe4850 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -4,6 +4,7 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq, }; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor}; @@ -266,7 +267,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { - fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) { + fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) -> ControlFlow { if self.initialization_found { match stmt.kind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => { @@ -280,9 +281,10 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { } else { walk_stmt(self, stmt); } + Continue(()) } - fn visit_block(&mut self, block: &'tcx Block<'_>) { + fn visit_block(&mut self, block: &'tcx Block<'_>) -> ControlFlow { if self.initialization_found { if let Some(s) = block.stmts.get(0) { self.visit_stmt(s); @@ -292,14 +294,15 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { } else { walk_block(self, block); } + Continue(()) } - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { // Skip all the expressions previous to the vector initialization if self.vec_alloc.allocation_expr.hir_id == expr.hir_id { self.initialization_found = true; } - walk_expr(self, expr); + walk_expr(self, expr) } } diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs index 0aa50c99c1690..1d98731f1af1c 100644 --- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint; +use core::ops::ControlFlow::{self, Continue}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor}; use rustc_hir::{GenericParamKind, TyKind}; @@ -36,12 +37,12 @@ struct TypeComplexityVisitor { } impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { - fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { + fn visit_infer(&mut self, inf: &'tcx hir::InferArg) -> ControlFlow { self.score += 1; - walk_inf(self, inf); + walk_inf(self, inf) } - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) -> ControlFlow { let (add_score, sub_nest) = match ty.kind { // _, &x and *x have only small overhead; don't mess with nesting level TyKind::Infer | TyKind::Ptr(..) | TyKind::Ref(..) => (1, 0), @@ -74,5 +75,6 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor { self.nest += sub_nest; walk_ty(self, ty); self.nest -= sub_nest; + Continue(()) } } diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index 55651a28be924..4afb42a73e2c3 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; +use core::ops::ControlFlow::{self, Break}; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; @@ -41,17 +42,18 @@ declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]); struct AsyncFnVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - found_await: bool, } impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow<()> { if let ExprKind::Yield(_, YieldSource::Await { .. }) = ex.kind { - self.found_await = true; + Break(()) + } else { + walk_expr(self, ex) } - walk_expr(self, ex); } fn nested_visit_map(&mut self) -> Self::Map { @@ -70,9 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { def_id: LocalDefId, ) { if !span.from_expansion() && fn_kind.asyncness().is_async() { - let mut visitor = AsyncFnVisitor { cx, found_await: false }; - walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id); - if !visitor.found_await { + let mut visitor = AsyncFnVisitor { cx }; + if walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id).is_continue() { span_lint_and_help( cx, UNUSED_ASYNC, diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs index 4ee16d9a5e4ad..5514ffc3cbc77 100644 --- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs +++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable}; use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators}; +use core::ops::ControlFlow::{self, Break, Continue}; use rustc_ast::Mutability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; @@ -64,21 +65,17 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) && match_type(cx, ty, &paths::PEEKABLE) { - let mut vis = PeekableVisitor::new(cx, binding); - if idx + 1 == block.stmts.len() && block.expr.is_none() { return; } - for stmt in &block.stmts[idx..] { - vis.visit_stmt(stmt); - } - - if let Some(expr) = block.expr { - vis.visit_expr(expr); + let mut vis = PeekableVisitor::new(cx, binding); + let mut found = block.stmts.iter().any(|s| vis.visit_stmt(s).is_break()); + if !found && let Some(e) = block.expr { + found = vis.visit_expr(e).is_break(); } - if !vis.found_peek_call { + if !found { span_lint_and_help( cx, UNUSED_PEEKABLE, @@ -96,31 +93,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { struct PeekableVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, expected_hir_id: HirId, - found_peek_call: bool, } impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> { fn new(cx: &'a LateContext<'tcx>, expected_hir_id: HirId) -> Self { - Self { - cx, - expected_hir_id, - found_peek_call: false, - } + Self { cx, expected_hir_id } } } impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { type NestedFilter = OnlyBodies; + type BreakTy = (); fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if self.found_peek_call { - return; - } - + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> ControlFlow<()> { if path_to_local_id(ex, self.expected_hir_id) { for (_, node) in self.cx.tcx.hir().parent_iter(ex.hir_id) { match node { @@ -139,14 +128,14 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { && func_did == into_iter_did { // Probably a for loop desugar, stop searching - return; + return Continue(()); } if args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) { - self.found_peek_call = true; + return Break(()); } - return; + return Continue(()); }, // Catch anything taking a Peekable mutably ExprKind::MethodCall( @@ -164,16 +153,14 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq") && arg_is_mut_peekable(self.cx, self_arg) { - self.found_peek_call = true; - return; + return Break(()); } // foo.some_method() excluding Iterator methods if remaining_args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) && !is_trait_method(self.cx, expr, sym::Iterator) { - self.found_peek_call = true; - return; + return Break(()); } // foo.by_ref(), keep checking for `peek` @@ -181,41 +168,38 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { continue; } - return; + return Continue(()); }, ExprKind::AddrOf(_, Mutability::Mut, _) | ExprKind::Unary(..) | ExprKind::DropTemps(_) => { }, - ExprKind::AddrOf(_, Mutability::Not, _) => return, - _ => { - self.found_peek_call = true; - return; - }, + ExprKind::AddrOf(_, Mutability::Not, _) => return Continue(()), + _ => return Break(()), } }, Node::Local(Local { init: Some(init), .. }) => { if arg_is_mut_peekable(self.cx, init) { - self.found_peek_call = true; + return Break(()); } - return; + return Continue(()); }, Node::Stmt(stmt) => { match stmt.kind { - StmtKind::Local(_) | StmtKind::Item(_) => self.found_peek_call = true, + StmtKind::Local(_) | StmtKind::Item(_) => return Break(()), StmtKind::Expr(_) | StmtKind::Semi(_) => {}, } - return; + return Continue(()); }, Node::Block(_) | Node::ExprField(_) => {}, _ => { - return; + return Continue(()); }, } } } - walk_expr(self, ex); + walk_expr(self, ex) } } diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 377d3fb6f4e1c..003ffc2a6f2fe 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{path_to_local, usage::is_potentially_mutated}; +use core::ops::ControlFlow::{self, Continue}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; @@ -218,10 +219,10 @@ impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> ControlFlow { // Shouldn't lint when `expr` is in macro. if in_external_macro(self.cx.tcx.sess, expr.span) { - return; + return Continue(()); } if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) { walk_expr(self, cond); @@ -296,6 +297,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { } walk_expr(self, expr); } + Continue(()) } fn nested_visit_map(&mut self) -> Self::Map { diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index e7c54000684ab..d655638d4a391 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::same_type_and_consts; +use core::ops::ControlFlow; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -270,15 +271,15 @@ struct SkipTyCollector { } impl<'tcx> Visitor<'tcx> for SkipTyCollector { - fn visit_infer(&mut self, inf: &hir::InferArg) { + fn visit_infer(&mut self, inf: &hir::InferArg) -> ControlFlow { self.types_to_skip.push(inf.hir_id); - walk_inf(self, inf); + walk_inf(self, inf) } - fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) { + fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) -> ControlFlow { self.types_to_skip.push(hir_ty.hir_id); - walk_ty(self, hir_ty); + walk_ty(self, hir_ty) } } diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index ee2f816f181ba..387fd95ef0f0a 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -18,7 +18,10 @@ use rustc_lint::LateContext; use rustc_middle::ty::{self, PredicateKind}; use rustc_span::{sym, Symbol}; use std::cmp; -use std::ops; +use std::ops::{ + self, + ControlFlow::{self, Break, Continue}, +}; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] enum EagernessSuggestion { @@ -109,11 +112,9 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS } impl<'cx, 'tcx> Visitor<'tcx> for V<'cx, 'tcx> { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - use EagernessSuggestion::{ForceNoChange, Lazy, NoChange}; - if self.eagerness == ForceNoChange { - return; - } + type BreakTy = (); + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { + use EagernessSuggestion::{Lazy, NoChange}; match e.kind { ExprKind::Call( &Expr { @@ -125,15 +126,14 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS ) => match self.cx.qpath_res(path, hir_id) { res @ (Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_)) => { if res_has_significant_drop(res, self.cx, e) { - self.eagerness = ForceNoChange; - return; + return Break(()); } }, Res::Def(_, id) if self.cx.tcx.is_promotable_const_fn(id) => (), // No need to walk the arguments here, `is_const_evaluatable` already did Res::Def(..) if is_const_evaluatable(self.cx, e) => { self.eagerness |= NoChange; - return; + return Continue(()); }, Res::Def(_, id) => match path { QPath::Resolved(_, p) => { @@ -150,12 +150,11 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS // No need to walk the arguments here, `is_const_evaluatable` already did ExprKind::MethodCall(..) if is_const_evaluatable(self.cx, e) => { self.eagerness |= NoChange; - return; + return Continue(()); }, ExprKind::Path(ref path) => { if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) { - self.eagerness = ForceNoChange; - return; + return Break(()); } }, ExprKind::MethodCall(name, ..) => { @@ -193,10 +192,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS | ExprKind::Ret(_) | ExprKind::InlineAsm(_) | ExprKind::Yield(..) - | ExprKind::Err(_) => { - self.eagerness = ForceNoChange; - return; - }, + | ExprKind::Err(_) => return Break(()), // Memory allocation, custom operator, loop, or call to an unknown function ExprKind::Box(_) @@ -227,7 +223,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS // TODO: Actually check if either of these are true here. ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Block(..) => self.eagerness |= NoChange, } - walk_expr(self, e); + walk_expr(self, e) } } @@ -235,8 +231,10 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS cx, eagerness: EagernessSuggestion::Eager, }; - v.visit_expr(e); - v.eagerness + match v.visit_expr(e) { + Continue(()) => v.eagerness, + Break(()) => EagernessSuggestion::ForceNoChange, + } } /// Whether the given expression should be changed to evaluate eagerly diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index f02f8ecb43d72..e3edba97272ae 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,5 +1,6 @@ #![feature(array_chunks)] #![feature(box_patterns)] +#![feature(control_flow_enum)] #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] @@ -71,7 +72,7 @@ pub use self::hir_utils::{ both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; -use core::ops::ControlFlow; +use core::ops::ControlFlow::{self, Break, Continue}; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use std::sync::OnceLock; @@ -1099,18 +1100,14 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' loops: Vec, /// Local variables created in the expression. These don't need to be captured. locals: HirIdSet, - /// Whether this expression can be turned into a closure. - allow_closure: bool, /// Locals which need to be captured, and whether they need to be by value, reference, or /// mutable reference. captures: HirIdMap, } impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if !self.allow_closure { - return; - } + type BreakTy = (); + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { match e.kind { ExprKind::Path(QPath::Resolved(None, &Path { res: Res::Local(l), .. })) => { if !self.locals.contains(&l) { @@ -1144,32 +1141,35 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' }, ExprKind::Loop(b, ..) => { self.loops.push(e.hir_id); - self.visit_block(b); + self.visit_block(b)?; self.loops.pop(); }, _ => { - self.allow_closure &= can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals); - walk_expr(self, e); + if !can_move_expr_to_closure_no_visit(self.cx, e, &self.loops, &self.locals) { + return Break(()); + } + walk_expr(self, e)?; }, } + Continue(()) } - fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) { + fn visit_pat(&mut self, p: &'tcx Pat<'tcx>) -> ControlFlow<()> { p.each_binding_or_first(&mut |_, id, _, _| { self.locals.insert(id); }); + Continue(()) } } let mut v = V { cx, - allow_closure: true, loops: Vec::new(), locals: HirIdSet::default(), captures: HirIdMap::default(), }; - v.visit_expr(expr); - v.allow_closure.then_some(v.captures) + let allow_closure = v.visit_expr(expr).is_continue(); + allow_closure.then_some(v.captures) } /// Arguments of a method: the receiver and all the additional arguments. @@ -1259,16 +1259,14 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { pub struct ContainsName<'a, 'tcx> { pub cx: &'a LateContext<'tcx>, pub name: Symbol, - pub result: bool, } impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); - fn visit_name(&mut self, name: Symbol) { - if self.name == name { - self.result = true; - } + fn visit_name(&mut self, name: Symbol) -> ControlFlow<()> { + if self.name == name { Break(()) } else { Continue(()) } } fn nested_visit_map(&mut self) -> Self::Map { @@ -1278,13 +1276,8 @@ impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> { /// Checks if an `Expr` contains a certain name. pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool { - let mut cn = ContainsName { - name, - result: false, - cx, - }; - cn.visit_expr(expr); - cn.result + let mut cn = ContainsName { name, cx }; + cn.visit_expr(expr).is_break() } /// Returns `true` if `expr` contains a return expression diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index be6133d320241..13ba2b48e3826 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -16,7 +16,7 @@ use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol}; use std::iter::{once, zip}; -use std::ops::ControlFlow; +use std::ops::ControlFlow::{self, Continue}; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ sym::assert_eq_macro, @@ -490,7 +490,7 @@ struct ParamPosition { } impl<'tcx> Visitor<'tcx> for ParamPosition { - fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) { + fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) -> ControlFlow { match field.ident.name { sym::position => { if let ExprKind::Lit(lit) = &field.expr.kind @@ -505,8 +505,11 @@ impl<'tcx> Visitor<'tcx> for ParamPosition { sym::width => { self.width = parse_count(field.expr); }, - _ => walk_expr(self, field.expr), + _ => { + walk_expr(self, field.expr); + }, } + Continue(()) } } diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index ab3976a13bdbb..d1e3ae2b1981d 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -1,6 +1,6 @@ use crate as utils; use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend}; -use core::ops::ControlFlow; +use core::ops::ControlFlow::{self, Break, Continue}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirIdSet; @@ -95,44 +95,42 @@ impl<'tcx> ParamBindingIdCollector { } } impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector { - fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { + fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) -> ControlFlow { if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind { self.binding_hir_ids.push(hir_id); } - intravisit::walk_pat(self, pat); + intravisit::walk_pat(self, pat) } } pub struct BindingUsageFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, binding_ids: Vec, - usage_found: bool, } impl<'a, 'tcx> BindingUsageFinder<'a, 'tcx> { pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -> bool { let mut finder = BindingUsageFinder { cx, binding_ids: ParamBindingIdCollector::collect_binding_hir_ids(body), - usage_found: false, }; - finder.visit_body(body); - finder.usage_found + finder.visit_body(body).is_break() } } impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if !self.usage_found { - intravisit::walk_expr(self, expr); - } + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow<()> { + intravisit::walk_expr(self, expr) } - fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) { - if let hir::def::Res::Local(id) = path.res { - if self.binding_ids.contains(&id) { - self.usage_found = true; - } + fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) -> ControlFlow<()> { + if let hir::def::Res::Local(id) = path.res + && self.binding_ids.contains(&id) + { + Break(()) + } else { + Continue(()) } } diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index d27a20bd4dfa7..21c2aefdad5d4 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -1,6 +1,6 @@ use crate::ty::needs_ordered_drop; use crate::{get_enclosing_block, path_to_local_id}; -use core::ops::ControlFlow; +use core::ops::ControlFlow::{self, Break, Continue}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor}; @@ -17,13 +17,13 @@ use rustc_span::Span; mod internal { /// Trait for visitor functions to control whether or not to descend to child nodes. Implemented /// for only two types. `()` always descends. `Descend` allows controlled descent. - pub trait Continue { + pub trait MaybeDescend { fn descend(&self) -> bool; } } -use internal::Continue; +use internal::MaybeDescend; -impl Continue for () { +impl MaybeDescend for () { fn descend(&self) -> bool { true } @@ -41,7 +41,7 @@ impl From for Descend { if from { Self::Yes } else { Self::No } } } -impl Continue for Descend { +impl MaybeDescend for Descend { fn descend(&self) -> bool { matches!(self, Self::Yes) } @@ -50,13 +50,13 @@ impl Continue for Descend { /// A type which can be visited. pub trait Visitable<'tcx> { /// Calls the corresponding `visit_*` function on the visitor. - fn visit>(self, visitor: &mut V); + fn visit>(self, visitor: &mut V) -> ControlFlow; } macro_rules! visitable_ref { ($t:ident, $f:ident) => { impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> { - fn visit>(self, visitor: &mut V) { - visitor.$f(self); + fn visit>(self, visitor: &mut V) -> ControlFlow { + visitor.$f(self) } } }; @@ -69,92 +69,98 @@ visitable_ref!(Stmt, visit_stmt); /// Calls the given function once for each expression contained. This does not enter any bodies or /// nested items. -pub fn for_each_expr<'tcx, B, C: Continue>( +pub fn for_each_expr<'tcx, B, C: MaybeDescend>( node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> Option { - struct V { + struct V { f: F, - res: Option, } - impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V { - fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { - if self.res.is_some() { - return; - } - match (self.f)(e) { - ControlFlow::Continue(c) if c.descend() => walk_expr(self, e), - ControlFlow::Break(b) => self.res = Some(b), - ControlFlow::Continue(_) => (), + impl<'tcx, B, C: MaybeDescend, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V { + type BreakTy = B; + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> ControlFlow { + if (self.f)(e)?.descend() { + walk_expr(self, e) + } else { + Continue(()) } } // Avoid unnecessary `walk_*` calls. - fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {} - fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {} - fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {} + fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> ControlFlow { + Continue(()) + } + fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> ControlFlow { + Continue(()) + } + fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> ControlFlow { + Continue(()) + } // Avoid monomorphising all `visit_*` functions. - fn visit_nested_item(&mut self, _: ItemId) {} + fn visit_nested_item(&mut self, _: ItemId) -> ControlFlow { + Continue(()) + } } - let mut v = V { f, res: None }; - node.visit(&mut v); - v.res + let mut v = V { f }; + node.visit(&mut v).break_value() } /// Calls the given function once for each expression contained. This will enter bodies, but not /// nested items. -pub fn for_each_expr_with_closures<'tcx, B, C: Continue>( +pub fn for_each_expr_with_closures<'tcx, B, C: MaybeDescend>( cx: &LateContext<'tcx>, node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> Option { - struct V<'tcx, B, F> { + struct V<'tcx, F> { tcx: TyCtxt<'tcx>, f: F, - res: Option, } - impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V<'tcx, B, F> { + impl<'tcx, B, C: MaybeDescend, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow> Visitor<'tcx> for V<'tcx, F> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = B; fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() } - fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { - if self.res.is_some() { - return; - } - match (self.f)(e) { - ControlFlow::Continue(c) if c.descend() => walk_expr(self, e), - ControlFlow::Break(b) => self.res = Some(b), - ControlFlow::Continue(_) => (), + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> ControlFlow { + if (self.f)(e)?.descend() { + walk_expr(self, e) + } else { + Continue(()) } } // Only walk closures - fn visit_anon_const(&mut self, _: &'tcx AnonConst) {} + fn visit_anon_const(&mut self, _: &'tcx AnonConst) -> ControlFlow { + Continue(()) + } // Avoid unnecessary `walk_*` calls. - fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {} - fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {} - fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {} + fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) -> ControlFlow { + Continue(()) + } + fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) -> ControlFlow { + Continue(()) + } + fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) -> ControlFlow { + Continue(()) + } // Avoid monomorphising all `visit_*` functions. - fn visit_nested_item(&mut self, _: ItemId) {} + fn visit_nested_item(&mut self, _: ItemId) -> ControlFlow { + Continue(()) + } } - let mut v = V { - tcx: cx.tcx, - f, - res: None, - }; - node.visit(&mut v); - v.res + let mut v = V { tcx: cx.tcx, f }; + node.visit(&mut v).break_value() } /// returns `true` if expr contains match expr desugared from try fn contains_try(expr: &hir::Expr<'_>) -> bool { for_each_expr(expr, |e| { if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar)) { - ControlFlow::Break(()) + Break(()) } else { - ControlFlow::Continue(()) + Continue(()) } }) .is_some() @@ -166,7 +172,6 @@ where { struct RetFinder { in_stmt: bool, - failed: bool, cb: F, } @@ -206,14 +211,12 @@ where } impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { - fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt); + type BreakTy = (); + fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) -> ControlFlow<()> { + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) } - fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { - if self.failed { - return; - } + fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) -> ControlFlow<()> { if self.in_stmt { match expr.kind { hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), @@ -222,21 +225,24 @@ where } else { match expr.kind { hir::ExprKind::If(cond, then, else_opt) => { - self.inside_stmt(true).visit_expr(cond); - self.visit_expr(then); + self.inside_stmt(true).visit_expr(cond)?; + self.visit_expr(then)?; if let Some(el) = else_opt { - self.visit_expr(el); + self.visit_expr(el)?; } + Continue(()) }, hir::ExprKind::Match(cond, arms, _) => { - self.inside_stmt(true).visit_expr(cond); + self.inside_stmt(true).visit_expr(cond)?; for arm in arms { - self.visit_expr(arm.body); + self.visit_expr(arm.body)?; } + Continue(()) }, hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), - _ => self.failed |= !(self.cb)(expr), + _ if !(self.cb)(expr) => Break(()), + _ => Continue(()), } } } @@ -245,11 +251,9 @@ where !contains_try(expr) && { let mut ret_finder = RetFinder { in_stmt: false, - failed: false, cb: callback, }; - ret_finder.visit_expr(expr); - !ret_finder.failed + ret_finder.visit_expr(expr).is_continue() } } @@ -258,10 +262,10 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| { if let ExprKind::Path(p) = &e.kind { if cx.qpath_res(p, e.hir_id) == res { - return ControlFlow::Break(()); + return Break(()); } } - ControlFlow::Continue(()) + Continue(()) }) .is_some() } @@ -270,9 +274,9 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool { for_each_expr_with_closures(cx, visitable, |e| { if path_to_local_id(e, id) { - ControlFlow::Break(()) + Break(()) } else { - ControlFlow::Continue(()) + Continue(()) } }) .is_some() @@ -282,20 +286,17 @@ pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tc pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { struct V<'a, 'tcx> { cx: &'a LateContext<'tcx>, - is_const: bool, } impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if !self.is_const { - return; - } + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { match e.kind { - ExprKind::ConstBlock(_) => return, + ExprKind::ConstBlock(_) => return Continue(()), ExprKind::Call( &Expr { kind: ExprKind::Path(ref p), @@ -354,39 +355,30 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> | ExprKind::Tup(_) | ExprKind::Type(..) => (), - _ => { - self.is_const = false; - return; - }, + _ => return Break(()), } - walk_expr(self, e); + walk_expr(self, e) } } - let mut v = V { cx, is_const: true }; - v.visit_expr(e); - v.is_const + let mut v = V { cx }; + v.visit_expr(e).is_continue() } /// Checks if the given expression performs an unsafe operation outside of an unsafe block. pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { struct V<'a, 'tcx> { cx: &'a LateContext<'tcx>, - is_unsafe: bool, } impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_expr(&mut self, e: &'tcx Expr<'_>) { - if self.is_unsafe { - return; - } + fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> ControlFlow<()> { match e.kind { - ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_unsafe_ptr() => { - self.is_unsafe = true; - }, + ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_unsafe_ptr() => Break(()), ExprKind::MethodCall(..) if self .cx @@ -396,13 +388,13 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe }) => { - self.is_unsafe = true; + Break(()) }, ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() { ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => { - self.is_unsafe = true; + Break(()) }, - ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true, + ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => Break(()), _ => walk_expr(self, e), }, ExprKind::Path(ref p) @@ -412,56 +404,53 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { .opt_def_id() .map_or(false, |id| self.cx.tcx.is_mutable_static(id)) => { - self.is_unsafe = true; + Break(()) }, _ => walk_expr(self, e), } } - fn visit_block(&mut self, b: &'tcx Block<'_>) { + fn visit_block(&mut self, b: &'tcx Block<'_>) -> ControlFlow<()> { if !matches!(b.rules, BlockCheckMode::UnsafeBlock(_)) { - walk_block(self, b); + walk_block(self, b) + } else { + Continue(()) } } - fn visit_nested_item(&mut self, id: ItemId) { - if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind { - self.is_unsafe = i.unsafety == Unsafety::Unsafe; + fn visit_nested_item(&mut self, id: ItemId) -> ControlFlow<()> { + if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind + && i.unsafety == Unsafety::Unsafe + { + Break(()) + } else { + Continue(()) } } } - let mut v = V { cx, is_unsafe: false }; - v.visit_expr(e); - v.is_unsafe + let mut v = V { cx }; + v.visit_expr(e).is_break() } /// Checks if the given expression contains an unsafe block pub fn contains_unsafe_block<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { struct V<'cx, 'tcx> { cx: &'cx LateContext<'tcx>, - found_unsafe: bool, } impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = (); fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_block(&mut self, b: &'tcx Block<'_>) { - if self.found_unsafe { - return; - } + fn visit_block(&mut self, b: &'tcx Block<'_>) -> ControlFlow<()> { if b.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { - self.found_unsafe = true; - return; + return Break(()); } - walk_block(self, b); + walk_block(self, b) } } - let mut v = V { - cx, - found_unsafe: false, - }; - v.visit_expr(e); - v.found_unsafe + let mut v = V { cx }; + v.visit_expr(e).is_break() } /// Runs the given function for each sub-expression producing the final value consumed by the parent @@ -486,7 +475,7 @@ pub fn for_each_value_source<'tcx, B>( for arm in arms { for_each_value_source(arm.body, f)?; } - ControlFlow::Continue(()) + Continue(()) }, ExprKind::If(_, if_expr, Some(else_expr)) => { for_each_value_source(if_expr, f)?; @@ -505,36 +494,32 @@ pub fn for_each_local_use_after_expr<'tcx, B>( expr_id: HirId, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> ControlFlow { - struct V<'cx, 'tcx, F, B> { + struct V<'cx, 'tcx, F> { cx: &'cx LateContext<'tcx>, local_id: HirId, expr_id: HirId, found: bool, - res: ControlFlow, f: F, } - impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> { + impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow, B> Visitor<'tcx> for V<'cx, 'tcx, F> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = B; fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> ControlFlow { if !self.found { if e.hir_id == self.expr_id { self.found = true; + Continue(()) } else { - walk_expr(self, e); + walk_expr(self, e) } - return; - } - if self.res.is_break() { - return; - } - if path_to_local_id(e, self.local_id) { - self.res = (self.f)(e); + } else if path_to_local_id(e, self.local_id) { + (self.f)(e) } else { - walk_expr(self, e); + walk_expr(self, e) } } } @@ -545,13 +530,11 @@ pub fn for_each_local_use_after_expr<'tcx, B>( local_id, expr_id, found: false, - res: ControlFlow::Continue(()), f, }; - v.visit_block(b); - v.res + v.visit_block(b) } else { - ControlFlow::Continue(()) + Continue(()) } } @@ -667,7 +650,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::InlineAsm(_) | ExprKind::Err(_) => (), } - ControlFlow::Continue(()) + Continue(()) } helper(cx.typeck_results(), true, e, &mut f) } @@ -675,9 +658,9 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( pub fn any_temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { for_each_unconsumed_temporary(cx, e, |ty| { if needs_ordered_drop(cx, ty) { - ControlFlow::Break(()) + Break(()) } else { - ControlFlow::Continue(()) + Continue(()) } }) .is_break() @@ -690,51 +673,44 @@ pub fn for_each_local_assignment<'tcx, B>( local_id: HirId, f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow, ) -> ControlFlow { - struct V<'cx, 'tcx, F, B> { + struct V<'cx, 'tcx, F> { cx: &'cx LateContext<'tcx>, local_id: HirId, - res: ControlFlow, f: F, } - impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow, B> Visitor<'tcx> for V<'cx, 'tcx, F, B> { + impl<'cx, 'tcx, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow, B> Visitor<'tcx> for V<'cx, 'tcx, F> { type NestedFilter = nested_filter::OnlyBodies; + type BreakTy = B; fn nested_visit_map(&mut self) -> Self::Map { self.cx.tcx.hir() } - fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { + fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) -> ControlFlow { if let ExprKind::Assign(lhs, rhs, _) = e.kind - && self.res.is_continue() && path_to_local_id(lhs, self.local_id) { - self.res = (self.f)(rhs); - self.visit_expr(rhs); + (self.f)(rhs)?; + self.visit_expr(rhs) } else { - walk_expr(self, e); + walk_expr(self, e) } } } if let Some(b) = get_enclosing_block(cx, local_id) { - let mut v = V { - cx, - local_id, - res: ControlFlow::Continue(()), - f, - }; - v.visit_block(b); - v.res + let mut v = V { cx, local_id, f }; + v.visit_block(b) } else { - ControlFlow::Continue(()) + Continue(()) } } pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool { for_each_expr(expr, |e| { if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) { - ControlFlow::Break(()) + Break(()) } else { - ControlFlow::Continue(()) + Continue(()) } }) .is_some()