Rollup merge of #104055 - AndyJado:bck_errors, r=davidtwco

Migrate diagnostics in `rustc_borrowck`

sorry for making a new PR, [#103559](https://github.com/rust-lang/rust/pull/103559) and [#103960](https://github.com/rust-lang/rust/pull/103960).

I am crawling, joyfully.
This commit is contained in:
Matthias Krüger 2023-04-17 18:13:33 +02:00 committed by GitHub
commit 91fe117418
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 612 additions and 252 deletions

View file

@ -56,18 +56,6 @@ borrowck_returned_lifetime_short =
borrowck_used_impl_require_static =
the used `impl` has a `'static` requirement
borrowck_capture_kind_label =
capture is {$kind_desc} because of use here
borrowck_var_borrow_by_use_place_in_generator =
borrow occurs due to use of {$place} in closure in generator
borrowck_var_borrow_by_use_place_in_closure =
borrow occurs due to use of {$place} in closure
borrowck_var_borrow_by_use_place =
borrow occurs due to use of {$place}
borrowck_borrow_due_to_use_generator =
borrow occurs due to use in generator
@ -101,12 +89,63 @@ borrowck_capture_mut =
borrowck_capture_move =
capture is moved because of use here
borrowck_var_borrow_by_use_place_in_generator =
{$is_single_var ->
*[true] borrow occurs
[false] borrows occur
} due to use of {$place} in generator
borrowck_var_borrow_by_use_place_in_closure =
{$is_single_var ->
*[true] borrow occurs
[false] borrows occur
} due to use of {$place} in closure
borrowck_var_borrow_by_use_in_generator =
borrow occurs due to use in generator
borrowck_var_borrow_by_use_in_closure =
borrow occurs due to use in closure
borrowck_var_move_by_use_place_in_generator =
move occurs due to use of {$place} in generator
borrowck_var_move_by_use_place_in_closure =
move occurs due to use of {$place} in closure
borrowck_var_move_by_use_in_generator =
move occurs due to use in generator
borrowck_var_move_by_use_in_closure =
move occurs due to use in closure
borrowck_partial_var_move_by_use_in_generator =
variable {$is_partial ->
[true] partially moved
*[false] moved
} due to use in generator
borrowck_partial_var_move_by_use_in_closure =
variable {$is_partial ->
[true] partially moved
*[false] moved
} due to use in closure
borrowck_var_first_borrow_by_use_place_in_generator =
first borrow occurs due to use of {$place} in generator
borrowck_var_first_borrow_by_use_place_in_closure =
first borrow occurs due to use of {$place} in closure
borrowck_var_second_borrow_by_use_place_in_generator =
second borrow occurs due to use of {$place} in generator
borrowck_var_second_borrow_by_use_place_in_closure =
second borrow occurs due to use of {$place} in closure
borrowck_var_mutable_borrow_by_use_place_in_closure =
mutable borrow occurs due to use of {$place} in closure
borrowck_cannot_move_when_borrowed =
cannot move out of {$place ->
[value] value
@ -127,3 +166,90 @@ borrowck_opaque_type_non_generic_param =
[true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
*[other] this generic parameter must be used with a generic {$kind} parameter
}
borrowck_moved_due_to_call =
{$place_name} {$is_partial ->
[true] partially moved
*[false] moved
} due to this {$is_loop_message ->
[true] call, in previous iteration of loop
*[false] call
}
borrowck_moved_due_to_usage_in_operator =
{$place_name} {$is_partial ->
[true] partially moved
*[false] moved
} due to usage in {$is_loop_message ->
[true] operator, in previous iteration of loop
*[false] operator
}
borrowck_moved_due_to_implicit_into_iter_call =
{$place_name} {$is_partial ->
[true] partially moved
*[false] moved
} due to this implicit call to {$is_loop_message ->
[true] `.into_iter()`, in previous iteration of loop
*[false] `.into_iter()`
}
borrowck_moved_due_to_method_call =
{$place_name} {$is_partial ->
[true] partially moved
*[false] moved
} due to this method {$is_loop_message ->
[true] call, in previous iteration of loop
*[false] call
}
borrowck_value_moved_here =
value {$is_partial ->
[true] partially moved
*[false] moved
} {$is_move_msg ->
[true] into closure here
*[false] here
}{$is_loop_message ->
[true] , in previous iteration of loop
*[false] {""}
}
borrowck_consider_borrow_type_contents =
help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
borrowck_moved_a_fn_once_in_call =
this value implements `FnOnce`, which causes it to be moved when called
borrowck_calling_operator_moves_lhs =
calling this operator moves the left-hand side
borrowck_func_take_self_moved_place =
`{$func}` takes ownership of the receiver `self`, which moves {$place_name}
borrowck_suggest_iterate_over_slice =
consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
borrowck_suggest_create_freash_reborrow =
consider reborrowing the `Pin` instead of moving it
borrowck_value_capture_here =
value captured {$is_within ->
[true] here by generator
*[false] here
}
borrowck_move_out_place_here =
{$place} is moved here
borrowck_closure_invoked_twice =
closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment
borrowck_closure_moved_twice =
closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment
borrowck_ty_no_impl_copy =
{$is_partial_move ->
[true] partial move
*[false] move
} occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait

View file

@ -30,8 +30,8 @@ use crate::borrow_set::TwoPhaseActivation;
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::diagnostics::{find_all_local_uses, CapturedMessageOpt};
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
@ -183,13 +183,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
let move_span = move_spans.args_or_use();
let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
let is_move_msg = move_spans.for_closure();
let loop_message = if location == move_out.source || move_site.traversed_back_edge {
", in previous iteration of loop"
} else {
""
};
let is_loop_message = location == move_out.source || move_site.traversed_back_edge;
if location == move_out.source {
is_loop_move = true;
@ -206,17 +202,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
let msg_opt = CapturedMessageOpt {
is_partial_move,
is_loop_message,
is_move_msg,
is_loop_move,
maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations
.is_empty(),
};
self.explain_captures(
&mut err,
span,
move_span,
move_spans,
*moved_place,
partially_str,
loop_message,
move_msg,
is_loop_move,
maybe_reinitialized_locations.is_empty(),
msg_opt,
);
}
seen_spans.insert(move_span);
@ -282,12 +282,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
if needs_note {
let span = if let Some(local) = place.as_local() {
Some(self.body.local_decls[local].source_info.span)
if let Some(local) = place.as_local() {
let span = self.body.local_decls[local].source_info.span;
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move,
ty,
place: &note_msg,
span,
});
} else {
None
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
is_partial_move,
ty,
place: &note_msg,
});
};
self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span, partial_str);
}
if let UseSpans::FnSelfUse {
@ -827,11 +836,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow);
move_spans.var_span_label(
&mut err,
format!("move occurs due to use{}", move_spans.describe()),
"moved",
);
move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
Some(_) => MoveUseInGenerator { var_span },
None => MoveUseInClosure { var_span },
}
});
self.explain_why_borrow_contains_point(location, borrow, None)
.add_explanation_to_diagnostic(
@ -868,13 +879,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_span,
&self.describe_any_place(borrow.borrowed_place.as_ref()),
);
borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {
borrow_spans.var_subdiag(None, &mut err, Some(borrow.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
let place = &borrow.borrowed_place;
let desc_place = self.describe_any_place(place.as_ref());
match kind {
Some(_) => BorrowUsePlaceGenerator { place: desc_place, var_span },
None => BorrowUsePlaceClosure { place: desc_place, var_span },
Some(_) => {
BorrowUsePlaceGenerator { place: desc_place, var_span, is_single_var: true }
}
None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true },
}
});
@ -988,16 +1001,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
immutable_section_description,
"mutably borrow",
);
borrow_spans.var_span_label(
borrow_spans.var_subdiag(
None,
&mut err,
format!(
"borrow occurs due to use of {}{}",
desc_place,
borrow_spans.describe(),
),
"immutable",
Some(BorrowKind::Unique),
|kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
Some(_) => BorrowUsePlaceGenerator {
place: desc_place,
var_span,
is_single_var: true,
},
None => BorrowUsePlaceClosure {
place: desc_place,
var_span,
is_single_var: true,
},
}
},
);
return err;
} else {
first_borrow_desc = "immutable ";
@ -1070,32 +1093,48 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
};
if issued_spans == borrow_spans {
borrow_spans.var_span_label(
&mut err,
format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
gen_borrow_kind.describe_mutability(),
);
borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
Some(_) => BorrowUsePlaceGenerator {
place: desc_place,
var_span,
is_single_var: false,
},
None => {
BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
}
}
});
} else {
let borrow_place = &issued_borrow.borrowed_place;
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
issued_spans.var_span_label(
issued_spans.var_subdiag(
Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic),
&mut err,
format!(
"first borrow occurs due to use of {}{}",
borrow_place_desc,
issued_spans.describe(),
),
issued_borrow.kind.describe_mutability(),
Some(issued_borrow.kind),
|kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
let borrow_place = &issued_borrow.borrowed_place;
let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
match kind {
Some(_) => {
FirstBorrowUsePlaceGenerator { place: borrow_place_desc, var_span }
}
None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span },
}
},
);
borrow_spans.var_span_label(
borrow_spans.var_subdiag(
Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic),
&mut err,
format!(
"second borrow occurs due to use of {}{}",
desc_place,
borrow_spans.describe(),
),
gen_borrow_kind.describe_mutability(),
Some(gen_borrow_kind),
|kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
Some(_) => SecondBorrowUsePlaceGenerator { place: desc_place, var_span },
None => SecondBorrowUsePlaceClosure { place: desc_place, var_span },
}
},
);
}
@ -1731,9 +1770,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
let within = if borrow_spans.for_generator() { " by generator" } else { "" };
borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
borrow_spans.args_subdiag(&mut err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::Capture {
is_within: borrow_spans.for_generator(),
args_span,
}
});
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
@ -1947,9 +1989,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
);
let within = if borrow_spans.for_generator() { " by generator" } else { "" };
borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
borrow_spans.args_subdiag(&mut err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::Capture {
is_within: borrow_spans.for_generator(),
args_span,
}
});
err
}
@ -2382,11 +2427,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
section,
"assign",
);
loan_spans.var_span_label(
&mut err,
format!("borrow occurs due to use{}", loan_spans.describe()),
loan.kind.describe_mutability(),
);
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
Some(_) => BorrowUseInGenerator { var_span },
None => BorrowUseInClosure { var_span },
}
});
self.buffer_error(err);
@ -2396,11 +2444,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
loan_spans.var_span_label(
&mut err,
format!("borrow occurs due to use{}", loan_spans.describe()),
loan.kind.describe_mutability(),
);
loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
Some(_) => BorrowUseInGenerator { var_span },
None => BorrowUseInClosure { var_span },
}
});
self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
self.infcx.tcx,

