diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 8d68179b495c6..a4e687b8f9080 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){ 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 0000000000000..1428324934de2 --- /dev/null +++ b/src/test/ui/suggestions/mut-ref-reassignment.rs @@ -0,0 +1,17 @@ +fn suggestion(opt: &mut Option) { + opt = None; //~ ERROR mismatched types +} + +fn no_suggestion(opt: &mut Result) { + opt = None //~ ERROR mismatched types +} + +fn suggestion2(opt: &mut Option) { + opt = Some(String::new())//~ ERROR mismatched types +} + +fn no_suggestion2(opt: &mut Option) { + 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 0000000000000..66b78a1b14015 --- /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` + 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` + 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` + found type `std::option::Option` +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` + found type `std::option::Option<{integer}>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`.