From 64d98f8ee037282c35007b64c2649055c56af1db Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:03 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- .../src/diagnostics/conflict_errors.rs | 304 ++++++++++++++++----- .../src/diagnostics/explain_borrow.rs | 53 ++-- .../src/diagnostics/find_all_local_uses.rs | 2 +- compiler/rustc_borrowck/src/diagnostics/mod.rs | 115 +++++--- .../rustc_borrowck/src/diagnostics/move_errors.rs | 100 ++++--- .../src/diagnostics/mutability_errors.rs | 162 +++++++---- .../src/diagnostics/outlives_suggestion.rs | 18 +- .../src/diagnostics/region_errors.rs | 233 ++++++++++------ .../rustc_borrowck/src/diagnostics/region_name.rs | 14 +- .../rustc_borrowck/src/diagnostics/var_name.rs | 25 +- 10 files changed, 677 insertions(+), 349 deletions(-) (limited to 'compiler/rustc_borrowck/src/diagnostics') diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 5e3745f17..e5a36259f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -6,6 +6,7 @@ use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, }; use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem}; use rustc_infer::infer::TyCtxtInferExt; @@ -20,7 +21,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; -use rustc_span::symbol::sym; +use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; @@ -29,6 +30,7 @@ use crate::borrowck_errors; use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead; use crate::diagnostics::find_all_local_uses; +use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref; use crate::{ borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, @@ -156,7 +158,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_note( MultiSpan::from_spans(reinit_spans), &if reinits <= 3 { - format!("these {} reinitializations might get skipped", reinits) + format!("these {reinits} reinitializations might get skipped") } else { format!( "these 3 reinitializations and {} other{} might get skipped", @@ -194,7 +196,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if !seen_spans.contains(&move_span) { if !closure { - self.suggest_ref_or_clone(mpi, move_span, &mut err, &mut in_pattern); + self.suggest_ref_or_clone( + mpi, + move_span, + &mut err, + &mut in_pattern, + move_spans, + ); } self.explain_captures( @@ -219,9 +227,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( span, format!( - "value {} here after {}move", + "value {} here after {partial_str}move", desired_action.as_verb_in_past_tense(), - partial_str ), ); } @@ -251,7 +258,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &format!( "consider creating a fresh reborrow of {} here", self.describe_place(moved_place) - .map(|n| format!("`{}`", n)) + .map(|n| format!("`{n}`")) .unwrap_or_else(|| "the mutable reference".to_string()), ), "&mut *", @@ -265,7 +272,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { DescribePlaceOpt { including_downcast: true, including_tuple_field: true }, ); let note_msg = match opt_name { - Some(name) => format!("`{}`", name), + Some(name) => format!("`{name}`"), None => "value".to_owned(), }; if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, ¬e_msg) { @@ -291,9 +298,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } = use_spans { err.note(&format!( - "{} occurs due to deref coercion to `{}`", + "{} occurs due to deref coercion to `{deref_target_ty}`", desired_action.as_noun(), - deref_target_ty )); // Check first whether the source is accessible (issue #87060) @@ -312,6 +318,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_span: Span, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, in_pattern: &mut bool, + move_spans: UseSpans<'_>, ) { struct ExpressionFinder<'hir> { expr_span: Span, @@ -351,7 +358,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. - })) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_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; @@ -387,7 +394,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } let typeck = self.infcx.tcx.typeck(self.mir_def_id()); - let hir_id = hir.get_parent_node(expr.hir_id); + let hir_id = hir.parent_id(expr.hir_id); if let Some(parent) = hir.find(hir_id) { let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind @@ -440,6 +447,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) = call_expr.kind { // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing. + } else if let UseSpans::FnSelfUse { + kind: CallKind::Normal { .. }, + .. + } = move_spans { + // We already suggest cloning for these cases in `explain_captures`. } else { self.suggest_cloning(err, ty, move_span); } @@ -515,26 +527,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // that are *partially* initialized by assigning to a field of an uninitialized // binding. We differentiate between them for more accurate wording here. "isn't fully initialized" - } else if spans - .iter() - .filter(|i| { - // We filter these to avoid misleading wording in cases like the following, - // where `x` has an `init`, but it is in the same place we're looking at: - // ``` - // let x; - // x += 1; - // ``` - !i.contains(span) - // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs` - && !visitor - .errors - .iter() - .map(|(sp, _)| *sp) - .any(|sp| span < sp && !sp.contains(span)) - }) - .count() - == 0 - { + } else if !spans.iter().any(|i| { + // We filter these to avoid misleading wording in cases like the following, + // where `x` has an `init`, but it is in the same place we're looking at: + // ``` + // let x; + // x += 1; + // ``` + !i.contains(span) + // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs` + && !visitor + .errors + .iter() + .map(|(sp, _)| *sp) + .any(|sp| span < sp && !sp.contains(span)) + }) { show_assign_sugg = true; "isn't initialized" } else { @@ -649,7 +656,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if !assign_value.is_empty() { err.span_suggestion_verbose( sugg_span.shrink_to_hi(), - format!("consider assigning a value"), + "consider assigning a value", format!(" = {}", assign_value), Applicability::MaybeIncorrect, ); @@ -666,40 +673,34 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let tcx = self.infcx.tcx; // Find out if the predicates show that the type is a Fn or FnMut - let find_fn_kind_from_did = |predicates: ty::EarlyBinder< - &[(ty::Predicate<'tcx>, Span)], - >, - substs| { - predicates.0.iter().find_map(|(pred, _)| { - let pred = if let Some(substs) = substs { - predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder() - } else { - pred.kind().skip_binder() - }; - if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred && pred.self_ty() == ty { - if Some(pred.def_id()) == tcx.lang_items().fn_trait() { - return Some(hir::Mutability::Not); - } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() { - return Some(hir::Mutability::Mut); - } + let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| { + if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = pred.kind().skip_binder() + && pred.self_ty() == ty + { + if Some(pred.def_id()) == tcx.lang_items().fn_trait() { + return Some(hir::Mutability::Not); + } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() { + return Some(hir::Mutability::Mut); } - None - }) + } + None }; // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably) // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`. // These types seem reasonably opaque enough that they could be substituted with their // borrowed variants in a function body when we see a move error. - let borrow_level = match ty.kind() { - ty::Param(_) => find_fn_kind_from_did( - tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id()) - .map_bound(|p| p.predicates), - None, - ), - ty::Opaque(did, substs) => { - find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*did), Some(*substs)) - } + let borrow_level = match *ty.kind() { + ty::Param(_) => tcx + .explicit_predicates_of(self.mir_def_id().to_def_id()) + .predicates + .iter() + .copied() + .find_map(find_fn_kind_from_did), + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx + .bound_explicit_item_bounds(def_id) + .subst_iter_copied(tcx, substs) + .find_map(find_fn_kind_from_did), ty::Closure(_, substs) => match substs.as_closure().kind() { ty::ClosureKind::Fn => Some(hir::Mutability::Not), ty::ClosureKind::FnMut => Some(hir::Mutability::Mut), @@ -745,7 +746,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_suggestion_verbose( span.shrink_to_hi(), "consider cloning the value if the performance cost is acceptable", - ".clone()".to_string(), + ".clone()", Applicability::MachineApplicable, ); } @@ -943,7 +944,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } (BorrowKind::Mut { .. }, BorrowKind::Shared) => { first_borrow_desc = "immutable "; - self.cannot_reborrow_already_borrowed( + let mut err = self.cannot_reborrow_already_borrowed( span, &desc_place, &msg_place, @@ -953,7 +954,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "immutable", &msg_borrow, None, - ) + ); + self.suggest_binding_for_closure_capture_self( + &mut err, + issued_borrow.borrowed_place, + &issued_spans, + ); + err } (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => { @@ -1235,6 +1242,138 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + fn suggest_binding_for_closure_capture_self( + &self, + err: &mut Diagnostic, + borrowed_place: Place<'tcx>, + issued_spans: &UseSpans<'tcx>, + ) { + let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return }; + let hir = self.infcx.tcx.hir(); + + // check whether the borrowed place is capturing `self` by mut reference + let local = borrowed_place.local; + let Some(_) = self + .body + .local_decls + .get(local) + .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return }; + + struct ExpressionFinder<'hir> { + capture_span: Span, + closure_change_spans: Vec, + closure_arg_span: Option, + in_closure: bool, + suggest_arg: String, + hir: rustc_middle::hir::map::Map<'hir>, + closure_local_id: Option, + closure_call_changes: Vec<(Span, String)>, + } + impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { + if e.span.contains(self.capture_span) { + if let hir::ExprKind::Closure(&hir::Closure { + movability: None, + body, + fn_arg_span, + fn_decl: hir::FnDecl{ inputs, .. }, + .. + }) = e.kind && + let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) { + self.suggest_arg = "this: &Self".to_string(); + if inputs.len() > 0 { + self.suggest_arg.push_str(", "); + } + self.in_closure = true; + self.closure_arg_span = fn_arg_span; + self.visit_expr(body); + self.in_closure = false; + } + } + if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e { + if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path && + seg.ident.name == kw::SelfLower && self.in_closure { + self.closure_change_spans.push(e.span); + } + } + hir::intravisit::walk_expr(self, e); + } + + fn visit_local(&mut self, local: &'hir hir::Local<'hir>) { + if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat && + let Some(init) = local.init + { + if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { + movability: None, + .. + }), .. } = init && + init.span.contains(self.capture_span) { + self.closure_local_id = Some(*hir_id); + } + } + hir::intravisit::walk_local(self, local); + } + + fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) { + 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 && + let Res::Local(hir_id) = seg.res && + Some(hir_id) == self.closure_local_id { + let (span, arg_str) = if args.len() > 0 { + (args[0].span.shrink_to_lo(), "self, ".to_string()) + } else { + let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span); + (span, "(self)".to_string()) + }; + self.closure_call_changes.push((span, arg_str)); + } + hir::intravisit::walk_stmt(self, s); + } + } + + if let Some(hir::Node::ImplItem( + hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. } + )) = hir.find(self.mir_hir_id()) && + let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) { + let mut finder = ExpressionFinder { + capture_span: *capture_kind_span, + closure_change_spans: vec![], + closure_arg_span: None, + in_closure: false, + suggest_arg: String::new(), + closure_local_id: None, + closure_call_changes: vec![], + hir, + }; + finder.visit_expr(expr); + + if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() { + return; + } + + let mut sugg = vec![]; + let sm = self.infcx.tcx.sess.source_map(); + + if let Some(span) = finder.closure_arg_span { + sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg)); + } + for span in finder.closure_change_spans { + sugg.push((span, "this".to_string())); + } + + for (span, suggest) in finder.closure_call_changes { + sugg.push((span, suggest)); + } + + err.multipart_suggestion_verbose( + "try explicitly pass `&Self` into the Closure as an argument", + sugg, + Applicability::MachineApplicable, + ); + } + } + /// Returns the description of the root place for a conflicting borrow and the full /// descriptions of the places that caused the conflict. /// @@ -1416,6 +1555,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // // then just use the normal error. The closure isn't escaping // and `move` will not help here. + ( + Some(name), + BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _), + ) => self.report_escaping_closure_capture( + borrow_spans, + borrow_span, + &RegionName { + name: self.synthesize_region_name(), + source: RegionNameSource::Static, + }, + ConstraintCategory::CallArgument(None), + var_or_use_span, + &format!("`{}`", name), + "block", + ), ( Some(name), BorrowExplanation::MustBeValidFor { @@ -1436,6 +1590,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { category, span, &format!("`{}`", name), + "function", ), ( name, @@ -1716,7 +1871,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// We check that there's a single level of block nesting to ensure always correct /// suggestions. If we don't, then we only provide a free-form message to avoid - /// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`. + /// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`. /// We could expand the analysis to suggest hoising all of the relevant parts of /// the users' code to make the code compile, but that could be too much. struct NestedStatementVisitor { @@ -1888,6 +2043,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(err) } + #[instrument(level = "debug", skip(self))] fn report_escaping_closure_capture( &mut self, use_span: UseSpans<'tcx>, @@ -1896,6 +2052,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { category: ConstraintCategory<'tcx>, constraint_span: Span, captured_var: &str, + scope: &str, ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { let tcx = self.infcx.tcx; let args_span = use_span.args_or_use(); @@ -1926,8 +2083,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None => "closure", }; - let mut err = - self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span); + let mut err = self.cannot_capture_in_long_lived_closure( + args_span, + kind, + captured_var, + var_span, + scope, + ); err.span_suggestion_verbose( sugg_span, &format!( @@ -1949,10 +2111,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) { err.note( "async blocks are not executed immediately and must either take a \ - reference or ownership of outside variables they use", + reference or ownership of outside variables they use", ); } else { - let msg = format!("function requires argument type to outlive `{}`", fr_name); + let msg = format!("{scope} requires argument type to outlive `{fr_name}`"); err.span_note(constraint_span, &msg); } } @@ -2031,7 +2193,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut back_edge_stack = Vec::new(); predecessor_locations(self.body, location).for_each(|predecessor| { - if location.dominates(predecessor, &self.dominators) { + if location.dominates(predecessor, self.dominators()) { back_edge_stack.push(predecessor) } else { stack.push(predecessor); @@ -2143,7 +2305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut has_predecessor = false; predecessor_locations(self.body, location).for_each(|predecessor| { - if location.dominates(predecessor, &self.dominators) { + if location.dominates(predecessor, self.dominators()) { back_edge_stack.push(predecessor) } else { stack.push(predecessor); @@ -2669,7 +2831,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Need to use the `rustc_middle::ty` types to compare against the // `return_region`. Then use the `rustc_hir` type to get only // the lifetime span. - if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind { + if let hir::TyKind::Ref(lifetime, _) = &fn_decl.inputs[index].kind { // With access to the lifetime, we can get // the span of it. arguments.push((*argument, lifetime.ident.span)); @@ -2690,7 +2852,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let return_ty = sig.output().skip_binder(); let mut return_span = fn_decl.output.span(); if let hir::FnRetTy::Return(ty) = &fn_decl.output { - if let hir::TyKind::Rptr(lifetime, _) = ty.kind { + if let hir::TyKind::Ref(lifetime, _) = ty.kind { return_span = lifetime.ident.span; } } diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 304683618..209574709 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -77,7 +77,7 @@ impl<'tcx> BorrowExplanation<'tcx> { if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) { err.span_label( var_or_use_span, - format!("{}borrow later {}", borrow_desc, message), + format!("{borrow_desc}borrow later {message}"), ); } } else { @@ -90,7 +90,7 @@ impl<'tcx> BorrowExplanation<'tcx> { let capture_kind_label = message; err.span_label( var_or_use_span, - format!("{}borrow later {}", borrow_desc, capture_kind_label), + format!("{borrow_desc}borrow later {capture_kind_label}"), ); err.span_label(path_span, path_label); } @@ -110,7 +110,7 @@ impl<'tcx> BorrowExplanation<'tcx> { }; // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) { - err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message)); + err.span_label(var_or_use_span, format!("{borrow_desc}{message}")); } else { // path_span must be `Some` as otherwise the if condition is true let path_span = path_span.unwrap(); @@ -121,7 +121,7 @@ impl<'tcx> BorrowExplanation<'tcx> { let capture_kind_label = message; err.span_label( var_or_use_span, - format!("{}borrow later {}", borrow_desc, capture_kind_label), + format!("{borrow_desc}borrow later {capture_kind_label}"), ); err.span_label(path_span, path_label); } @@ -160,12 +160,8 @@ impl<'tcx> BorrowExplanation<'tcx> { match local_names[dropped_local] { Some(local_name) if !local_decl.from_compiler_desugaring() => { let message = format!( - "{B}borrow might be used here, when `{LOC}` is dropped \ - and runs the {DTOR} for {TYPE}", - B = borrow_desc, - LOC = local_name, - TYPE = type_desc, - DTOR = dtor_desc + "{borrow_desc}borrow might be used here, when `{local_name}` is dropped \ + and runs the {dtor_desc} for {type_desc}", ); err.span_label(body.source_info(drop_loc).span, message); @@ -180,18 +176,14 @@ impl<'tcx> BorrowExplanation<'tcx> { err.span_label( local_decl.source_info.span, format!( - "a temporary with access to the {B}borrow \ + "a temporary with access to the {borrow_desc}borrow \ is created here ...", - B = borrow_desc ), ); let message = format!( - "... and the {B}borrow might be used here, \ + "... and the {borrow_desc}borrow might be used here, \ when that temporary is dropped \ - and runs the {DTOR} for {TYPE}", - B = borrow_desc, - TYPE = type_desc, - DTOR = dtor_desc + and runs the {dtor_desc} for {type_desc}", ); err.span_label(body.source_info(drop_loc).span, message); @@ -249,20 +241,16 @@ impl<'tcx> BorrowExplanation<'tcx> { err.span_label( span, format!( - "{}requires that `{}` is borrowed for `{}`", + "{}requires that `{desc}` is borrowed for `{region_name}`", category.description(), - desc, - region_name, ), ); } else { err.span_label( span, format!( - "{}requires that {}borrow lasts for `{}`", + "{}requires that {borrow_desc}borrow lasts for `{region_name}`", category.description(), - borrow_desc, - region_name, ), ); }; @@ -270,7 +258,7 @@ impl<'tcx> BorrowExplanation<'tcx> { for extra in extra_info { match extra { ExtraConstraintInfo::PlaceholderFromPredicate(span) => { - err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")); + err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); } } } @@ -296,15 +284,14 @@ impl<'tcx> BorrowExplanation<'tcx> { if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime }; let msg = format!( - "you can add a bound to the {}to make it last less than `'static` and match `{}`", + "you can add a bound to the {}to make it last less than `'static` and match `{region_name}`", category.description(), - region_name, ); err.span_suggestion_verbose( span.shrink_to_hi(), &msg, - format!(" + {}", suggestable_name), + format!(" + {suggestable_name}"), Applicability::Unspecified, ); } @@ -444,6 +431,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// First span returned points to the location of the conflicting use /// Second span if `Some` is returned in the case of closures and points /// to the use of the path + #[instrument(level = "debug", skip(self))] fn later_use_kind( &self, borrow: &BorrowData<'tcx>, @@ -461,11 +449,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let block = &self.body.basic_blocks[location.block]; let kind = if let Some(&Statement { - kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)), + kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)), .. }) = block.statements.get(location.statement_index) { - LaterUseKind::FakeLetRead + if let Some(l) = place.as_local() + && let local_decl = &self.body.local_decls[l] + && local_decl.ty.is_closure() + { + LaterUseKind::ClosureCapture + } else { + LaterUseKind::FakeLetRead + } } else if self.was_captured_by_trait_object(borrow) { LaterUseKind::TraitCapture } else if location.statement_index == block.statements.len() { diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs index 498e98343..2c4d953f0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs +++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{Body, Local, Location}; /// Find all uses of (including assignments to) a [`Local`]. /// /// Uses `BTreeSet` so output is deterministic. -pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet { +pub(super) fn find(body: &Body<'_>, local: Local) -> BTreeSet { let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() }; visitor.visit_body(body); visitor.uses diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 4e2271a30..1b40b7143 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -6,7 +6,7 @@ use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::GeneratorKind; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{LateBoundRegionConversionTime, TyCtxtInferExt}; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand, @@ -18,7 +18,10 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; -use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{ + type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause, +}; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; @@ -400,8 +403,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_prefix: &str, ) { let message = format!( - "{}move occurs because {} has type `{}`, which does not implement the `Copy` trait", - move_prefix, place_desc, ty, + "{move_prefix}move occurs because {place_desc} has type `{ty}`, which does not implement the `Copy` trait", ); if let Some(span) = span { err.span_label(span, message); @@ -736,11 +738,11 @@ impl<'tcx> BorrowedContentSource<'tcx> { BorrowedContentSource::OverloadedDeref(ty) => ty .ty_adt_def() .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? { - name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)), + name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")), _ => None, }) - .unwrap_or_else(|| format!("dereference of `{}`", ty)), - BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty), + .unwrap_or_else(|| format!("dereference of `{ty}`")), + BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{ty}`"), } } @@ -766,11 +768,11 @@ impl<'tcx> BorrowedContentSource<'tcx> { BorrowedContentSource::OverloadedDeref(ty) => ty .ty_adt_def() .and_then(|adt| match tcx.get_diagnostic_name(adt.did())? { - name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)), + name @ (sym::Rc | sym::Arc) => Some(format!("an `{name}`")), _ => None, }) - .unwrap_or_else(|| format!("dereference of `{}`", ty)), - BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty), + .unwrap_or_else(|| format!("dereference of `{ty}`")), + BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{ty}`"), } } @@ -1030,7 +1032,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { let place_name = self .describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) + .map(|n| format!("`{n}`")) .unwrap_or_else(|| "value".to_owned()); match kind { CallKind::FnCall { fn_trait_id, .. } @@ -1039,8 +1041,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( fn_call_span, &format!( - "{} {}moved due to this call{}", - place_name, partially_str, loop_message + "{place_name} {partially_str}moved due to this call{loop_message}", ), ); err.span_note( @@ -1053,36 +1054,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( fn_call_span, &format!( - "{} {}moved due to usage in operator{}", - place_name, partially_str, loop_message + "{place_name} {partially_str}moved due to usage in operator{loop_message}", ), ); if self.fn_self_span_reported.insert(fn_span) { err.span_note( - // Check whether the source is accessible - if self.infcx.tcx.sess.source_map().is_span_accessible(self_arg.span) { - self_arg.span - } else { - fn_call_span - }, + self_arg.span, "calling this operator moves the left-hand side", ); } } - CallKind::Normal { self_arg, desugaring, is_option_or_result } => { + CallKind::Normal { self_arg, desugaring, method_did } => { let self_arg = self_arg.unwrap(); + let tcx = self.infcx.tcx; if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { - let ty = moved_place.ty(self.body, self.infcx.tcx).ty; - let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { + let ty = moved_place.ty(self.body, tcx).ty; + let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) { Some(def_id) => { let infcx = self.infcx.tcx.infer_ctxt().build(); type_known_to_meet_bound_modulo_regions( &infcx, self.param_env, - infcx.tcx.mk_imm_ref( - infcx.tcx.lifetimes.re_erased, - infcx.tcx.erase_regions(ty), - ), + tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)), def_id, DUMMY_SP, ) @@ -1093,9 +1086,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_suggestion_verbose( move_span.shrink_to_lo(), &format!( - "consider iterating over a slice of the `{}`'s content to \ + "consider iterating over a slice of the `{ty}`'s content to \ avoid moving into the `for` loop", - ty, ), "&", Applicability::MaybeIncorrect, @@ -1105,8 +1097,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( fn_call_span, &format!( - "{} {}moved due to this implicit call to `.into_iter()`{}", - place_name, partially_str, loop_message + "{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}", ), ); // If the moved place was a `&mut` ref, then we can @@ -1122,7 +1113,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &format!( "consider creating a fresh reborrow of {} here", self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{}`", n)) + .map(|n| format!("`{n}`")) .unwrap_or_else(|| "the mutable reference".to_string()), ), "&mut *", @@ -1134,19 +1125,67 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( fn_call_span, &format!( - "{} {}moved due to this method call{}", - place_name, partially_str, loop_message + "{place_name} {partially_str}moved due to this method call{loop_message}", ), ); + let infcx = tcx.infer_ctxt().build(); + let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty); + if let ty::Adt(def, substs) = ty.kind() + && Some(def.did()) == tcx.lang_items().pin_type() + && let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind() + && let self_ty = infcx.replace_bound_vars_with_fresh_vars( + fn_call_span, + LateBoundRegionConversionTime::FnCall, + tcx.fn_sig(method_did).input(0), + ) + && infcx.can_eq(self.param_env, ty, self_ty).is_ok() + { + err.span_suggestion_verbose( + fn_call_span.shrink_to_lo(), + "consider reborrowing the `Pin` instead of moving it", + "as_mut().".to_string(), + Applicability::MaybeIncorrect, + ); + } + if let Some(clone_trait) = tcx.lang_items().clone_trait() + && let trait_ref = tcx.mk_trait_ref(clone_trait, [ty]) + && let o = Obligation::new( + tcx, + ObligationCause::dummy(), + self.param_env, + ty::Binder::dummy(trait_ref), + ) + && infcx.predicate_must_hold_modulo_regions(&o) + { + err.span_suggestion_verbose( + fn_call_span.shrink_to_lo(), + "you can `clone` the value and consume it, but this might not be \ + your desired behavior", + "clone().".to_string(), + Applicability::MaybeIncorrect, + ); + } } // Avoid pointing to the same function in multiple different // error messages. if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { + let func = tcx.def_path_str(method_did); err.span_note( self_arg.span, - &format!("this function takes ownership of the receiver `self`, which moves {}", place_name) + &format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}") ); } + let parent_did = tcx.parent(method_did); + let parent_self_ty = (tcx.def_kind(parent_did) + == rustc_hir::def::DefKind::Impl) + .then_some(parent_did) + .and_then(|did| match tcx.type_of(did).kind() { + ty::Adt(def, ..) => Some(def.did()), + _ => None, + }); + let is_option_or_result = parent_self_ty.map_or(false, |def_id| { + matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) + }); if is_option_or_result && maybe_reinitialized_locations_is_empty { err.span_label( var_span, @@ -1161,7 +1200,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if move_span != span || !loop_message.is_empty() { err.span_label( move_span, - format!("value {}moved{} here{}", partially_str, move_msg, loop_message), + format!("value {partially_str}moved{move_msg} here{loop_message}"), ); } // If the move error occurs due to a loop, don't show @@ -1169,7 +1208,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if loop_message.is_empty() { move_spans.var_span_label( err, - format!("variable {}moved due to use{}", partially_str, move_spans.describe()), + format!("variable {partially_str}moved due to use{}", move_spans.describe()), "moved", ); } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 5a47f4567..6db3c858a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -4,7 +4,7 @@ use rustc_middle::ty; use rustc_mir_dataflow::move_paths::{ IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex, }; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; use crate::diagnostics::{DescribePlaceOpt, UseSpans}; use crate::prefixes::PrefixSet; @@ -148,7 +148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match_span: Span, statement_span: Span, ) { - debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span); + debug!(?match_place, ?match_span, "append_binding_error"); let from_simple_let = match_place.is_none(); let match_place = match_place.unwrap_or(move_from); @@ -160,7 +160,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge && match_span == *span { - debug!("appending local({:?}) to list", bind_to); + debug!("appending local({bind_to:?}) to list"); if !binds_to.is_empty() { binds_to.push(bind_to); } @@ -198,7 +198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } = ge { if match_span == *span && mpi == *other_mpi { - debug!("appending local({:?}) to list", bind_to); + debug!("appending local({bind_to:?}) to list"); binds_to.push(bind_to); return; } @@ -410,15 +410,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) { match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { - if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "consider borrowing here", - format!("&{snippet}"), - Applicability::Unspecified, - ); - } - + self.add_borrow_suggestions(err, span); if binds_to.is_empty() { let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; let place_desc = match self.describe_place(move_from.as_ref()) { @@ -461,39 +453,75 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } + fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) { + match self.infcx.tcx.sess.source_map().span_to_snippet(span) { + Ok(snippet) if snippet.starts_with('*') => { + err.span_suggestion_verbose( + span.with_hi(span.lo() + BytePos(1)), + "consider removing the dereference here", + String::new(), + Applicability::MaybeIncorrect, + ); + } + _ => { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider borrowing here", + "&".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) { - let mut suggestions: Vec<(Span, &str, String)> = Vec::new(); + let mut suggestions: Vec<(Span, String, String)> = Vec::new(); for local in binds_to { let bind_to = &self.body.local_decls[*local]; if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( VarBindingForm { pat_span, .. }, )))) = bind_to.local_info { - if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) + let Ok(pat_snippet) = + self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; }; + let Some(stripped) = pat_snippet.strip_prefix('&') else { + suggestions.push(( + bind_to.source_info.span.shrink_to_lo(), + "consider borrowing the pattern binding".to_string(), + "ref ".to_string(), + )); + continue; + }; + let inner_pat_snippet = stripped.trim_start(); + let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut") + && inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace) { - if let Some(stripped) = pat_snippet.strip_prefix('&') { - let pat_snippet = stripped.trim_start(); - let (suggestion, to_remove) = if pat_snippet.starts_with("mut") - && pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace) - { - (pat_snippet["mut".len()..].trim_start(), "&mut") - } else { - (pat_snippet, "&") - }; - suggestions.push((pat_span, to_remove, suggestion.to_owned())); - } - } + let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start(); + let pat_span = pat_span.with_hi( + pat_span.lo() + + BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32), + ); + (pat_span, String::new(), "mutable borrow") + } else { + let pat_span = pat_span.with_hi( + pat_span.lo() + + BytePos( + (pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32, + ), + ); + (pat_span, String::new(), "borrow") + }; + suggestions.push(( + pat_span, + format!("consider removing the {to_remove}"), + suggestion.to_string(), + )); } } suggestions.sort_unstable_by_key(|&(span, _, _)| span); suggestions.dedup_by_key(|&mut (span, _, _)| span); - for (span, to_remove, suggestion) in suggestions { - err.span_suggestion( - span, - &format!("consider removing the `{to_remove}`"), - suggestion, - Applicability::MachineApplicable, - ); + for (span, msg, suggestion) in suggestions { + err.span_suggestion_verbose(span, &msg, suggestion, Applicability::MachineApplicable); } } @@ -521,8 +549,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if binds_to.len() > 1 { err.note( - "move occurs because these variables have types that \ - don't implement the `Copy` trait", + "move occurs because these variables have types that don't implement the `Copy` \ + trait", ); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 3319a8068..45b15c2c5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -180,6 +180,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // the verbs used in some diagnostic messages. let act; let acted_on; + let mut suggest = true; + let mut mut_error = None; + let mut count = 1; let span = match error_access { AccessKind::Mutate => { @@ -194,15 +197,50 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let borrow_spans = self.borrow_spans(span, location); let borrow_span = borrow_spans.args_or_use(); - err = self.cannot_borrow_path_as_mutable_because(borrow_span, &item_msg, &reason); - borrow_spans.var_span_label( - &mut err, - format!( - "mutable borrow occurs due to use of {} in closure", - self.describe_any_place(access_place.as_ref()), - ), - "mutable", - ); + match the_place_err { + PlaceRef { local, projection: [] } + if self.body.local_decls[local].can_be_made_mutable() => + { + let span = self.body.local_decls[local].source_info.span; + mut_error = Some(span); + if let Some((buffer, c)) = self.get_buffered_mut_error(span) { + // We've encountered a second (or more) attempt to mutably borrow an + // immutable binding, so the likely problem is with the binding + // declaration, not the use. We collect these in a single diagnostic + // and make the binding the primary span of the error. + err = buffer; + count = c + 1; + if count == 2 { + err.replace_span_with(span, false); + err.span_label(span, "not mutable"); + } + suggest = false; + } else { + err = self.cannot_borrow_path_as_mutable_because( + borrow_span, + &item_msg, + &reason, + ); + } + } + _ => { + err = self.cannot_borrow_path_as_mutable_because( + borrow_span, + &item_msg, + &reason, + ); + } + } + if suggest { + borrow_spans.var_span_label( + &mut err, + format!( + "mutable borrow occurs due to use of {} in closure", + self.describe_any_place(access_place.as_ref()), + ), + "mutable", + ); + } borrow_span } }; @@ -226,7 +264,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ProjectionElem::Deref, ], } => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_label(span, format!("cannot {act}")); if let Some(span) = get_mut_span_in_struct_field( self.infcx.tcx, @@ -252,7 +290,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .unwrap_or(false) => { let decl = &self.body.local_decls[local]; - err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_label(span, format!("cannot {act}")); if let Some(mir::Statement { source_info, kind: @@ -276,7 +314,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pat_span: _, }, )))) => { - err.span_note(sp, "the binding is already a mutable borrow"); + if suggest { + err.span_note(sp, "the binding is already a mutable borrow"); + } } _ => { err.span_note( @@ -304,20 +344,25 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { err.span_help(source_info.span, "try removing `&mut` here"); } - } else if decl.mutability == Mutability::Not - && !matches!( + } else if decl.mutability == Mutability::Not { + if matches!( decl.local_info, Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( hir::ImplicitSelfKind::MutRef - )))) - ) - { - err.span_suggestion_verbose( - decl.source_info.span.shrink_to_lo(), - "consider making the binding mutable", - "mut ", - Applicability::MachineApplicable, - ); + ),))) + ) { + err.note( + "as `Self` may be unsized, this call attempts to take `&mut &mut self`", + ); + err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably"); + } else { + err.span_suggestion_verbose( + decl.source_info.span.shrink_to_lo(), + "consider making the binding mutable", + "mut ", + Applicability::MachineApplicable, + ); + }; } } @@ -333,16 +378,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let local_decl = &self.body.local_decls[local]; assert_eq!(local_decl.mutability, Mutability::Not); - err.span_label(span, format!("cannot {ACT}", ACT = act)); - err.span_suggestion( - local_decl.source_info.span, - "consider changing this to be mutable", - format!("mut {}", self.local_names[local].unwrap()), - Applicability::MachineApplicable, - ); - let tcx = self.infcx.tcx; - if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() { - self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err); + if count < 10 { + err.span_label(span, format!("cannot {act}")); + } + if suggest { + err.span_suggestion_verbose( + local_decl.source_info.span.shrink_to_lo(), + "consider changing this to be mutable", + "mut ".to_string(), + Applicability::MachineApplicable, + ); + let tcx = self.infcx.tcx; + if let ty::Closure(id, _) = *the_place_err.ty(self.body, tcx).ty.kind() { + self.show_mutating_upvar(tcx, id.expect_local(), the_place_err, &mut err); + } } } @@ -357,7 +406,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let captured_place = &self.upvars[upvar_index.index()].place; - err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_label(span, format!("cannot {act}")); let upvar_hir_id = captured_place.get_root_variable(); @@ -397,7 +446,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .span_to_snippet(span) .map_or(false, |snippet| snippet.starts_with("&mut ")) => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_label(span, format!("cannot {act}")); err.span_suggestion( span, "try removing `&mut` here", @@ -409,7 +458,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { local, projection: [ProjectionElem::Deref] } if self.body.local_decls[local].is_ref_for_guard() => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_label(span, format!("cannot {act}")); err.note( "variables bound in patterns are immutable until the end of the pattern guard", ); @@ -537,7 +586,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Some((true, err_help_span, suggested_code)) => { let (is_trait_sig, local_trait) = self.is_error_in_trait(local); if !is_trait_sig { - err.span_suggestion( + err.span_suggestion_verbose( err_help_span, &format!( "consider changing this to be a mutable {pointer_desc}" @@ -546,7 +595,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } else if let Some(x) = local_trait { - err.span_suggestion( + err.span_suggestion_verbose( x, &format!( "consider changing that to be a mutable {pointer_desc}" @@ -569,24 +618,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_label( span, format!( - "`{NAME}` is a `{SIGIL}` {DESC}, \ - so the data it refers to cannot be {ACTED_ON}", - NAME = name, - SIGIL = pointer_sigil, - DESC = pointer_desc, - ACTED_ON = acted_on + "`{name}` is a `{pointer_sigil}` {pointer_desc}, \ + so the data it refers to cannot be {acted_on}", ), ); } _ => { err.span_label( span, - format!( - "cannot {ACT} through `{SIGIL}` {DESC}", - ACT = act, - SIGIL = pointer_sigil, - DESC = pointer_desc - ), + format!("cannot {act} through `{pointer_sigil}` {pointer_desc}"), ); } } @@ -599,19 +639,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_label(span, format!("cannot {act}")); match opt_source { Some(BorrowedContentSource::OverloadedDeref(ty)) => { err.help(&format!( "trait `DerefMut` is required to modify through a dereference, \ - but it is not implemented for `{ty}`", + but it is not implemented for `{ty}`", )); } Some(BorrowedContentSource::OverloadedIndex(ty)) => { err.help(&format!( "trait `IndexMut` is required to modify indexed content, \ - but it is not implemented for `{ty}`", + but it is not implemented for `{ty}`", )); self.suggest_map_index_mut_alternatives(ty, &mut err, span); } @@ -620,11 +660,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } _ => { - err.span_label(span, format!("cannot {ACT}", ACT = act)); + err.span_label(span, format!("cannot {act}")); } } - self.buffer_error(err); + if let Some(span) = mut_error { + self.buffer_mut_error(span, err, count); + } else { + self.buffer_error(err); + } } fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) { @@ -965,7 +1009,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let hir = self.infcx.tcx.hir(); let closure_id = self.mir_hir_id(); let closure_span = self.infcx.tcx.def_span(self.mir_def_id()); - let fn_call_id = hir.get_parent_node(closure_id); + let fn_call_id = hir.parent_id(closure_id); let node = hir.get(fn_call_id); let def_id = hir.enclosing_body_owner(fn_call_id); let mut look_at_return = true; @@ -1050,7 +1094,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } -fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option) -> bool { +pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option) -> bool { debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind()); match local_decl.local_info.as_deref() { @@ -1168,7 +1212,7 @@ fn suggest_ampmut<'tcx>( { let lt_name = &src[1..ws_pos]; let ty = &src[ws_pos..]; - return (true, highlight_span, format!("&{} mut{}", lt_name, ty)); + return (true, highlight_span, format!("&{lt_name} mut{ty}")); } let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); @@ -1209,7 +1253,7 @@ fn get_mut_span_in_struct_field<'tcx>( // Now we're dealing with the actual struct that we're going to suggest a change to, // we can expect a field that is an immutable reference to a type. && let hir::Node::Field(field) = node - && let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind + && let hir::TyKind::Ref(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind { return Some(lt.ident.span.between(ty.span)); } diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index 35c3df768..1eaf0a2f1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -209,14 +209,14 @@ impl OutlivesSuggestionBuilder { let mut diag = if suggested.len() == 1 { mbcx.infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() { SuggestedConstraint::Outlives(a, bs) => { - let bs: SmallVec<[String; 2]> = bs.iter().map(|r| format!("{}", r)).collect(); - format!("add bound `{}: {}`", a, bs.join(" + ")) + let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect(); + format!("add bound `{a}: {}`", bs.join(" + ")) } SuggestedConstraint::Equal(a, b) => { - format!("`{}` and `{}` must be the same: replace one with the other", a, b) + format!("`{a}` and `{b}` must be the same: replace one with the other") } - SuggestedConstraint::Static(a) => format!("replace `{}` with `'static`", a), + SuggestedConstraint::Static(a) => format!("replace `{a}` with `'static`"), }) } else { // Create a new diagnostic. @@ -231,18 +231,16 @@ impl OutlivesSuggestionBuilder { for constraint in suggested { match constraint { SuggestedConstraint::Outlives(a, bs) => { - let bs: SmallVec<[String; 2]> = - bs.iter().map(|r| format!("{}", r)).collect(); - diag.help(&format!("add bound `{}: {}`", a, bs.join(" + "))); + let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect(); + diag.help(&format!("add bound `{a}: {}`", bs.join(" + "))); } SuggestedConstraint::Equal(a, b) => { diag.help(&format!( - "`{}` and `{}` must be the same: replace one with the other", - a, b + "`{a}` and `{b}` must be the same: replace one with the other", )); } SuggestedConstraint::Static(a) => { - diag.help(&format!("replace `{}` with `'static`", a)); + diag.help(&format!("replace `{a}` with `'static`")); } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 9bc2e79e2..187861ba1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -4,9 +4,14 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; +use rustc_hir as hir; +use rustc_hir::def::Res::Def; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{self as hir, Item, ItemKind, Node}; +use rustc_hir::GenericBound::Trait; +use rustc_hir::QPath::Resolved; +use rustc_hir::WherePredicate::BoundPredicate; +use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; use rustc_infer::infer::{ error_reporting::nice_region_error::{ self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, @@ -18,11 +23,11 @@ use rustc_infer::infer::{ use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::Region; use rustc_middle::ty::TypeVisitor; use rustc_middle::ty::{self, RegionVid, Ty}; +use rustc_middle::ty::{Region, TyCtxt}; use rustc_span::symbol::{kw, Ident}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use crate::borrowck_errors; use crate::session_diagnostics::{ @@ -70,7 +75,25 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> { /// /// Usually we expect this to either be empty or contain a small number of items, so we can avoid /// allocation most of the time. -pub(crate) type RegionErrors<'tcx> = Vec>; +pub(crate) struct RegionErrors<'tcx>(Vec>, TyCtxt<'tcx>); + +impl<'tcx> RegionErrors<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + Self(vec![], tcx) + } + #[track_caller] + pub fn push(&mut self, val: impl Into>) { + let val = val.into(); + self.1.sess.delay_span_bug(DUMMY_SP, format!("{val:?}")); + self.0.push(val); + } + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + pub fn into_iter(self) -> impl Iterator> { + self.0.into_iter() + } +} #[derive(Clone, Debug)] pub(crate) enum RegionErrorKind<'tcx> { @@ -168,12 +191,109 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { false } + // For generic associated types (GATs) which implied 'static requirement + // from higher-ranked trait bounds (HRTB). Try to locate span of the trait + // and the span which bounded to the trait for adding 'static lifetime suggestion + fn suggest_static_lifetime_for_gat_from_hrtb( + &self, + diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + lower_bound: RegionVid, + ) { + let mut suggestions = vec![]; + let hir = self.infcx.tcx.hir(); + + // find generic associated types in the given region 'lower_bound' + let gat_id_and_generics = self + .regioncx + .placeholders_contained_in(lower_bound) + .map(|placeholder| { + if let Some(id) = placeholder.name.get_id() + && let Some(placeholder_id) = id.as_local() + && let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id) + && let Some(generics_impl) = hir.get_parent(gat_hir_id).generics() + { + Some((gat_hir_id, generics_impl)) + } else { + None + } + }) + .collect::>(); + debug!(?gat_id_and_generics); + + // find higher-ranked trait bounds bounded to the generic associated types + let mut hrtb_bounds = vec![]; + gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| { + for pred in generics.predicates { + let BoundPredicate( + WhereBoundPredicate { + bound_generic_params, + bounds, + .. + }) = pred else { continue; }; + if bound_generic_params + .iter() + .rfind(|bgp| hir.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id) + .is_some() + { + for bound in *bounds { + hrtb_bounds.push(bound); + } + } + } + }); + debug!(?hrtb_bounds); + + hrtb_bounds.iter().for_each(|bound| { + let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { return; }; + diag.span_note( + *trait_span, + format!("due to current limitations in the borrow checker, this implies a `'static` lifetime") + ); + let Some(generics_fn) = hir.get_generics(self.body.source.def_id().expect_local()) else { return; }; + let Def(_, trait_res_defid) = trait_ref.path.res else { return; }; + debug!(?generics_fn); + generics_fn.predicates.iter().for_each(|predicate| { + let BoundPredicate( + WhereBoundPredicate { + span: bounded_span, + bounded_ty, + bounds, + .. + } + ) = predicate else { return; }; + bounds.iter().for_each(|bd| { + if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }, _) = bd + && let Def(_, res_defid) = tr_ref.path.res + && res_defid == trait_res_defid // trait id matches + && let TyKind::Path(Resolved(_, path)) = bounded_ty.kind + && let Def(_, defid) = path.res + && generics_fn.params + .iter() + .rfind(|param| param.def_id.to_def_id() == defid) + .is_some() { + suggestions.push((bounded_span.shrink_to_hi(), format!(" + 'static"))); + } + }); + }); + }); + if suggestions.len() > 0 { + suggestions.dedup(); + diag.multipart_suggestion_verbose( + format!("consider restricting the type parameter to the `'static` lifetime"), + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + /// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`. pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) { // Iterate through all the errors, producing a diagnostic for each one. The diagnostics are // buffered in the `MirBorrowckCtxt`. let mut outlives_suggestion = OutlivesSuggestionBuilder::default(); + let mut last_unexpected_hidden_region: Option<(Span, Ty<'_>, ty::OpaqueTypeKey<'tcx>)> = + None; for nll_error in nll_errors.into_iter() { match nll_error { @@ -203,12 +323,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // to report it; we could probably handle it by // iterating over the universal regions and reporting // an error that multiple bounds are required. - self.buffer_error(self.infcx.tcx.sess.create_err( - GenericDoesNotLiveLongEnough { + let mut diag = + self.infcx.tcx.sess.create_err(GenericDoesNotLiveLongEnough { kind: type_test.generic_kind.to_string(), span: type_test_span, - }, - )); + }); + + // Add notes and suggestions for the case of 'static lifetime + // implied but not specified when a generic associated types + // are from higher-ranked trait bounds + self.suggest_static_lifetime_for_gat_from_hrtb( + &mut diag, + type_test.lower_bound, + ); + + self.buffer_error(diag); } } @@ -216,13 +345,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); let named_key = self.regioncx.name_regions(self.infcx.tcx, key); let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); - self.buffer_error(unexpected_hidden_region_diagnostic( + let mut diag = unexpected_hidden_region_diagnostic( self.infcx.tcx, span, named_ty, named_region, named_key, - )); + ); + if last_unexpected_hidden_region != Some((span, named_ty, named_key)) { + self.buffer_error(diag); + last_unexpected_hidden_region = Some((span, named_ty, named_key)); + } else { + diag.delay_as_bug(); + } } RegionErrorKind::BoundUniversalRegionError { @@ -273,71 +408,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { outlives_suggestion.add_suggestion(self); } - fn get_impl_ident_and_self_ty_from_trait( - &self, - def_id: DefId, - trait_objects: &FxIndexSet, - ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> { - let tcx = self.infcx.tcx; - match tcx.hir().get_if_local(def_id) { - Some(Node::ImplItem(impl_item)) => { - match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id) - { - Some(Node::Item(Item { - kind: ItemKind::Impl(hir::Impl { self_ty, .. }), - .. - })) => Some((impl_item.ident, self_ty)), - _ => None, - } - } - Some(Node::TraitItem(trait_item)) => { - let trait_did = tcx.hir().get_parent_item(trait_item.hir_id()); - match tcx.hir().find_by_def_id(trait_did.def_id) { - Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => { - // The method being called is defined in the `trait`, but the `'static` - // obligation comes from the `impl`. Find that `impl` so that we can point - // at it in the suggestion. - let trait_did = trait_did.to_def_id(); - match tcx - .hir() - .trait_impls(trait_did) - .iter() - .filter_map(|&impl_did| { - match tcx.hir().get_if_local(impl_did.to_def_id()) { - Some(Node::Item(Item { - kind: ItemKind::Impl(hir::Impl { self_ty, .. }), - .. - })) if trait_objects.iter().all(|did| { - // FIXME: we should check `self_ty` against the receiver - // type in the `UnifyReceiver` context, but for now, use - // this imperfect proxy. This will fail if there are - // multiple `impl`s for the same trait like - // `impl Foo for Box` and `impl Foo for dyn Bar`. - // In that case, only the first one will get suggestions. - let mut traits = vec![]; - let mut hir_v = HirTraitObjectVisitor(&mut traits, *did); - hir_v.visit_ty(self_ty); - !traits.is_empty() - }) => - { - Some(self_ty) - } - _ => None, - } - }) - .next() - { - Some(self_ty) => Some((trait_item.ident, self_ty)), - _ => None, - } - } - _ => None, - } - } - _ => None, - } - } - /// Report an error because the universal region `fr` was required to outlive /// `outlived_fr` but it is not known to do so. For example: /// @@ -461,7 +531,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); (desc, note) } - _ => panic!("Unexpected type {:?}", ty), + _ => panic!("Unexpected type {ty:?}"), }; diag.note(&format!("requirement occurs because of {desc}",)); diag.note(¬e); @@ -472,7 +542,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { for extra in extra_info { match extra { ExtraConstraintInfo::PlaceholderFromPredicate(span) => { - diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime")); + diag.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); } } } @@ -504,7 +574,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let ErrorConstraintInfo { outlived_fr, span, .. } = errci; let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; - if let ty::Opaque(def_id, _) = *output_ty.kind() { + if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *output_ty.kind() { output_ty = self.infcx.tcx.type_of(def_id) }; @@ -764,10 +834,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let lifetime = if f.has_name() { fr_name.name } else { kw::UnderscoreLifetime }; let arg = match param.param.pat.simple_ident() { - Some(simple_ident) => format!("argument `{}`", simple_ident), + Some(simple_ident) => format!("argument `{simple_ident}`"), None => "the argument".to_string(), }; - let captures = format!("captures data from {}", arg); + let captures = format!("captures data from {arg}"); return nice_region_error::suggest_new_region_bound( self.infcx.tcx, @@ -777,6 +847,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Some(arg), captures, Some((param.param_ty_span, param.param_ty.to_string())), + self.infcx.tcx.is_suitable_region(f).map(|r| r.def_id), ); } } @@ -832,7 +903,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { visitor.visit_ty(param.param_ty); let Some((ident, self_ty)) = - self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &visitor.0) else {return}; + NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &visitor.0) else { return; }; self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty); } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 171e62d91..9233287cf 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -200,9 +200,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// increment the counter. /// /// This is _not_ idempotent. Call `give_region_a_name` when possible. - fn synthesize_region_name(&self) -> Symbol { + pub(crate) fn synthesize_region_name(&self) -> Symbol { let c = self.next_region_name.replace_with(|counter| *counter + 1); - Symbol::intern(&format!("'{:?}", c)) + Symbol::intern(&format!("'{c:?}")) } /// Maps from an internal MIR region vid to something that we can @@ -493,10 +493,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { // // & // - let's call the lifetime of this reference `'1` - ( - ty::Ref(region, referent_ty, _), - hir::TyKind::Rptr(_lifetime, referent_hir_ty), - ) => { + (ty::Ref(region, referent_ty, _), hir::TyKind::Ref(_lifetime, referent_hir_ty)) => { if region.to_region_vid() == needle_fr { // Just grab the first character, the `&`. let source_map = self.infcx.tcx.sess.source_map(); @@ -622,7 +619,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { // programs, so we need to use delay_span_bug here. See #82126. self.infcx.tcx.sess.delay_span_bug( hir_arg.span(), - &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg), + &format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"), ); } } @@ -786,8 +783,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } else { span_bug!( hir_ty.span, - "bounds from lowered return type of async fn did not match expected format: {:?}", - opaque_ty + "bounds from lowered return type of async fn did not match expected format: {opaque_ty:?}", ); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index b385f95b6..ada3310d8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -18,7 +18,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { upvars: &[Upvar<'tcx>], fr: RegionVid, ) -> Option<(Option, Span)> { - debug!("get_var_name_and_span_for_region(fr={:?})", fr); + debug!("get_var_name_and_span_for_region(fr={fr:?})"); assert!(self.universal_regions().is_universal_region(fr)); debug!("get_var_name_and_span_for_region: attempting upvar"); @@ -44,10 +44,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Option { let upvar_index = self.universal_regions().defining_ty.upvar_tys().position(|upvar_ty| { - debug!("get_upvar_index_for_region: upvar_ty={:?}", upvar_ty); + debug!("get_upvar_index_for_region: upvar_ty={upvar_ty:?}"); tcx.any_free_region_meets(&upvar_ty, |r| { let r = r.to_region_vid(); - debug!("get_upvar_index_for_region: r={:?} fr={:?}", r, fr); + debug!("get_upvar_index_for_region: r={r:?} fr={fr:?}"); r == fr }) })?; @@ -55,8 +55,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let upvar_ty = self.universal_regions().defining_ty.upvar_tys().nth(upvar_index); debug!( - "get_upvar_index_for_region: found {:?} in upvar {} which has type {:?}", - fr, upvar_index, upvar_ty, + "get_upvar_index_for_region: found {fr:?} in upvar {upvar_index} which has type {upvar_ty:?}", ); Some(upvar_index) @@ -71,13 +70,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { upvar_index: usize, ) -> (Symbol, Span) { let upvar_hir_id = upvars[upvar_index].place.get_root_variable(); - debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id); + debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}"); let upvar_name = tcx.hir().name(upvar_hir_id); let upvar_span = tcx.hir().span(upvar_hir_id); debug!( - "get_upvar_name_and_span_for_region: upvar_name={:?} upvar_span={:?}", - upvar_name, upvar_span + "get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}", ); (upvar_name, upvar_span) @@ -97,15 +95,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { let argument_index = self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position( |arg_ty| { - debug!("get_argument_index_for_region: arg_ty = {:?}", arg_ty); + debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}"); tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr) }, )?; debug!( - "get_argument_index_for_region: found {:?} in argument {} which has type {:?}", - fr, - argument_index, + "get_argument_index_for_region: found {fr:?} in argument {argument_index} which has type {:?}", self.universal_regions().unnormalized_input_tys[argument_index], ); @@ -122,13 +118,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> (Option, Span) { let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs(); let argument_local = Local::new(implicit_inputs + argument_index + 1); - debug!("get_argument_name_and_span_for_region: argument_local={:?}", argument_local); + debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}"); let argument_name = local_names[argument_local]; let argument_span = body.local_decls[argument_local].source_info.span; debug!( - "get_argument_name_and_span_for_region: argument_name={:?} argument_span={:?}", - argument_name, argument_span + "get_argument_name_and_span_for_region: argument_name={argument_name:?} argument_span={argument_span:?}", ); (argument_name, argument_span) -- cgit v1.2.3