From 1e3302d85f6c9635c14535bb59d17964a9479c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 22 May 2019 13:10:38 -0700 Subject: [PATCH 1/2] 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 @@ 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 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`. From 7fbbcfaafd08023cc2296481425e16a02ccd3f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 May 2019 10:32:01 -0700 Subject: [PATCH 2/2] Add regression test for negative case --- .../ui/suggestions/mut-ref-reassignment.rs | 14 ++++++- .../suggestions/mut-ref-reassignment.stderr | 37 +++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/test/ui/suggestions/mut-ref-reassignment.rs b/src/test/ui/suggestions/mut-ref-reassignment.rs index b9deaa96dbf..1428324934d 100644 --- a/src/test/ui/suggestions/mut-ref-reassignment.rs +++ b/src/test/ui/suggestions/mut-ref-reassignment.rs @@ -1,5 +1,17 @@ -fn change_opt(opt: &mut Option){ +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 index d90c13b3882..66b78a1b140 100644 --- a/src/test/ui/suggestions/mut-ref-reassignment.stderr +++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr @@ -1,16 +1,47 @@ error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:2:11 | -LL | opt = None +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 +LL | *opt = None; | ^^^^ -error: aborting due to previous error +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`.