View file

@ -1,5 +1,9 @@
//! Borrow checker diagnostics.
use crate::session_diagnostics::{
CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
};
use itertools::Itertools;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
@ -117,13 +121,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.span_note(
*span,
&format!(
"closure cannot be invoked more than once because it moves the \
variable `{}` out of its environment",
ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
),
diag.eager_subdiagnostic(
&self.infcx.tcx.sess.parse_sess.span_diagnostic,
OnClosureNote::InvokedTwice {
place_name: &ty::place_to_string_for_capture(
self.infcx.tcx,
hir_place,
),
span: *span,
},
);
return true;
}
@ -137,13 +143,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.span_note(
*span,
&format!(
"closure cannot be moved more than once as it is not `Copy` due to \
moving the variable `{}` out of its environment",
ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
),
diag.eager_subdiagnostic(
&self.infcx.tcx.sess.parse_sess.span_diagnostic,
OnClosureNote::MovedTwice {
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
span: *span,
},
);
return true;
}
@ -380,25 +385,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
/// Add a note that a type does not implement `Copy`
pub(super) fn note_type_does_not_implement_copy(
&self,
err: &mut Diagnostic,
place_desc: &str,
ty: Ty<'tcx>,
span: Option<Span>,
move_prefix: &str,
) {
let message = format!(
"{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);
} else {
err.note(&message);
}
}
pub(super) fn borrowed_content_source(
&self,
deref_base: PlaceRef<'tcx>,
@ -582,9 +568,13 @@ impl UseSpans<'_> {
}
/// Add a span label to the arguments of the closure, if it exists.
pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<String>) {
pub(super) fn args_subdiag(
self,
err: &mut Diagnostic,
f: impl FnOnce(Span) -> CaptureArgLabel,
) {
if let UseSpans::ClosureUse { args_span, .. } = self {
err.span_label(args_span, message);
err.subdiagnostic(f(args_span));
}
}
@ -595,8 +585,8 @@ impl UseSpans<'_> {
err: &mut Diagnostic,
action: crate::InitializationRequiringAction,
) {
use crate::session_diagnostics::CaptureVarPathUseCause::*;
use crate::InitializationRequiringAction::*;
use CaptureVarPathUseCause::*;
if let UseSpans::ClosureUse { generator_kind, path_span, .. } = self {
match generator_kind {
Some(_) => {
@ -619,34 +609,14 @@ impl UseSpans<'_> {
}
}
/// Add a span label to the use of the captured variable, if it exists.
pub(super) fn var_span_label(
self,
err: &mut Diagnostic,
message: impl Into<String>,
kind_desc: impl Into<String>,
) {
if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
if capture_kind_span == path_span {
err.span_label(capture_kind_span, message);
} else {
let capture_kind_label =
format!("capture is {} because of use here", kind_desc.into());
let path_label = message;
err.span_label(capture_kind_span, capture_kind_label);
err.span_label(path_span, path_label);
}
}
}
/// Add a subdiagnostic to the use of the captured variable, if it exists.
pub(super) fn var_subdiag(
self,
handler: Option<&rustc_errors::Handler>,
err: &mut Diagnostic,
kind: Option<rustc_middle::mir::BorrowKind>,
f: impl Fn(Option<GeneratorKind>, Span) -> crate::session_diagnostics::CaptureVarCause,
f: impl FnOnce(Option<GeneratorKind>, Span) -> CaptureVarCause,
) {
use crate::session_diagnostics::CaptureVarKind::*;
if let UseSpans::ClosureUse { generator_kind, capture_kind_span, path_span, .. } = self {
if capture_kind_span != path_span {
err.subdiagnostic(match kind {
@ -654,17 +624,21 @@ impl UseSpans<'_> {
rustc_middle::mir::BorrowKind::Shared
| rustc_middle::mir::BorrowKind::Shallow
| rustc_middle::mir::BorrowKind::Unique => {
Immute { kind_span: capture_kind_span }
CaptureVarKind::Immut { kind_span: capture_kind_span }
}
rustc_middle::mir::BorrowKind::Mut { .. } => {
Mut { kind_span: capture_kind_span }
CaptureVarKind::Mut { kind_span: capture_kind_span }
}
},
None => Move { kind_span: capture_kind_span },
None => CaptureVarKind::Move { kind_span: capture_kind_span },
});
};
err.subdiagnostic(f(generator_kind, path_span));
let diag = f(generator_kind, path_span);
match handler {
Some(hd) => err.eager_subdiagnostic(hd, diag),
None => err.subdiagnostic(diag),
};
}
}
@ -684,20 +658,6 @@ impl UseSpans<'_> {
}
}
/// Describe the span associated with a use of a place.
pub(super) fn describe(&self) -> &str {
match *self {
UseSpans::ClosureUse { generator_kind, .. } => {
if generator_kind.is_some() {
" in generator"
} else {
" in closure"
}
}
_ => "",
}
}
pub(super) fn or_else<F>(self, if_other: F) -> Self
where
F: FnOnce() -> Self,
@ -788,6 +748,15 @@ impl<'tcx> BorrowedContentSource<'tcx> {
}
}
///helper struct for explain_captures()
struct CapturedMessageOpt {
is_partial_move: bool,
is_loop_message: bool,
is_move_msg: bool,
is_loop_move: bool,
maybe_reinitialized_locations_is_empty: bool,
}
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Finds the spans associated to a move or copy of move_place at location.
pub(super) fn move_spans(
@ -1027,12 +996,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_span: Span,
move_spans: UseSpans<'tcx>,
moved_place: Place<'tcx>,
partially_str: &str,
loop_message: &str,
move_msg: &str,
is_loop_move: bool,
maybe_reinitialized_locations_is_empty: bool,
msg_opt: CapturedMessageOpt,
) {
let CapturedMessageOpt {
is_partial_move: is_partial,
is_loop_message,
is_move_msg,
is_loop_move,
maybe_reinitialized_locations_is_empty,
} = msg_opt;
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
let place_name = self
.describe_place(moved_place.as_ref())
@ -1042,30 +1014,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
CallKind::FnCall { fn_trait_id, .. }
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
{
err.span_label(
err.subdiagnostic(CaptureReasonLabel::Call {
fn_call_span,
&format!(
"{place_name} {partially_str}moved due to this call{loop_message}",
),
);
err.span_note(
var_span,
"this value implements `FnOnce`, which causes it to be moved when called",
);
place_name: &place_name,
is_partial,
is_loop_message,
});
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
}
CallKind::Operator { self_arg, .. } => {
let self_arg = self_arg.unwrap();
err.span_label(
err.subdiagnostic(CaptureReasonLabel::OperatorUse {
fn_call_span,
&format!(
"{place_name} {partially_str}moved due to usage in operator{loop_message}",
),
);
place_name: &place_name,
is_partial,
is_loop_message,
});
if self.fn_self_span_reported.insert(fn_span) {
err.span_note(
self_arg.span,
"calling this operator moves the left-hand side",
);
err.subdiagnostic(CaptureReasonNote::LhsMoveByOperator {
span: self_arg.span,
});
}
}
CallKind::Normal { self_arg, desugaring, method_did, method_substs } => {
@ -1086,23 +1054,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
_ => false,
};
if suggest {
err.span_suggestion_verbose(
move_span.shrink_to_lo(),
&format!(
"consider iterating over a slice of the `{ty}`'s content to \
avoid moving into the `for` loop",
),
"&",
Applicability::MaybeIncorrect,
);
err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
ty,
span: move_span.shrink_to_lo(),
});
}
err.span_label(
err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
fn_call_span,
&format!(
"{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}",
),
);
place_name: &place_name,
is_partial,
is_loop_message,
});
// If the moved place was a `&mut` ref, then we can
// suggest to reborrow it where it was moved, so it
// will still be valid by the time we get to the usage.
@ -1125,13 +1088,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
} else {
err.span_label(
err.subdiagnostic(CaptureReasonLabel::MethodCall {
fn_call_span,
&format!(
"{place_name} {partially_str}moved due to this method call{loop_message}",
),
);
place_name: &place_name,
is_partial,
is_loop_message,
});
let infcx = tcx.infer_ctxt().build();
// Erase and shadow everything that could be passed to the new infcx.
let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
@ -1147,12 +1109,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
)
&& infcx.can_eq(self.param_env, ty, self_ty)
{
err.span_suggestion_verbose(
fn_call_span.shrink_to_lo(),
"consider reborrowing the `Pin` instead of moving it",
"as_mut().".to_string(),
Applicability::MaybeIncorrect,
);
err.eager_subdiagnostic(
&self.infcx.tcx.sess.parse_sess.span_diagnostic,
CaptureReasonSuggest::FreshReborrow {
span: fn_call_span.shrink_to_lo(),
});
}
if let Some(clone_trait) = tcx.lang_items().clone_trait()
&& let trait_ref = tcx.mk_trait_ref(clone_trait, [ty])
@ -1177,10 +1138,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// 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!("`{func}` takes ownership of the receiver `self`, which moves {place_name}")
);
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
func,
place_name,
span: self_arg.span,
});
}
let parent_did = tcx.parent(method_did);
let parent_self_ty =
@ -1194,30 +1156,28 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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,
"help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents",
);
err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
}
}
// Other desugarings takes &self, which cannot cause a move
_ => {}
}
} else {
if move_span != span || !loop_message.is_empty() {
err.span_label(
if move_span != span || is_loop_message {
err.subdiagnostic(CaptureReasonLabel::MovedHere {
move_span,
format!("value {partially_str}moved{move_msg} here{loop_message}"),
);
is_partial,
is_move_msg,
is_loop_message,
});
}
// If the move error occurs due to a loop, don't show
// another message for the same span
if loop_message.is_empty() {
move_spans.var_span_label(
err,
format!("variable {partially_str}moved due to use{}", move_spans.describe()),
"moved",
);
if !is_loop_message {
move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
Some(_) => CaptureVarCause::PartialMoveUseInGenerator { var_span, is_partial },
None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial },
})
}
}
}

