Rollup merge of #80324 - Aaron1011:loop-move-fn-self, r=oli-obk
Explain method-call move errors in loops PR #73708 added a more detailed explanation of move errors that occur due to a call to a method that takes `self`. This PR extends that logic to work when a move error occurs due to a method call in the previous iteration of a loop.
This commit is contained in:
commit
8e6472fe32
15 changed files with 118 additions and 104 deletions
|
@ -151,95 +151,88 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
|
||||
|
||||
let loop_message = if location == move_out.source || move_site.traversed_back_edge {
|
||||
", in previous iteration of loop"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
if location == move_out.source {
|
||||
err.span_label(
|
||||
span,
|
||||
format!(
|
||||
"value {}moved{} here, in previous iteration of loop",
|
||||
partially_str, move_msg
|
||||
),
|
||||
);
|
||||
is_loop_move = true;
|
||||
} else if move_site.traversed_back_edge {
|
||||
}
|
||||
|
||||
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))
|
||||
.unwrap_or_else(|| "value".to_owned());
|
||||
match kind {
|
||||
FnSelfUseKind::FnOnceCall => {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this call{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
err.span_note(
|
||||
var_span,
|
||||
"this value implements `FnOnce`, which causes it to be moved when called",
|
||||
);
|
||||
}
|
||||
FnSelfUseKind::Operator { self_arg } => {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to usage in operator{}",
|
||||
place_name, partially_str, 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",
|
||||
);
|
||||
}
|
||||
}
|
||||
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
|
||||
if implicit_into_iter {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this implicit call to `.into_iter()`{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this method call{}",
|
||||
place_name, partially_str, loop_message
|
||||
),
|
||||
);
|
||||
}
|
||||
// Avoid pointing to the same function in multiple different
|
||||
// error messages
|
||||
if self.fn_self_span_reported.insert(self_arg.span) {
|
||||
err.span_note(
|
||||
self_arg.span,
|
||||
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
|
||||
);
|
||||
}
|
||||
}
|
||||
// Deref::deref takes &self, which cannot cause a move
|
||||
FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
err.span_label(
|
||||
move_span,
|
||||
format!(
|
||||
"value {}moved{} here, in previous iteration of loop",
|
||||
partially_str, move_msg
|
||||
),
|
||||
format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
|
||||
);
|
||||
} else {
|
||||
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))
|
||||
.unwrap_or_else(|| "value".to_owned());
|
||||
match kind {
|
||||
FnSelfUseKind::FnOnceCall => {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this call",
|
||||
place_name, partially_str
|
||||
),
|
||||
);
|
||||
err.span_note(
|
||||
var_span,
|
||||
"this value implements `FnOnce`, which causes it to be moved when called",
|
||||
);
|
||||
}
|
||||
FnSelfUseKind::Operator { self_arg } => {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to usage in operator",
|
||||
place_name, partially_str
|
||||
),
|
||||
);
|
||||
if self.fn_self_span_reported.insert(fn_span) {
|
||||
err.span_note(
|
||||
self_arg.span,
|
||||
"calling this operator moves the left-hand side",
|
||||
);
|
||||
}
|
||||
}
|
||||
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
|
||||
if implicit_into_iter {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this implicit call to `.into_iter()`",
|
||||
place_name, partially_str
|
||||
),
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
fn_call_span,
|
||||
&format!(
|
||||
"{} {}moved due to this method call",
|
||||
place_name, partially_str
|
||||
),
|
||||
);
|
||||
}
|
||||
// Avoid pointing to the same function in multiple different
|
||||
// error messages
|
||||
if self.fn_self_span_reported.insert(self_arg.span) {
|
||||
err.span_note(
|
||||
self_arg.span,
|
||||
&format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
|
||||
);
|
||||
}
|
||||
}
|
||||
// Deref::deref takes &self, which cannot cause a move
|
||||
FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
err.span_label(
|
||||
move_span,
|
||||
format!("value {}moved{} here", partially_str, move_msg),
|
||||
);
|
||||
// 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(
|
||||
&mut err,
|
||||
format!(
|
||||
|
@ -250,6 +243,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let UseSpans::PatUse(span) = move_spans {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue