From 1e3302d85f6c9635c14535bb59d17964a9479c2d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Esteban=20K=C3=BCber?= Date: Wed, 22 May 2019 13:10:38 -0700 Subject: [PATCH] Suggest dereferencing on assignment to mutable borrow --- src/librustc_typeck/check/demand.rs | 34 ++++++++++++++++--- .../ui/suggestions/mut-ref-reassignment.rs | 5 +++ .../suggestions/mut-ref-reassignment.stderr | 16 +++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/suggestions/mut-ref-reassignment.rs create mode 100644 src/test/ui/suggestions/mut-ref-reassignment.stderr 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 @@ 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){ 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..b9deaa96dbf --- /dev/null +++ b/src/test/ui/suggestions/mut-ref-reassignment.rs @@ -0,0 +1,5 @@ +fn change_opt(opt: &mut Option){ + opt = None //~ 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..d90c13b3882 --- /dev/null +++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr @@ -0,0 +1,16 @@ +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: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. -- 2.44.0