about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_resolve/lib.rs36
-rw-r--r--src/test/ui/suggestions/suggest-labels.rs26
-rw-r--r--src/test/ui/suggestions/suggest-labels.stderr20
3 files changed, 72 insertions, 10 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 36cd69f91b9..4aab43cbec7 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -137,7 +137,7 @@ enum ResolutionError<'a> {
     /// error E0416: identifier is bound more than once in the same pattern
     IdentifierBoundMoreThanOnceInSamePattern(&'a str),
     /// error E0426: use of undeclared label
-    UndeclaredLabel(&'a str),
+    UndeclaredLabel(&'a str, Option<Name>),
     /// error E0429: `self` imports are only allowed within a { } list
     SelfImportsOnlyAllowedWithin,
     /// error E0430: `self` import can only appear once in the list
@@ -263,13 +263,17 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             err.span_label(span, "used in a pattern more than once");
             err
         }
-        ResolutionError::UndeclaredLabel(name) => {
+        ResolutionError::UndeclaredLabel(name, lev_candidate) => {
             let mut err = struct_span_err!(resolver.session,
                                            span,
                                            E0426,
                                            "use of undeclared label `{}`",
                                            name);
-            err.span_label(span, format!("undeclared label `{}`", name));
+            if let Some(lev_candidate) = lev_candidate {
+                err.span_label(span, format!("did you mean `{}`?", lev_candidate));
+            } else {
+                err.span_label(span, format!("undeclared label `{}`", name));
+            }
             err
         }
         ResolutionError::SelfImportsOnlyAllowedWithin => {
@@ -1790,9 +1794,13 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    /// Searches the current set of local scopes for labels.
+    /// Searches the current set of local scopes for labels. Returns the first non-None label that
+    /// is returned by the given predicate function
+    ///
     /// Stops after meeting a closure.
-    fn search_label(&self, mut ident: Ident) -> Option<Def> {
+    fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
+        where P: Fn(&Rib, Ident) -> Option<R>
+    {
         for rib in self.label_ribs.iter().rev() {
             match rib.kind {
                 NormalRibKind => {}
@@ -1808,9 +1816,9 @@ impl<'a> Resolver<'a> {
                     return None;
                 }
             }
-            let result = rib.bindings.get(&ident).cloned();
-            if result.is_some() {
-                return result;
+            let r = pred(rib, ident);
+            if r.is_some() {
+                return r;
             }
         }
         None
@@ -3202,12 +3210,20 @@ impl<'a> Resolver<'a> {
             }
 
             ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
-                match self.search_label(label.node) {
+                match self.search_label(label.node, |rib, id| rib.bindings.get(&id).cloned()) {
                     None => {
+                        // Search again for close matches...
+                        // Picks the first label that is "close enough", which is not necessarily
+                        // the closest match
+                        let close_match = self.search_label(label.node, |rib, ident| {
+                            let names = rib.bindings.iter().map(|(id, _)| &id.name);
+                            find_best_match_for_name(names, &*ident.name.as_str(), None)
+                        });
                         self.record_def(expr.id, err_path_resolution());
                         resolve_error(self,
                                       label.span,
-                                      ResolutionError::UndeclaredLabel(&label.node.name.as_str()));
+                                      ResolutionError::UndeclaredLabel(&label.node.name.as_str(),
+                                                                       close_match));
                     }
                     Some(def @ Def::Label(_)) => {
                         // Since this def is a label, it is never read.
diff --git a/src/test/ui/suggestions/suggest-labels.rs b/src/test/ui/suggestions/suggest-labels.rs
new file mode 100644
index 00000000000..5bebce79ecc
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-labels.rs
@@ -0,0 +1,26 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[allow(unreachable_code)]
+fn main() {
+    'foo: loop {
+        break 'fo;
+    }
+
+    'bar: loop {
+        continue 'bor;
+    }
+
+    'longlabel: loop {
+        'longlabel1: loop {
+            break 'longlable;
+        }
+    }
+}
diff --git a/src/test/ui/suggestions/suggest-labels.stderr b/src/test/ui/suggestions/suggest-labels.stderr
new file mode 100644
index 00000000000..23aa18a3655
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-labels.stderr
@@ -0,0 +1,20 @@
+error[E0426]: use of undeclared label `'fo`
+  --> $DIR/suggest-labels.rs:14:15
+   |
+14 |         break 'fo;
+   |               ^^^ did you mean `'foo`?
+
+error[E0426]: use of undeclared label `'bor`
+  --> $DIR/suggest-labels.rs:18:18
+   |
+18 |         continue 'bor;
+   |                  ^^^^ did you mean `'bar`?
+
+error[E0426]: use of undeclared label `'longlable`
+  --> $DIR/suggest-labels.rs:23:19
+   |
+23 |             break 'longlable;
+   |                   ^^^^^^^^^^ did you mean `'longlabel1`?
+
+error: aborting due to 3 previous errors
+