diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 36cd69f91b9c3..4aab43cbec701 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), /// 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 { + fn search_label(&self, mut ident: Ident, pred: P) -> Option + where P: Fn(&Rib, Ident) -> Option + { 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 0000000000000..5bebce79eccbc --- /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 or the MIT license +// , 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 0000000000000..23aa18a3655fb --- /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 +