View file

@ -6,6 +6,7 @@ use rustc_mir_dataflow::move_paths::{
};
use rustc_span::{BytePos, Span};
use crate::diagnostics::CapturedMessageOpt;
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
@ -397,10 +398,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
};
let msg_opt = CapturedMessageOpt {
is_partial_move: false,
is_loop_message: false,
is_move_msg: false,
is_loop_move: false,
maybe_reinitialized_locations_is_empty: true,
};
if let Some(use_spans) = use_spans {
self.explain_captures(
&mut err, span, span, use_spans, move_place, "", "", "", false, true,
);
self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt);
}
err
}
@ -416,13 +422,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
None => "value".to_string(),
};
self.note_type_does_not_implement_copy(
err,
&place_desc,
place_ty,
Some(span),
"",
);
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty: place_ty,
place: &place_desc,
span,
});
} else {
binds_to.sort();
binds_to.dedup();
@ -444,9 +449,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Some(desc) => format!("`{desc}`"),
None => "value".to_string(),
};
self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty: place_ty,
place: &place_desc,
span,
});
use_spans.args_span_label(err, format!("{place_desc} is moved here"));
use_spans.args_subdiag(err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
place: place_desc,
args_span,
}
});
}
}
}
@ -534,13 +549,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
if binds_to.len() == 1 {
self.note_type_does_not_implement_copy(
err,
&format!("`{}`", self.local_names[*local].unwrap()),
bind_to.ty,
Some(binding_span),
"",
);
let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
is_partial_move: false,
ty: bind_to.ty,
place: &place_desc,
span: binding_span,
});
}
}

