Skip to content

Commit dcdbbd0

Browse files
authored
Rollup merge of #105476 - estebank:moves-n-borrows, r=compiler-errors
Change pattern borrowing suggestions to be verbose and remove invalid suggestion Synthesize a more accurate span and use verbose suggestion output to make the message clearer. Do not suggest borrowing binding in pattern in let else. Fix #104838.
2 parents 5e38e70 + cf0b6b9 commit dcdbbd0

File tree

73 files changed

+1842
-816
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+1842
-816
lines changed

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

+64-36
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_middle::ty;
44
use rustc_mir_dataflow::move_paths::{
55
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
66
};
7-
use rustc_span::Span;
7+
use rustc_span::{BytePos, Span};
88

99
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
1010
use crate::prefixes::PrefixSet;
@@ -148,7 +148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
148148
match_span: Span,
149149
statement_span: Span,
150150
) {
151-
debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span);
151+
debug!(?match_place, ?match_span, "append_binding_error");
152152

153153
let from_simple_let = match_place.is_none();
154154
let match_place = match_place.unwrap_or(move_from);
@@ -160,7 +160,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
160160
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge
161161
&& match_span == *span
162162
{
163-
debug!("appending local({:?}) to list", bind_to);
163+
debug!("appending local({bind_to:?}) to list");
164164
if !binds_to.is_empty() {
165165
binds_to.push(bind_to);
166166
}
@@ -198,7 +198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
198198
} = ge
199199
{
200200
if match_span == *span && mpi == *other_mpi {
201-
debug!("appending local({:?}) to list", bind_to);
201+
debug!("appending local({bind_to:?}) to list");
202202
binds_to.push(bind_to);
203203
return;
204204
}
@@ -410,15 +410,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
410410
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) {
411411
match error {
412412
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
413-
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
414-
err.span_suggestion(
415-
span,
416-
"consider borrowing here",
417-
format!("&{snippet}"),
418-
Applicability::Unspecified,
419-
);
420-
}
421-
413+
self.add_borrow_suggestions(err, span);
422414
if binds_to.is_empty() {
423415
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
424416
let place_desc = match self.describe_place(move_from.as_ref()) {
@@ -461,39 +453,75 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
461453
}
462454
}
463455

456+
fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) {
457+
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
458+
Ok(snippet) if snippet.starts_with('*') => {
459+
err.span_suggestion_verbose(
460+
span.with_hi(span.lo() + BytePos(1)),
461+
"consider removing the dereference here",
462+
String::new(),
463+
Applicability::MaybeIncorrect,
464+
);
465+
}
466+
_ => {
467+
err.span_suggestion_verbose(
468+
span.shrink_to_lo(),
469+
"consider borrowing here",
470+
"&".to_string(),
471+
Applicability::MaybeIncorrect,
472+
);
473+
}
474+
}
475+
}
476+
464477
fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
465-
let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
478+
let mut suggestions: Vec<(Span, String, String)> = Vec::new();
466479
for local in binds_to {
467480
let bind_to = &self.body.local_decls[*local];
468481
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
469482
VarBindingForm { pat_span, .. },
470483
)))) = bind_to.local_info
471484
{
472-
if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
485+
let Ok(pat_snippet) =
486+
self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };
487+
let Some(stripped) = pat_snippet.strip_prefix('&') else {
488+
suggestions.push((
489+
bind_to.source_info.span.shrink_to_lo(),
490+
"consider borrowing the pattern binding".to_string(),
491+
"ref ".to_string(),
492+
));
493+
continue;
494+
};
495+
let inner_pat_snippet = stripped.trim_start();
496+
let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut")
497+
&& inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
473498
{
474-
if let Some(stripped) = pat_snippet.strip_prefix('&') {
475-
let pat_snippet = stripped.trim_start();
476-
let (suggestion, to_remove) = if pat_snippet.starts_with("mut")
477-
&& pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
478-
{
479-
(pat_snippet["mut".len()..].trim_start(), "&mut")
480-
} else {
481-
(pat_snippet, "&")
482-
};
483-
suggestions.push((pat_span, to_remove, suggestion.to_owned()));
484-
}
485-
}
499+
let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start();
500+
let pat_span = pat_span.with_hi(
501+
pat_span.lo()
502+
+ BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32),
503+
);
504+
(pat_span, String::new(), "mutable borrow")
505+
} else {
506+
let pat_span = pat_span.with_hi(
507+
pat_span.lo()
508+
+ BytePos(
509+
(pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32,
510+
),
511+
);
512+
(pat_span, String::new(), "borrow")
513+
};
514+
suggestions.push((
515+
pat_span,
516+
format!("consider removing the {to_remove}"),
517+
suggestion.to_string(),
518+
));
486519
}
487520
}
488521
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
489522
suggestions.dedup_by_key(|&mut (span, _, _)| span);
490-
for (span, to_remove, suggestion) in suggestions {
491-
err.span_suggestion(
492-
span,
493-
&format!("consider removing the `{to_remove}`"),
494-
suggestion,
495-
Applicability::MachineApplicable,
496-
);
523+
for (span, msg, suggestion) in suggestions {
524+
err.span_suggestion_verbose(span, &msg, suggestion, Applicability::MachineApplicable);
497525
}
498526
}
499527

@@ -521,8 +549,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
521549

522550
if binds_to.len() > 1 {
523551
err.note(
524-
"move occurs because these variables have types that \
525-
don't implement the `Copy` trait",
552+
"move occurs because these variables have types that don't implement the `Copy` \
553+
trait",
526554
);
527555
}
528556
}

