Skip to content

Commit ed2a511

Browse files
committed
Auto merge of #61147 - estebank:suggest-as-ref, r=oli-obk
When encountering move error on an `Option`, suggest using `as_ref` Fix #61109, cc #15457.
2 parents 37c45ec + 1cc42ea commit ed2a511

File tree

4 files changed

+189
-77
lines changed

4 files changed

+189
-77
lines changed

src/librustc_mir/borrow_check/move_errors.rs

+90-77
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
242242
let (mut err, err_span) = {
243243
let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
244244
match error {
245-
GroupedMoveError::MovesFromPlace {
246-
span,
247-
ref original_path,
248-
ref kind,
249-
..
250-
} |
245+
GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
251246
GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } |
252247
GroupedMoveError::OtherIllegalMove { span, ref original_path, ref kind } => {
253248
(span, original_path, kind)
@@ -257,81 +252,99 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
257252
debug!("report: original_path={:?} span={:?}, kind={:?} \
258253
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
259254
self.is_upvar_field_projection(original_path));
260-
(
261-
match kind {
262-
IllegalMoveOriginKind::Static => {
263-
self.infcx.tcx.cannot_move_out_of(span, "static item", origin)
264-
}
265-
IllegalMoveOriginKind::BorrowedContent { target_place: place } => {
266-
// Inspect the type of the content behind the
267-
// borrow to provide feedback about why this
268-
// was a move rather than a copy.
269-
let ty = place.ty(self.mir, self.infcx.tcx).ty;
270-
let is_upvar_field_projection =
271-
self.prefixes(&original_path, PrefixSet::All)
272-
.any(|p| self.is_upvar_field_projection(p).is_some());
273-
debug!("report: ty={:?}", ty);
274-
match ty.sty {
275-
ty::Array(..) | ty::Slice(..) =>
276-
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
277-
span, ty, None, origin
278-
),
279-
ty::Closure(def_id, closure_substs)
280-
if def_id == self.mir_def_id && is_upvar_field_projection
281-
=> {
282-
let closure_kind_ty =
283-
closure_substs.closure_kind_ty(def_id, self.infcx.tcx);
284-
let closure_kind = closure_kind_ty.to_opt_closure_kind();
285-
let place_description = match closure_kind {
286-
Some(ty::ClosureKind::Fn) => {
287-
"captured variable in an `Fn` closure"
288-
}
289-
Some(ty::ClosureKind::FnMut) => {
290-
"captured variable in an `FnMut` closure"
291-
}
292-
Some(ty::ClosureKind::FnOnce) => {
293-
bug!("closure kind does not match first argument type")
294-
}
295-
None => bug!("closure kind not inferred by borrowck"),
296-
};
297-
debug!("report: closure_kind_ty={:?} closure_kind={:?} \
298-
place_description={:?}", closure_kind_ty, closure_kind,
299-
place_description);
300-
301-
let mut diag = self.infcx.tcx.cannot_move_out_of(
302-
span, place_description, origin);
303-
304-
for prefix in self.prefixes(&original_path, PrefixSet::All) {
305-
if let Some(field) = self.is_upvar_field_projection(prefix) {
306-
let upvar_hir_id = self.upvars[field.index()].var_hir_id;
307-
let upvar_span = self.infcx.tcx.hir().span_by_hir_id(
308-
upvar_hir_id);
309-
diag.span_label(upvar_span, "captured outer variable");
310-
break;
311-
}
255+
let err = match kind {
256+
IllegalMoveOriginKind::Static => {
257+
self.infcx.tcx.cannot_move_out_of(span, "static item", origin)
258+
}
259+
IllegalMoveOriginKind::BorrowedContent { target_place: place } => {
260+
// Inspect the type of the content behind the
261+
// borrow to provide feedback about why this
262+
// was a move rather than a copy.
263+
let ty = place.ty(self.mir, self.infcx.tcx).ty;
264+
let is_upvar_field_projection =
265+
self.prefixes(&original_path, PrefixSet::All)
266+
.any(|p| self.is_upvar_field_projection(p).is_some());
267+
debug!("report: ty={:?}", ty);
268+
let mut err = match ty.sty {
269+
ty::Array(..) | ty::Slice(..) =>
270+
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
271+
span, ty, None, origin
272+
),
273+
ty::Closure(def_id, closure_substs)
274+
if def_id == self.mir_def_id && is_upvar_field_projection
275+
=> {
276+
let closure_kind_ty =
277+
closure_substs.closure_kind_ty(def_id, self.infcx.tcx);
278+
let closure_kind = closure_kind_ty.to_opt_closure_kind();
279+
let place_description = match closure_kind {
280+
Some(ty::ClosureKind::Fn) => {
281+
"captured variable in an `Fn` closure"
282+
}
283+
Some(ty::ClosureKind::FnMut) => {
284+
"captured variable in an `FnMut` closure"
285+
}
286+
Some(ty::ClosureKind::FnOnce) => {
287+
bug!("closure kind does not match first argument type")
288+
}
289+
None => bug!("closure kind not inferred by borrowck"),
290+
};
291+
debug!("report: closure_kind_ty={:?} closure_kind={:?} \
292+
place_description={:?}", closure_kind_ty, closure_kind,
293+
place_description);
294+
295+
let mut diag = self.infcx.tcx.cannot_move_out_of(
296+
span, place_description, origin);
297+
298+
for prefix in self.prefixes(&original_path, PrefixSet::All) {
299+
if let Some(field) = self.is_upvar_field_projection(prefix) {
300+
let upvar_hir_id = self.upvars[field.index()].var_hir_id;
301+
let upvar_span = self.infcx.tcx.hir().span_by_hir_id(
302+
upvar_hir_id);
303+
diag.span_label(upvar_span, "captured outer variable");
304+
break;
312305
}
313-
314-
diag
315306
}
316-
_ => {
317-
let source = self.borrowed_content_source(place);
318-
self.infcx.tcx.cannot_move_out_of(
319-
span, &source.to_string(), origin
320-
)
321-
},
307+
308+
diag
322309
}
310+
_ => {
311+
let source = self.borrowed_content_source(place);
312+
self.infcx.tcx.cannot_move_out_of(
313+
span, &source.to_string(), origin
314+
)
315+
},
316+
};
317+
let orig_path_ty = format!(
318+
"{:?}",
319+
original_path.ty(self.mir, self.infcx.tcx).ty,
320+
);
321+
let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap();
322+
let is_option = orig_path_ty.starts_with("std::option::Option");
323+
let is_result = orig_path_ty.starts_with("std::result::Result");
324+
if is_option || is_result {
325+
err.span_suggestion(
326+
span,
327+
&format!("consider borrowing the `{}`'s content", if is_option {
328+
"Option"
329+
} else {
330+
"Result"
331+
}),
332+
format!("{}.as_ref()", snippet),
333+
Applicability::MaybeIncorrect,
334+
);
323335
}
324-
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
325-
self.infcx.tcx
326-
.cannot_move_out_of_interior_of_drop(span, ty, origin)
327-
}
328-
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
329-
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
330-
span, ty, Some(*is_index), origin
331-
),
332-
},
333-
span,
334-
)
336+
err
337+
}
338+
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
339+
self.infcx.tcx
340+
.cannot_move_out_of_interior_of_drop(span, ty, origin)
341+
}
342+
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
343+
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
344+
span, ty, Some(*is_index), origin
345+
),
346+
};
347+
(err, span)
335348
};
336349