View file

@ -231,14 +231,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
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_spans.var_subdiag(
None,
&mut err,
Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }),
|_kind, var_span| {
let place = self.describe_any_place(access_place.as_ref());
crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
place,
var_span,
}
},
);
}
borrow_span
}

View file

@ -184,7 +184,7 @@ pub(crate) enum CaptureVarPathUseCause {
#[derive(Subdiagnostic)]
pub(crate) enum CaptureVarKind {
#[label(borrowck_capture_immute)]
Immute {
Immut {
#[primary_span]
kind_span: Span,
},
@ -204,16 +204,80 @@ pub(crate) enum CaptureVarKind {
pub(crate) enum CaptureVarCause {
#[label(borrowck_var_borrow_by_use_place_in_generator)]
BorrowUsePlaceGenerator {
is_single_var: bool,
place: String,
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_borrow_by_use_place_in_closure)]
BorrowUsePlaceClosure {
is_single_var: bool,
place: String,
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_borrow_by_use_in_generator)]
BorrowUseInGenerator {
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_borrow_by_use_in_closure)]
BorrowUseInClosure {
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_move_by_use_in_generator)]
MoveUseInGenerator {
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_move_by_use_in_closure)]
MoveUseInClosure {
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_first_borrow_by_use_place_in_generator)]
FirstBorrowUsePlaceGenerator {
place: String,
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_first_borrow_by_use_place_in_closure)]
FirstBorrowUsePlaceClosure {
place: String,
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_second_borrow_by_use_place_in_generator)]
SecondBorrowUsePlaceGenerator {
place: String,
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_second_borrow_by_use_place_in_closure)]
SecondBorrowUsePlaceClosure {
place: String,
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_mutable_borrow_by_use_place_in_closure)]
MutableBorrowUsePlaceClosure {
place: String,
#[primary_span]
var_span: Span,
},
#[label(borrowck_partial_var_move_by_use_in_generator)]
PartialMoveUseInGenerator {
#[primary_span]
var_span: Span,
is_partial: bool,
},
#[label(borrowck_partial_var_move_by_use_in_closure)]
PartialMoveUseInClosure {
#[primary_span]
var_span: Span,
is_partial: bool,
},
}
#[derive(Diagnostic)]
@ -239,3 +303,144 @@ pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
#[label]
pub param_span: Span,
}
#[derive(Subdiagnostic)]
pub(crate) enum CaptureReasonLabel<'a> {
#[label(borrowck_moved_due_to_call)]
Call {
#[primary_span]
fn_call_span: Span,
place_name: &'a str,
is_partial: bool,
is_loop_message: bool,
},
#[label(borrowck_moved_due_to_usage_in_operator)]
OperatorUse {
#[primary_span]
fn_call_span: Span,
place_name: &'a str,
is_partial: bool,
is_loop_message: bool,
},
#[label(borrowck_moved_due_to_implicit_into_iter_call)]
ImplicitCall {
#[primary_span]
fn_call_span: Span,
place_name: &'a str,
is_partial: bool,
is_loop_message: bool,
},
#[label(borrowck_moved_due_to_method_call)]
MethodCall {
#[primary_span]
fn_call_span: Span,
place_name: &'a str,
is_partial: bool,
is_loop_message: bool,
},
#[label(borrowck_value_moved_here)]
MovedHere {
#[primary_span]
move_span: Span,
is_partial: bool,
is_move_msg: bool,
is_loop_message: bool,
},
#[label(borrowck_consider_borrow_type_contents)]
BorrowContent {
#[primary_span]
var_span: Span,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum CaptureReasonNote {
#[note(borrowck_moved_a_fn_once_in_call)]
FnOnceMoveInCall {
#[primary_span]
var_span: Span,
},
#[note(borrowck_calling_operator_moves_lhs)]
LhsMoveByOperator {
#[primary_span]
span: Span,
},
#[note(borrowck_func_take_self_moved_place)]
FuncTakeSelf {
func: String,
place_name: String,
#[primary_span]
span: Span,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum CaptureReasonSuggest<'tcx> {
#[suggestion(
borrowck_suggest_iterate_over_slice,
applicability = "maybe-incorrect",
code = "&",
style = "verbose"
)]
IterateSlice {
ty: Ty<'tcx>,
#[primary_span]
span: Span,
},
#[suggestion(
borrowck_suggest_create_freash_reborrow,
applicability = "maybe-incorrect",
code = "as_mut().",
style = "verbose"
)]
FreshReborrow {
#[primary_span]
span: Span,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum CaptureArgLabel {
#[label(borrowck_value_capture_here)]
Capture {
is_within: bool,
#[primary_span]
args_span: Span,
},
#[label(borrowck_move_out_place_here)]
MoveOutPlace {
place: String,
#[primary_span]
args_span: Span,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum OnClosureNote<'a> {
#[note(borrowck_closure_invoked_twice)]
InvokedTwice {
place_name: &'a str,
#[primary_span]
span: Span,
},
#[note(borrowck_closure_moved_twice)]
MovedTwice {
place_name: &'a str,
#[primary_span]
span: Span,
},
}
#[derive(Subdiagnostic)]
pub(crate) enum TypeNoCopy<'a, 'tcx> {
#[label(borrowck_ty_no_impl_copy)]
Label {
is_partial_move: bool,
ty: Ty<'tcx>,
place: &'a str,
#[primary_span]
span: Span,
},
#[note(borrowck_ty_no_impl_copy)]
Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
}