From 09d71448b7bfa18dca8e3c94cde5914d25cdd607 Mon Sep 17 00:00:00 2001
From: Deadbeef <fee1-dead-beef@protonmail.com>
Date: Tue, 23 Mar 2021 10:45:34 +0800
Subject: [PATCH] Fix ICE of for-loop mut borrowck where no suggestions are
 available

---
 .../diagnostics/mutability_errors.rs          | 17 ++++++----
 .../issue-83309-ice-immut-in-for-loop.rs      | 32 +++++++++++++++++++
 .../issue-83309-ice-immut-in-for-loop.stderr  | 12 +++++++
 3 files changed, 54 insertions(+), 7 deletions(-)
 create mode 100644 src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs
 create mode 100644 src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr

diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index 28f6508cab2..d1fb999e518 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -642,15 +642,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                         .starts_with(&original_method_ident.name.to_string())
                             })
                             .map(|ident| format!("{}()", ident))
+                            .peekable()
                     });
 
-                if let Some(suggestions) = opt_suggestions {
-                    err.span_suggestions(
-                        path_segment.ident.span,
-                        &format!("use mutable method"),
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
+                if let Some(mut suggestions) = opt_suggestions {
+                    if suggestions.peek().is_some() {
+                        err.span_suggestions(
+                            path_segment.ident.span,
+                            &format!("use mutable method"),
+                            suggestions,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
             }
         };
diff --git a/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs
new file mode 100644
index 00000000000..6da88bed2c6
--- /dev/null
+++ b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs
@@ -0,0 +1,32 @@
+// rust-lang/rust#83309: The compiler tries to suggest potential
+// methods that return `&mut` items. However, when it doesn't
+// find such methods, it still tries to add suggestions
+// which then fails an assertion later because there was
+// no suggestions to make.
+
+
+fn main() {
+    for v in Query.iter_mut() {
+        //~^ NOTE this iterator yields `&` references
+        *v -= 1;
+        //~^ ERROR cannot assign to `*v` which is behind a `&` reference
+        //~| NOTE `v` is a `&` reference, so the data it refers to cannot be written
+    }
+}
+
+pub struct Query;
+pub struct QueryIter<'a>(&'a i32);
+
+impl Query {
+    pub fn iter_mut<'a>(&'a mut self) -> QueryIter<'a> {
+        todo!();
+    }
+}
+
+impl<'a> Iterator for QueryIter<'a> {
+    type Item = &'a i32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        todo!();
+    }
+}
diff --git a/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr
new file mode 100644
index 00000000000..143b74c39ba
--- /dev/null
+++ b/src/test/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr
@@ -0,0 +1,12 @@
+error[E0594]: cannot assign to `*v` which is behind a `&` reference
+  --> $DIR/issue-83309-ice-immut-in-for-loop.rs:11:9
+   |
+LL |     for v in Query.iter_mut() {
+   |              ---------------- this iterator yields `&` references
+LL |
+LL |         *v -= 1;
+   |         ^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.