337350
self.add_move_hints(error, &mut err, err_span);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//run-rustfix
2+
3+
pub struct LipogramCorpora {
4+
selections: Vec<(char, Option<String>)>,
5+
}
6+
7+
impl LipogramCorpora {
8+
pub fn validate_all(&mut self) -> Result<(), char> {
9+
for selection in &self.selections {
10+
if selection.1.is_some() {
11+
if selection.1.as_ref().unwrap().contains(selection.0) {
12+
//~^ ERROR cannot move out of borrowed content
13+
return Err(selection.0);
14+
}
15+
}
16+
}
17+
Ok(())
18+
}
19+
}
20+
21+
pub struct LipogramCorpora2 {
22+
selections: Vec<(char, Result<String, String>)>,
23+
}
24+
25+
impl LipogramCorpora2 {
26+
pub fn validate_all(&mut self) -> Result<(), char> {
27+
for selection in &self.selections {
28+
if selection.1.is_ok() {
29+
if selection.1.as_ref().unwrap().contains(selection.0) {
30+
//~^ ERROR cannot move out of borrowed content
31+
return Err(selection.0);
32+
}
33+
}
34+
}
35+
Ok(())
36+
}
37+
}
38+
39+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//run-rustfix
2+
3+
pub struct LipogramCorpora {
4+
selections: Vec<(char, Option<String>)>,
5+
}
6+
7+
impl LipogramCorpora {
8+
pub fn validate_all(&mut self) -> Result<(), char> {
9+
for selection in &self.selections {
10+
if selection.1.is_some() {
11+
if selection.1.unwrap().contains(selection.0) {
12+
//~^ ERROR cannot move out of borrowed content
13+
return Err(selection.0);
14+
}
15+
}
16+
}
17+
Ok(())
18+
}
19+
}
20+
21+
pub struct LipogramCorpora2 {
22+
selections: Vec<(char, Result<String, String>)>,
23+
}
24+
25+
impl LipogramCorpora2 {
26+
pub fn validate_all(&mut self) -> Result<(), char> {
27+
for selection in &self.selections {
28+
if selection.1.is_ok() {
29+
if selection.1.unwrap().contains(selection.0) {
30+
//~^ ERROR cannot move out of borrowed content
31+
return Err(selection.0);
32+
}
33+
}
34+
}
35+
Ok(())
36+
}
37+
}
38+
39+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0507]: cannot move out of borrowed content
2+
--> $DIR/option-content-move.rs:11:20
3+
|
4+
LL | if selection.1.unwrap().contains(selection.0) {
5+
| ^^^^^^^^^^^
6+
| |
7+
| cannot move out of borrowed content
8+
| help: consider borrowing the `Option`'s content: `selection.1.as_ref()`
9+
10+
error[E0507]: cannot move out of borrowed content
11+
--> $DIR/option-content-move.rs:29:20
12+
|
13+
LL | if selection.1.unwrap().contains(selection.0) {
14+
| ^^^^^^^^^^^
15+
| |
16+
| cannot move out of borrowed content
17+
| help: consider borrowing the `Result`'s content: `selection.1.as_ref()`
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0507`.

0 commit comments

Comments
 (0)