Skip to content

Commit 3a471b5

Browse files
committed
Account for x @ y and suggest ref x @ ref y
1 parent 3c905d4 commit 3a471b5

13 files changed

+362
-30
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+22-8
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
315315
expr_span: Span,
316316
expr: Option<&'hir hir::Expr<'hir>>,
317317
pat: Option<&'hir hir::Pat<'hir>>,
318+
parent_pat: Option<&'hir hir::Pat<'hir>>,
318319
}
319320
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
320321
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
@@ -327,10 +328,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
327328
if p.span == self.expr_span {
328329
self.pat = Some(p);
329330
}
330-
if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, _) = p.kind
331-
&& i.span == self.expr_span
332-
{
333-
self.pat = Some(p);
331+
if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, sub) = p.kind {
332+
if i.span == self.expr_span || p.span == self.expr_span {
333+
self.pat = Some(p);
334+
}
335+
// Check if we are in a situation of `ident @ ident` where we want to suggest
336+
// `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`.
337+
if let Some(subpat) = sub && self.pat.is_none() {
338+
self.visit_pat(subpat);
339+
if self.pat.is_some() {
340+
self.parent_pat = Some(p);
341+
}
342+
return;
343+
}
334344
}
335345
hir::intravisit::walk_pat(self, p);
336346
}
@@ -349,6 +359,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
349359
expr_span: move_span,
350360
expr: None,
351361
pat: None,
362+
parent_pat: None,
352363
};
353364
finder.visit_expr(expr);
354365
if let Some(span) = span && let Some(expr) = finder.expr {
@@ -414,7 +425,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
414425
span,
415426
format!(
416427
"consider changing this parameter type in {descr} `{ident}` to \
417-
borrow instead if ownering the value isn't necessary",
428+
borrow instead if owning the value isn't necessary",
418429
),
419430
);
420431
}
@@ -434,10 +445,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
434445
}
435446
if let Some(pat) = finder.pat {
436447
*in_pattern = true;
437-
err.span_suggestion_verbose(
438-
pat.span.shrink_to_lo(),
448+
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
449+
if let Some(pat) = finder.parent_pat {
450+
sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string()));
451+
}
452+
err.multipart_suggestion_verbose(
439453
"borrow this binding in the pattern to avoid moving the value",
440-
"ref ".to_string(),
454+
sugg,
441455
Applicability::MachineApplicable,
442456
);
443457
}

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -1044,11 +1044,19 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
10441044
name,
10451045
typeck_results.node_type(pat.hir_id),
10461046
);
1047-
sess.struct_span_err(pat.span, "borrow of moved value")
1048-
.span_label(binding_span, format!("value moved into `{}` here", name))
1047+
let mut err = sess.struct_span_err(pat.span, "borrow of moved value");
1048+
err.span_label(binding_span, format!("value moved into `{}` here", name))
10491049
.span_label(binding_span, occurs_because)
1050-
.span_labels(conflicts_ref, "value borrowed here after move")
1051-
.emit();
1050+
.span_labels(conflicts_ref, "value borrowed here after move");
1051+
if pat.span.contains(binding_span) {
1052+
err.span_suggestion_verbose(
1053+
binding_span.shrink_to_lo(),
1054+
"borrow this binding in the pattern to avoid moving the value",
1055+
"ref ".to_string(),
1056+
Applicability::MachineApplicable,
1057+
);
1058+
}
1059+
err.emit();
10521060
}
10531061
return;
10541062
}

src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ LL | Some(_z @ ref _y) => {}
1616
| | value borrowed here after move
1717
| value moved into `_z` here
1818
| move occurs because `_z` has type `X` which does not implement the `Copy` trait
19+
|
20+
help: borrow this binding in the pattern to avoid moving the value
21+
|
22+
LL | Some(ref _z @ ref _y) => {}
23+
| +++
1924

2025
error: cannot move out of value because it is borrowed
2126
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
@@ -35,6 +40,11 @@ LL | Some(_z @ ref mut _y) => {}
3540
| | value borrowed here after move
3641
| value moved into `_z` here
3742
| move occurs because `_z` has type `X` which does not implement the `Copy` trait
43+
|
44+
help: borrow this binding in the pattern to avoid moving the value
45+
|
46+
LL | Some(ref _z @ ref mut _y) => {}
47+
| +++
3848

3949
error[E0382]: borrow of moved value
4050
--> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14

src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr

+10-10
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ LL | let a @ b = U;
99
|
1010
help: borrow this binding in the pattern to avoid moving the value
1111
|
12-
LL | let a @ ref b = U;
13-
| +++
12+
LL | let ref a @ ref b = U;
13+
| +++ +++
1414

1515
error[E0382]: use of partially moved value
1616
--> $DIR/borrowck-move-and-move.rs:13:9
@@ -23,8 +23,8 @@ LL | let a @ (b, c) = (U, U);
2323
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
2424
help: borrow this binding in the pattern to avoid moving the value
2525
|
26-
LL | let a @ (b, ref c) = (U, U);
27-
| +++
26+
LL | let ref a @ (b, ref c) = (U, U);
27+
| +++ +++
2828

2929
error[E0382]: use of partially moved value
3030
--> $DIR/borrowck-move-and-move.rs:15:9
@@ -37,8 +37,8 @@ LL | let a @ (b, c) = (u(), u());
3737
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
3838
help: borrow this binding in the pattern to avoid moving the value
3939
|
40-
LL | let a @ (b, ref c) = (u(), u());
41-
| +++
40+
LL | let ref a @ (b, ref c) = (u(), u());
41+
| +++ +++
4242

4343
error[E0382]: use of moved value
4444
--> $DIR/borrowck-move-and-move.rs:18:16
@@ -81,8 +81,8 @@ LL | xs @ [a, .., b] => {}
8181
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
8282
help: borrow this binding in the pattern to avoid moving the value
8383
|
84-
LL | xs @ [a, .., ref b] => {}
85-
| +++
84+
LL | ref xs @ [a, .., ref b] => {}
85+
| +++ +++
8686

8787
error[E0382]: use of partially moved value
8888
--> $DIR/borrowck-move-and-move.rs:29:9
@@ -95,8 +95,8 @@ LL | xs @ [_, ys @ .., _] => {}
9595
= note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
9696
help: borrow this binding in the pattern to avoid moving the value
9797
|
98-
LL | xs @ [_, ref ys @ .., _] => {}
99-
| +++
98+
LL | ref xs @ [_, ref ys @ .., _] => {}
99+
| +++ +++
100100

101101
error[E0382]: use of moved value
102102
--> $DIR/borrowck-move-and-move.rs:22:12

src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ LL | let a @ ref b = U;
77
| | value borrowed here after move
88
| value moved into `a` here
99
| move occurs because `a` has type `U` which does not implement the `Copy` trait
10+
|
11+
help: borrow this binding in the pattern to avoid moving the value
12+
|
13+
LL | let ref a @ ref b = U;
14+
| +++
1015

1116
error: aborting due to previous error
1217

0 commit comments

Comments
 (0)