about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTyler Mandry <tmandry@gmail.com>2020-01-24 00:30:53 -0800
committerGitHub <noreply@github.com>2020-01-24 00:30:53 -0800
commiteb769ed6b09cb9fa007508caef808f5e50264cb0 (patch)
tree19390f81a3749210c1c1f86154e697871405c764
parent62f227b3f822a27bd603acede9137bfb49ca8b68 (diff)
parent6eaf59dfc8be4ee5647f9c090c5a7668682f30c0 (diff)
downloadrust-eb769ed6b09cb9fa007508caef808f5e50264cb0.tar.gz
rust-eb769ed6b09cb9fa007508caef808f5e50264cb0.zip
Rollup merge of #68424 - estebank:suggest-borrow-for-non-copy-vec, r=davidtwco
Suggest borrowing `Vec<NonCopy>` in for loop

Partially address #64167.
-rw-r--r--src/libcore/option.rs1
-rw-r--r--src/libcore/result.rs1
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/move_errors.rs29
-rw-r--r--src/test/ui/suggestions/for-i-in-vec.fixed15
-rw-r--r--src/test/ui/suggestions/for-i-in-vec.rs15
-rw-r--r--src/test/ui/suggestions/for-i-in-vec.stderr12
6 files changed, 69 insertions, 4 deletions
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index a471b174534..cb4247d9874 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -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
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index c657ce33f60..bc70dbd62eb 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -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
diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
index eb6db7c145c..43121b38da0 100644
--- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs
@@ -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
diff --git a/src/test/ui/suggestions/for-i-in-vec.fixed b/src/test/ui/suggestions/for-i-in-vec.fixed
new file mode 100644
index 00000000000..ec7358bd08a
--- /dev/null
+++ b/src/test/ui/suggestions/for-i-in-vec.fixed
@@ -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() {}
diff --git a/src/test/ui/suggestions/for-i-in-vec.rs b/src/test/ui/suggestions/for-i-in-vec.rs
new file mode 100644
index 00000000000..304fe8cc81f
--- /dev/null
+++ b/src/test/ui/suggestions/for-i-in-vec.rs
@@ -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() {}
diff --git a/src/test/ui/suggestions/for-i-in-vec.stderr b/src/test/ui/suggestions/for-i-in-vec.stderr
new file mode 100644
index 00000000000..576a7cc2f60
--- /dev/null
+++ b/src/test/ui/suggestions/for-i-in-vec.stderr
@@ -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`.