]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #61054 - estebank:mut-ref-reassign, r=zackmdavis
authorMazdak Farrokhzad <twingoow@gmail.com>
Thu, 23 May 2019 23:30:20 +0000 (01:30 +0200)
committerGitHub <noreply@github.com>
Thu, 23 May 2019 23:30:20 +0000 (01:30 +0200)
Suggest dereferencing on assignment to mutable borrow

Fix #33570

src/librustc_typeck/check/demand.rs
src/test/ui/suggestions/mut-ref-reassignment.rs [new file with mode: 0644]
src/test/ui/suggestions/mut-ref-reassignment.stderr [new file with mode: 0644]

index 8d68179b495c6015738344919f05b2af1a07daca..a4e687b8f9080f4b4e8e535af1b36200c26dc7dc 100644 (file)
@@ -306,11 +306,12 @@ fn is_hir_id_from_struct_pattern_shorthand_field(&self, hir_id: hir::HirId, sp:
     /// 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 @@ pub fn check_ref(&self,
                         } 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 (file)
index 0000000..1428324
--- /dev/null
@@ -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 (file)
index 0000000..66b78a1
--- /dev/null
@@ -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`.