about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/demand.rs34
-rw-r--r--src/test/ui/suggestions/mut-ref-reassignment.rs17
-rw-r--r--src/test/ui/suggestions/mut-ref-reassignment.stderr47
3 files changed, 93 insertions, 5 deletions
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 8d68179b495..a4e687b8f90 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -306,11 +306,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// In addition of this check, it also checks between references mutability state. If the
     /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
     /// `&mut`!".
-    pub fn check_ref(&self,
-                 expr: &hir::Expr,
-                 checked_ty: Ty<'tcx>,
-                 expected: Ty<'tcx>)
-                 -> Option<(Span, &'static str, String)> {
+    pub fn check_ref(
+        &self,
+        expr: &hir::Expr,
+        checked_ty: Ty<'tcx>,
+        expected: Ty<'tcx>,
+    ) -> Option<(Span, &'static str, String)> {
         let cm = self.sess().source_map();
         let sp = expr.span;
         if !cm.span_to_filename(sp).is_real() {
@@ -397,6 +398,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         } else {
                             String::new()
                         };
+                        if let Some(hir::Node::Expr(hir::Expr {
+                            node: hir::ExprKind::Assign(left_expr, _),
+                            ..
+                        })) = self.tcx.hir().find_by_hir_id(
+                            self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id),
+                        ) {
+                            if mutability == hir::Mutability::MutMutable {
+                                // Found the following case:
+                                // fn foo(opt: &mut Option<String>){ opt = None }
+                                //                                   ---   ^^^^
+                                //                                   |     |
+                                //    consider dereferencing here: `*opt`  |
+                                // expected mutable reference, found enum `Option`
+                                if let Ok(src) = cm.span_to_snippet(left_expr.span) {
+                                    return Some((
+                                        left_expr.span,
+                                        "consider dereferencing here to assign to the mutable \
+                                         borrowed piece of memory",
+                                        format!("*{}", src),
+                                    ));
+                                }
+                            }
+                        }
                         return Some(match mutability {
                             hir::Mutability::MutMutable => (
                                 sp,
diff --git a/src/test/ui/suggestions/mut-ref-reassignment.rs b/src/test/ui/suggestions/mut-ref-reassignment.rs
new file mode 100644
index 00000000000..1428324934d
--- /dev/null
+++ b/src/test/ui/suggestions/mut-ref-reassignment.rs
@@ -0,0 +1,17 @@
+fn suggestion(opt: &mut Option<String>) {
+    opt = None; //~ ERROR mismatched types
+}
+
+fn no_suggestion(opt: &mut Result<String, ()>) {
+    opt = None //~ ERROR mismatched types
+}
+
+fn suggestion2(opt: &mut Option<String>) {
+    opt = Some(String::new())//~ ERROR mismatched types
+}
+
+fn no_suggestion2(opt: &mut Option<String>) {
+    opt = Some(42)//~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/mut-ref-reassignment.stderr b/src/test/ui/suggestions/mut-ref-reassignment.stderr
new file mode 100644
index 00000000000..66b78a1b140
--- /dev/null
+++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr
@@ -0,0 +1,47 @@
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-reassignment.rs:2:11
+   |
+LL |     opt = None;
+   |           ^^^^ expected mutable reference, found enum `std::option::Option`
+   |
+   = note: expected type `&mut std::option::Option<std::string::String>`
+              found type `std::option::Option<_>`
+help: consider dereferencing here to assign to the mutable borrowed piece of memory
+   |
+LL |     *opt = None;
+   |     ^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-reassignment.rs:6:11
+   |
+LL |     opt = None
+   |           ^^^^ expected mutable reference, found enum `std::option::Option`
+   |
+   = note: expected type `&mut std::result::Result<std::string::String, ()>`
+              found type `std::option::Option<_>`
+
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-reassignment.rs:10:11
+   |
+LL |     opt = Some(String::new())
+   |           ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `std::option::Option`
+   |
+   = note: expected type `&mut std::option::Option<std::string::String>`
+              found type `std::option::Option<std::string::String>`
+help: consider dereferencing here to assign to the mutable borrowed piece of memory
+   |
+LL |     *opt = Some(String::new())
+   |     ^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/mut-ref-reassignment.rs:14:11
+   |
+LL |     opt = Some(42)
+   |           ^^^^^^^^ expected mutable reference, found enum `std::option::Option`
+   |
+   = note: expected type `&mut std::option::Option<std::string::String>`
+              found type `std::option::Option<{integer}>`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.