compiler/rustc_mir_build/src/build/block.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
231231
remainder_span,
232232
pattern,
233233
None,
234-
Some((None, initializer_span)),
234+
Some((Some(&destination), initializer_span)),
235235
);
236236
this.visit_primary_bindings(
237237
pattern,

src/test/ui/borrowck/access-mode-in-closures.stderr

+9-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ error[E0507]: cannot move out of `s` which is behind a shared reference
33
|
44
LL | match *s { S(v) => v }
55
| ^^ -
6-
| | |
7-
| | data moved here
8-
| | move occurs because `v` has type `Vec<isize>`, which does not implement the `Copy` trait
9-
| help: consider borrowing here: `&*s`
6+
| |
7+
| data moved here
8+
| move occurs because `v` has type `Vec<isize>`, which does not implement the `Copy` trait
9+
|
10+
help: consider removing the dereference here
11+
|
12+
LL - match *s { S(v) => v }
13+
LL + match s { S(v) => v }
14+
|
1015

1116
error: aborting due to previous error
1217

src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr

+30-15
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,46 @@ error[E0507]: cannot move out of a shared reference
22
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:15
33
|
44
LL | for &a in x.iter() {
5-
| -- ^^^^^^^^
6-
| ||
7-
| |data moved here
8-
| |move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait
9-
| help: consider removing the `&`: `a`
5+
| - ^^^^^^^^
6+
| |
7+
| data moved here
8+
| move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait
9+
|
10+
help: consider removing the borrow
11+
|
12+
LL - for &a in x.iter() {
13+
LL + for a in x.iter() {
14+
|
1015

1116
error[E0507]: cannot move out of a shared reference
1217
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:15
1318
|
1419
LL | for &a in &f.a {
15-
| -- ^^^^
16-
| ||
17-
| |data moved here
18-
| |move occurs because `a` has type `Box<isize>`, which does not implement the `Copy` trait
19-
| help: consider removing the `&`: `a`
20+
| - ^^^^
21+
| |
22+
| data moved here
23+
| move occurs because `a` has type `Box<isize>`, which does not implement the `Copy` trait
24+
|
25+
help: consider removing the borrow
26+
|
27+
LL - for &a in &f.a {
28+
LL + for a in &f.a {
29+
|
2030

2131
error[E0507]: cannot move out of a shared reference
2232
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:15
2333
|
2434
LL | for &a in x.iter() {
25-
| -- ^^^^^^^^
26-
| ||
27-
| |data moved here
28-
| |move occurs because `a` has type `Box<i32>`, which does not implement the `Copy` trait
29-
| help: consider removing the `&`: `a`
35+
| - ^^^^^^^^
36+
| |
37+
| data moved here
38+
| move occurs because `a` has type `Box<i32>`, which does not implement the `Copy` trait
39+
|
40+
help: consider removing the borrow
41+
|
42+
LL - for &a in x.iter() {
43+
LL + for a in x.iter() {
44+
|
3045

3146
error: aborting due to 3 previous errors
3247

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// run-rustfix
2+
fn main() {
3+
4+
let x: Option<Box<_>> = Some(Box::new(1));
5+
6+
match x {
7+
Some(ref y) => {
8+
let _b = y; //~ ERROR cannot move out
9+
}
10+
_ => {}
11+
}
12+
}

src/test/ui/borrowck/borrowck-issue-2657-2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// run-rustfix
12
fn main() {
23

34
let x: Option<Box<_>> = Some(Box::new(1));

src/test/ui/borrowck/borrowck-issue-2657-2.stderr

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
error[E0507]: cannot move out of `*y` which is behind a shared reference
2-
--> $DIR/borrowck-issue-2657-2.rs:7:18
2+
--> $DIR/borrowck-issue-2657-2.rs:8:18
33
|
44
LL | let _b = *y;
5-
| ^^
6-
| |
7-
| move occurs because `*y` has type `Box<i32>`, which does not implement the `Copy` trait
8-
| help: consider borrowing here: `&*y`
5+
| ^^ move occurs because `*y` has type `Box<i32>`, which does not implement the `Copy` trait
6+
|
7+
help: consider removing the dereference here
8+
|
9+
LL - let _b = *y;
10+
LL + let _b = y;
11+
|
912

1013
error: aborting due to previous error
1114

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// run-rustfix
2+
#![allow(unused)]
3+
enum Foo {
4+
Foo1(Box<u32>, Box<u32>),
5+
Foo2(Box<u32>),
6+
Foo3,
7+
}
8+
9+
10+
11+
fn blah() {
12+
let f = &Foo::Foo1(Box::new(1), Box::new(2));
13+
match f { //~ ERROR cannot move out of
14+
Foo::Foo1(num1,
15+
num2) => (),
16+
Foo::Foo2(num) => (),
17+
Foo::Foo3 => ()
18+
}
19+
}
20+
21+
struct S {
22+
f: String,
23+
g: String
24+
}
25+
impl Drop for S {
26+
fn drop(&mut self) { println!("{}", self.f); }
27+
}
28+
29+
fn move_in_match() {
30+
match (S {f: "foo".to_string(), g: "bar".to_string()}) {
31+
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
32+
S {
33+
f: ref _s,
34+
g: ref _t
35+
} => {}
36+
}
37+
}
38+
39+
// from issue-8064
40+
struct A {
41+
a: Box<isize>,
42+
}
43+
44+
fn free<T>(_: T) {}
45+
46+
fn blah2() {
47+
let a = &A { a: Box::new(1) };
48+
match &a.a { //~ ERROR cannot move out of
49+
n => {
50+
free(n)
51+
}
52+
}
53+
free(a)
54+
}
55+
56+
fn main() {}

src/test/ui/borrowck/borrowck-move-error-with-note.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// run-rustfix
2+
#![allow(unused)]
13
enum Foo {
24
Foo1(Box<u32>, Box<u32>),
35
Foo2(Box<u32>),

0 commit comments

Comments
 (0)