diff options
| author | Thomas Jespersen <laumann.thomas@gmail.com> | 2017-10-10 00:21:09 +0200 |
|---|---|---|
| committer | Thomas Jespersen <laumann.thomas@gmail.com> | 2017-10-10 17:22:14 +0200 |
| commit | 843dc604447139463b76014d51e6976dc07ec0db (patch) | |
| tree | 6a5fababe7465cef450b7bc3d7812f5f6556930c /src/librustc_resolve | |
| parent | 5f578dfad0dd5d43b28eff71a7e857d10c3f55fe (diff) | |
| download | rust-843dc604447139463b76014d51e6976dc07ec0db.tar.gz rust-843dc604447139463b76014d51e6976dc07ec0db.zip | |
Add suggestions for misspelled labels
Another part of #30197
Diffstat (limited to 'src/librustc_resolve')
| -rw-r--r-- | src/librustc_resolve/lib.rs | 36 |
1 files changed, 26 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. |
