Rollup merge of #68424 - estebank:suggest-borrow-for-non-copy-vec, r=davidtwco

Suggest borrowing `Vec<NonCopy>` in for loop

Partially address #64167.
This commit is contained in:
Tyler Mandry 2020-01-24 00:30:53 -08:00 committed by GitHub
commit eb769ed6b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 4 deletions

View file

@ -151,6 +151,7 @@ use crate::{
/// The `Option` type. See [the module level documentation](index.html) for more.
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[rustc_diagnostic_item = "option_type"]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Option<T> {
/// No value

View file

@ -242,6 +242,7 @@ use crate::ops::{self, Deref, DerefMut};
/// [`Err`]: enum.Result.html#variant.Err
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
#[must_use = "this `Result` may be an `Err` variant, which should be handled"]
#[rustc_diagnostic_item = "result_type"]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Result<T, E> {
/// Contains the success value

View file

@ -1,7 +1,8 @@
use rustc::mir::*;
use rustc::ty;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_span::Span;
use rustc_span::source_map::DesugaringKind;
use rustc_span::{Span, Symbol};
use crate::borrow_check::diagnostics::UseSpans;
use crate::borrow_check::prefixes::PrefixSet;
@ -383,10 +384,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
};
let move_ty = format!("{:?}", move_place.ty(*self.body, self.infcx.tcx).ty,);
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
let is_option = move_ty.starts_with("std::option::Option");
let is_result = move_ty.starts_with("std::result::Result");
let def_id = match move_place.ty(*self.body, self.infcx.tcx).ty.kind {
ty::Adt(self_def, _) => self_def.did,
ty::Foreign(def_id)
| ty::FnDef(def_id, _)
| ty::Closure(def_id, _)
| ty::Generator(def_id, ..)
| ty::Opaque(def_id, _) => def_id,
_ => return err,
};
let is_option =
self.infcx.tcx.is_diagnostic_item(Symbol::intern("option_type"), def_id);
let is_result =
self.infcx.tcx.is_diagnostic_item(Symbol::intern("result_type"), def_id);
if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
err.span_suggestion(
span,
@ -397,6 +408,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
format!("{}.as_ref()", snippet),
Applicability::MaybeIncorrect,
);
} else if span.is_desugaring(DesugaringKind::ForLoop)
&& self.infcx.tcx.is_diagnostic_item(Symbol::intern("vec_type"), def_id)
{
// FIXME: suggest for anything that implements `IntoIterator`.
err.span_suggestion(
span,
"consider iterating over a slice of the `Vec<_>`'s content",
format!("&{}", snippet),
Applicability::MaybeIncorrect,
);
}
}
err

View file

@ -0,0 +1,15 @@
// run-rustfix
#![allow(dead_code)]
struct Foo {
v: Vec<u32>,
}
impl Foo {
fn bar(&self) {
for _ in &self.v { //~ ERROR cannot move out of `self.v` which is behind a shared reference
}
}
}
fn main() {}

View file

@ -0,0 +1,15 @@
// run-rustfix
#![allow(dead_code)]
struct Foo {
v: Vec<u32>,
}
impl Foo {
fn bar(&self) {
for _ in self.v { //~ ERROR cannot move out of `self.v` which is behind a shared reference
}
}
}
fn main() {}

View file

@ -0,0 +1,12 @@
error[E0507]: cannot move out of `self.v` which is behind a shared reference
--> $DIR/for-i-in-vec.rs:10:18
|
LL | for _ in self.v {
| ^^^^^^
| |
| move occurs because `self.v` has type `std::vec::Vec<u32>`, which does not implement the `Copy` trait
| help: consider iterating over a slice of the `Vec<_>`'s content: `&self.v`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0507`.