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.
This commit is contained in:
commit
ed2a5115da
|
@ -242,12 +242,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||||
let (mut err, err_span) = {
|
let (mut err, err_span) = {
|
||||||
let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
|
let (span, original_path, kind): (Span, &Place<'tcx>, &IllegalMoveOriginKind<'_>) =
|
||||||
match error {
|
match error {
|
||||||
GroupedMoveError::MovesFromPlace {
|
GroupedMoveError::MovesFromPlace { span, ref original_path, ref kind, .. } |
|
||||||
span,
|
|
||||||
ref original_path,
|
|
||||||
ref kind,
|
|
||||||
..
|
|
||||||
} |
|
|
||||||
GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } |
|
GroupedMoveError::MovesFromValue { span, ref original_path, ref kind, .. } |
|
||||||
GroupedMoveError::OtherIllegalMove { span, ref original_path, ref kind } => {
|
GroupedMoveError::OtherIllegalMove { span, ref original_path, ref kind } => {
|
||||||
(span, original_path, kind)
|
(span, original_path, kind)
|
||||||
|
@ -257,81 +252,99 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||||
debug!("report: original_path={:?} span={:?}, kind={:?} \
|
debug!("report: original_path={:?} span={:?}, kind={:?} \
|
||||||
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
|
original_path.is_upvar_field_projection={:?}", original_path, span, kind,
|
||||||
self.is_upvar_field_projection(original_path));
|
self.is_upvar_field_projection(original_path));
|
||||||
(
|
let err = match kind {
|
||||||
match kind {
|
IllegalMoveOriginKind::Static => {
|
||||||
IllegalMoveOriginKind::Static => {
|
self.infcx.tcx.cannot_move_out_of(span, "static item", origin)
|
||||||
self.infcx.tcx.cannot_move_out_of(span, "static item", origin)
|
}
|
||||||
}
|
IllegalMoveOriginKind::BorrowedContent { target_place: place } => {
|
||||||
IllegalMoveOriginKind::BorrowedContent { target_place: place } => {
|
// Inspect the type of the content behind the
|
||||||
// Inspect the type of the content behind the
|
// borrow to provide feedback about why this
|
||||||
// borrow to provide feedback about why this
|
// was a move rather than a copy.
|
||||||
// was a move rather than a copy.
|
let ty = place.ty(self.mir, self.infcx.tcx).ty;
|
||||||
let ty = place.ty(self.mir, self.infcx.tcx).ty;
|
let is_upvar_field_projection =
|
||||||
let is_upvar_field_projection =
|
self.prefixes(&original_path, PrefixSet::All)
|
||||||
self.prefixes(&original_path, PrefixSet::All)
|
.any(|p| self.is_upvar_field_projection(p).is_some());
|
||||||
.any(|p| self.is_upvar_field_projection(p).is_some());
|
debug!("report: ty={:?}", ty);
|
||||||
debug!("report: ty={:?}", ty);
|
let mut err = match ty.sty {
|
||||||
match ty.sty {
|
ty::Array(..) | ty::Slice(..) =>
|
||||||
ty::Array(..) | ty::Slice(..) =>
|
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
|
||||||
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
|
span, ty, None, origin
|
||||||
span, ty, None, origin
|
),
|
||||||
),
|
ty::Closure(def_id, closure_substs)
|
||||||
ty::Closure(def_id, closure_substs)
|
if def_id == self.mir_def_id && is_upvar_field_projection
|
||||||
if def_id == self.mir_def_id && is_upvar_field_projection
|
=> {
|
||||||
=> {
|
let closure_kind_ty =
|
||||||
let closure_kind_ty =
|
closure_substs.closure_kind_ty(def_id, self.infcx.tcx);
|
||||||
closure_substs.closure_kind_ty(def_id, self.infcx.tcx);
|
let closure_kind = closure_kind_ty.to_opt_closure_kind();
|
||||||
let closure_kind = closure_kind_ty.to_opt_closure_kind();
|
let place_description = match closure_kind {
|
||||||
let place_description = match closure_kind {
|
Some(ty::ClosureKind::Fn) => {
|
||||||
Some(ty::ClosureKind::Fn) => {
|
"captured variable in an `Fn` closure"
|
||||||
"captured variable in an `Fn` closure"
|
|
||||||
}
|
|
||||||
Some(ty::ClosureKind::FnMut) => {
|
|
||||||
"captured variable in an `FnMut` closure"
|
|
||||||
}
|
|
||||||
Some(ty::ClosureKind::FnOnce) => {
|
|
||||||
bug!("closure kind does not match first argument type")
|
|
||||||
}
|
|
||||||
None => bug!("closure kind not inferred by borrowck"),
|
|
||||||
};
|
|
||||||
debug!("report: closure_kind_ty={:?} closure_kind={:?} \
|
|
||||||
place_description={:?}", closure_kind_ty, closure_kind,
|
|
||||||
place_description);
|
|
||||||
|
|
||||||
let mut diag = self.infcx.tcx.cannot_move_out_of(
|
|
||||||
span, place_description, origin);
|
|
||||||
|
|
||||||
for prefix in self.prefixes(&original_path, PrefixSet::All) {
|
|
||||||
if let Some(field) = self.is_upvar_field_projection(prefix) {
|
|
||||||
let upvar_hir_id = self.upvars[field.index()].var_hir_id;
|
|
||||||
let upvar_span = self.infcx.tcx.hir().span_by_hir_id(
|
|
||||||
upvar_hir_id);
|
|
||||||
diag.span_label(upvar_span, "captured outer variable");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Some(ty::ClosureKind::FnMut) => {
|
||||||
|
"captured variable in an `FnMut` closure"
|
||||||
|
}
|
||||||
|
Some(ty::ClosureKind::FnOnce) => {
|
||||||
|
bug!("closure kind does not match first argument type")
|
||||||
|
}
|
||||||
|
None => bug!("closure kind not inferred by borrowck"),
|
||||||
|
};
|
||||||
|
debug!("report: closure_kind_ty={:?} closure_kind={:?} \
|
||||||
|
place_description={:?}", closure_kind_ty, closure_kind,
|
||||||
|
place_description);
|
||||||
|
|
||||||
diag
|
let mut diag = self.infcx.tcx.cannot_move_out_of(
|
||||||
|
span, place_description, origin);
|
||||||
|
|
||||||
|
for prefix in self.prefixes(&original_path, PrefixSet::All) {
|
||||||
|
if let Some(field) = self.is_upvar_field_projection(prefix) {
|
||||||
|
let upvar_hir_id = self.upvars[field.index()].var_hir_id;
|
||||||
|
let upvar_span = self.infcx.tcx.hir().span_by_hir_id(
|
||||||
|
upvar_hir_id);
|
||||||
|
diag.span_label(upvar_span, "captured outer variable");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
let source = self.borrowed_content_source(place);
|
diag
|
||||||
self.infcx.tcx.cannot_move_out_of(
|
|
||||||
span, &source.to_string(), origin
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
let source = self.borrowed_content_source(place);
|
||||||
|
self.infcx.tcx.cannot_move_out_of(
|
||||||
|
span, &source.to_string(), origin
|
||||||
|
)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let orig_path_ty = format!(
|
||||||
|
"{:?}",
|
||||||
|
original_path.ty(self.mir, self.infcx.tcx).ty,
|
||||||
|
);
|
||||||
|
let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap();
|
||||||
|
let is_option = orig_path_ty.starts_with("std::option::Option");
|
||||||
|
let is_result = orig_path_ty.starts_with("std::result::Result");
|
||||||
|
if is_option || is_result {
|
||||||
|
err.span_suggestion(
|
||||||
|
span,
|
||||||
|
&format!("consider borrowing the `{}`'s content", if is_option {
|
||||||
|
"Option"
|
||||||
|
} else {
|
||||||
|
"Result"
|
||||||
|
}),
|
||||||
|
format!("{}.as_ref()", snippet),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
|
err
|
||||||
self.infcx.tcx
|
}
|
||||||
.cannot_move_out_of_interior_of_drop(span, ty, origin)
|
IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
|
||||||
}
|
self.infcx.tcx
|
||||||
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
|
.cannot_move_out_of_interior_of_drop(span, ty, origin)
|
||||||
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
|
}
|
||||||
span, ty, Some(*is_index), origin
|
IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } =>
|
||||||
),
|
self.infcx.tcx.cannot_move_out_of_interior_noncopy(
|
||||||
},
|
span, ty, Some(*is_index), origin
|
||||||
span,
|
),
|
||||||
)
|
};
|
||||||
|
(err, span)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.add_move_hints(error, &mut err, err_span);
|
self.add_move_hints(error, &mut err, err_span);
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
//run-rustfix
|
||||||
|
|
||||||
|
pub struct LipogramCorpora {
|
||||||
|
selections: Vec<(char, Option<String>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LipogramCorpora {
|
||||||
|
pub fn validate_all(&mut self) -> Result<(), char> {
|
||||||
|
for selection in &self.selections {
|
||||||
|
if selection.1.is_some() {
|
||||||
|
if selection.1.as_ref().unwrap().contains(selection.0) {
|
||||||
|
//~^ ERROR cannot move out of borrowed content
|
||||||
|
return Err(selection.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LipogramCorpora2 {
|
||||||
|
selections: Vec<(char, Result<String, String>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LipogramCorpora2 {
|
||||||
|
pub fn validate_all(&mut self) -> Result<(), char> {
|
||||||
|
for selection in &self.selections {
|
||||||
|
if selection.1.is_ok() {
|
||||||
|
if selection.1.as_ref().unwrap().contains(selection.0) {
|
||||||
|
//~^ ERROR cannot move out of borrowed content
|
||||||
|
return Err(selection.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,39 @@
|
||||||
|
//run-rustfix
|
||||||
|
|
||||||
|
pub struct LipogramCorpora {
|
||||||
|
selections: Vec<(char, Option<String>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LipogramCorpora {
|
||||||
|
pub fn validate_all(&mut self) -> Result<(), char> {
|
||||||
|
for selection in &self.selections {
|
||||||
|
if selection.1.is_some() {
|
||||||
|
if selection.1.unwrap().contains(selection.0) {
|
||||||
|
//~^ ERROR cannot move out of borrowed content
|
||||||
|
return Err(selection.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LipogramCorpora2 {
|
||||||
|
selections: Vec<(char, Result<String, String>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LipogramCorpora2 {
|
||||||
|
pub fn validate_all(&mut self) -> Result<(), char> {
|
||||||
|
for selection in &self.selections {
|
||||||
|
if selection.1.is_ok() {
|
||||||
|
if selection.1.unwrap().contains(selection.0) {
|
||||||
|
//~^ ERROR cannot move out of borrowed content
|
||||||
|
return Err(selection.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0507]: cannot move out of borrowed content
|
||||||
|
--> $DIR/option-content-move.rs:11:20
|
||||||
|
|
|
||||||
|
LL | if selection.1.unwrap().contains(selection.0) {
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| cannot move out of borrowed content
|
||||||
|
| help: consider borrowing the `Option`'s content: `selection.1.as_ref()`
|
||||||
|
|
||||||
|
error[E0507]: cannot move out of borrowed content
|
||||||
|
--> $DIR/option-content-move.rs:29:20
|
||||||
|
|
|
||||||
|
LL | if selection.1.unwrap().contains(selection.0) {
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| cannot move out of borrowed content
|
||||||
|
| help: consider borrowing the `Result`'s content: `selection.1.as_ref()`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0507`.
|
Loading…
Reference in New Issue