about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-03-04 21:59:13 -0800
committerMichael Goulet <michael@errs.io>2022-05-17 20:21:54 -0700
commita5c4f4cc4b14b2dff2506d08defb1b97adcbf333 (patch)
treec04d82a4d30d2856726dc5078528963892583260
parent4c5f6e6277b89e47d73a192078697f7a5f3dc0ac (diff)
downloadrust-a5c4f4cc4b14b2dff2506d08defb1b97adcbf333.tar.gz
rust-a5c4f4cc4b14b2dff2506d08defb1b97adcbf333.zip
Suggest deref non-lvalue mutable reference
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs22
-rw-r--r--compiler/rustc_typeck/src/check/op.rs2
-rw-r--r--src/test/ui/typeck/assign-non-lval-mut-ref.fixed7
-rw-r--r--src/test/ui/typeck/assign-non-lval-mut-ref.rs7
-rw-r--r--src/test/ui/typeck/assign-non-lval-mut-ref.stderr16
-rw-r--r--src/test/ui/typeck/issue-93486.stderr5
6 files changed, 56 insertions, 3 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index f3a5b9f13dd..9015868b499 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -836,6 +836,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         lhs: &'tcx hir::Expr<'tcx>,
         err_code: &'static str,
         op_span: Span,
+        adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
     ) {
         if lhs.is_syntactic_place_expr() {
             return;
@@ -858,6 +859,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         });
 
+        adjust_err(&mut err);
+
         err.emit();
     }
 
@@ -1050,9 +1053,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return self.tcx.ty_error();
         }
 
-        self.check_lhs_assignable(lhs, "E0070", span);
-
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
+
+        self.check_lhs_assignable(lhs, "E0070", span, |err| {
+            let rhs_ty = self.check_expr(&rhs);
+
+            if let ty::Ref(_, lhs_inner_ty, hir::Mutability::Mut) = lhs_ty.kind() {
+                if self.can_coerce(rhs_ty, *lhs_inner_ty) {
+                    err.span_suggestion_verbose(
+                        lhs.span.shrink_to_lo(),
+                        "consider dereferencing here to assign to the mutable \
+                    borrowed piece of memory",
+                        "*".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        });
+
         let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
 
         self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 1ae53a77adc..5066e21dc8d 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -41,7 +41,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return_ty
             };
 
-        self.check_lhs_assignable(lhs, "E0067", op.span);
+        self.check_lhs_assignable(lhs, "E0067", op.span, |_| {});
 
         ty
     }
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.fixed b/src/test/ui/typeck/assign-non-lval-mut-ref.fixed
new file mode 100644
index 00000000000..76e2afc672a
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-mut-ref.fixed
@@ -0,0 +1,7 @@
+// run-rustfix
+
+fn main() {
+    let mut x = vec![1usize];
+    *x.last_mut().unwrap() = 2usize;
+    //~^ ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.rs b/src/test/ui/typeck/assign-non-lval-mut-ref.rs
new file mode 100644
index 00000000000..ff91f2297c8
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-mut-ref.rs
@@ -0,0 +1,7 @@
+// run-rustfix
+
+fn main() {
+    let mut x = vec![1usize];
+    x.last_mut().unwrap() = 2usize;
+    //~^ ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.stderr b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr
new file mode 100644
index 00000000000..745ada5de0b
--- /dev/null
+++ b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr
@@ -0,0 +1,16 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/assign-non-lval-mut-ref.rs:5:27
+   |
+LL |     x.last_mut().unwrap() = 2usize;
+   |     --------------------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+help: consider dereferencing here to assign to the mutable borrowed piece of memory
+   |
+LL |     *x.last_mut().unwrap() = 2usize;
+   |     +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/test/ui/typeck/issue-93486.stderr b/src/test/ui/typeck/issue-93486.stderr
index 70b5b63f1cb..95eb021965f 100644
--- a/src/test/ui/typeck/issue-93486.stderr
+++ b/src/test/ui/typeck/issue-93486.stderr
@@ -5,6 +5,11 @@ LL |         vec![].last_mut().unwrap() = 3_u8;
    |         -------------------------- ^
    |         |
    |         cannot assign to this expression
+   |
+help: consider dereferencing here to assign to the mutable borrowed piece of memory
+   |
+LL |         *vec![].last_mut().unwrap() = 3_u8;
+   |         +
 
 error: aborting due to previous error