diff options
Diffstat (limited to 'compiler/rustc_borrowck/src/diagnostics/move_errors.rs')
-rw-r--r-- | compiler/rustc_borrowck/src/diagnostics/move_errors.rs | 100 |
1 files changed, 64 insertions, 36 deletions
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", ); } } |