1
Fork 0

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:
Aaron Hill 2020-12-22 22:15:40 -05:00
parent ddf2cc7f8e
commit de90afc72e
No known key found for this signature in database
GPG key ID: B4087E510E98B164
4 changed files with 100 additions and 86 deletions

View file

@ -151,27 +151,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let move_msg = if move_spans.for_closure() { " into closure" } else { "" }; let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
if location == move_out.source { let loop_message = if location == move_out.source || move_site.traversed_back_edge {
err.span_label( ", in previous iteration of loop"
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 {
err.span_label(
move_span,
format!(
"value {}moved{} here, in previous iteration of loop",
partially_str, move_msg
),
);
} else { } else {
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = ""
move_spans };
{
if location == move_out.source {
is_loop_move = true;
}
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
let place_name = self let place_name = self
.describe_place(moved_place.as_ref()) .describe_place(moved_place.as_ref())
.map(|n| format!("`{}`", n)) .map(|n| format!("`{}`", n))
@ -181,8 +171,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label( err.span_label(
fn_call_span, fn_call_span,
&format!( &format!(
"{} {}moved due to this call", "{} {}moved due to this call{}",
place_name, partially_str place_name, partially_str, loop_message
), ),
); );
err.span_note( err.span_note(
@ -194,8 +184,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label( err.span_label(
fn_call_span, fn_call_span,
&format!( &format!(
"{} {}moved due to usage in operator", "{} {}moved due to usage in operator{}",
place_name, partially_str place_name, partially_str, loop_message
), ),
); );
if self.fn_self_span_reported.insert(fn_span) { if self.fn_self_span_reported.insert(fn_span) {
@ -210,16 +200,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label( err.span_label(
fn_call_span, fn_call_span,
&format!( &format!(
"{} {}moved due to this implicit call to `.into_iter()`", "{} {}moved due to this implicit call to `.into_iter()`{}",
place_name, partially_str place_name, partially_str, loop_message
), ),
); );
} else { } else {
err.span_label( err.span_label(
fn_call_span, fn_call_span,
&format!( &format!(
"{} {}moved due to this method call", "{} {}moved due to this method call{}",
place_name, partially_str place_name, partially_str, loop_message
), ),
); );
} }
@ -238,8 +228,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else { } else {
err.span_label( err.span_label(
move_span, move_span,
format!("value {}moved{} here", partially_str, move_msg), format!("value {}moved{} here{}", partially_str, move_msg, 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( move_spans.var_span_label(
&mut err, &mut err,
format!( format!(
@ -250,6 +243,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
); );
} }
} }
if let UseSpans::PatUse(span) = move_spans { if let UseSpans::PatUse(span) = move_spans {
err.span_suggestion_verbose( err.span_suggestion_verbose(
span.shrink_to_lo(), span.shrink_to_lo(),

View file

@ -69,6 +69,11 @@ fn move_out(val: Container) {
let container = Container(vec![]); let container = Container(vec![]);
for _val in container.custom_into_iter() {} for _val in container.custom_into_iter() {}
container; //~ ERROR use of moved container; //~ ERROR use of moved
let foo2 = Foo;
loop {
foo2.use_self(); //~ ERROR use of moved
}
} }
fn main() {} fn main() {}

View file

@ -152,7 +152,16 @@ note: this function consumes the receiver `self` by taking ownership of it, whic
LL | fn custom_into_iter(self) -> impl Iterator<Item = bool> { LL | fn custom_into_iter(self) -> impl Iterator<Item = bool> {
| ^^^^ | ^^^^
error: aborting due to 11 previous errors error[E0382]: use of moved value: `foo2`
--> $DIR/move-fn-self-receiver.rs:75:9
|
LL | let foo2 = Foo;
| ---- move occurs because `foo2` has type `Foo`, which does not implement the `Copy` trait
LL | loop {
LL | foo2.use_self();
| ^^^^ ---------- `foo2` moved due to this method call, in previous iteration of loop
error: aborting due to 12 previous errors
Some errors have detailed explanations: E0382, E0505. Some errors have detailed explanations: E0382, E0505.
For more information about an error, try `rustc --explain E0382`. For more information about an error, try `rustc --explain E0382`.

View file

@ -15,8 +15,14 @@ LL | for i in &a {
LL | for j in a { LL | for j in a {
| ^ | ^
| | | |
| value moved here, in previous iteration of loop | `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
| help: consider borrowing to avoid moving into the for loop: `&a` | help: consider borrowing to avoid moving into the for loop: `&a`
|
note: this function consumes the receiver `self` by taking ownership of it, which moves `a`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error: aborting due to 2 previous errors error: aborting due to 2 previous errors