Skip to content

Commit 46d86d3

Browse files
authored
Rollup merge of rust-lang#45173 - laumann:suggest-misspelled-labels, r=petrochenkov
Add suggestions for misspelled labels Another part of rust-lang#30197
2 parents b290568 + 843dc60 commit 46d86d3

File tree

3 files changed

+72
-10
lines changed

3 files changed

+72
-10
lines changed

src/librustc_resolve/lib.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ enum ResolutionError<'a> {
137137
/// error E0416: identifier is bound more than once in the same pattern
138138
IdentifierBoundMoreThanOnceInSamePattern(&'a str),
139139
/// error E0426: use of undeclared label
140-
UndeclaredLabel(&'a str),
140+
UndeclaredLabel(&'a str, Option<Name>),
141141
/// error E0429: `self` imports are only allowed within a { } list
142142
SelfImportsOnlyAllowedWithin,
143143
/// error E0430: `self` import can only appear once in the list
@@ -263,13 +263,17 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
263263
err.span_label(span, "used in a pattern more than once");
264264
err
265265
}
266-
ResolutionError::UndeclaredLabel(name) => {
266+
ResolutionError::UndeclaredLabel(name, lev_candidate) => {
267267
let mut err = struct_span_err!(resolver.session,
268268
span,
269269
E0426,
270270
"use of undeclared label `{}`",
271271
name);
272-
err.span_label(span, format!("undeclared label `{}`", name));
272+
if let Some(lev_candidate) = lev_candidate {
273+
err.span_label(span, format!("did you mean `{}`?", lev_candidate));
274+
} else {
275+
err.span_label(span, format!("undeclared label `{}`", name));
276+
}
273277
err
274278
}
275279
ResolutionError::SelfImportsOnlyAllowedWithin => {
@@ -1790,9 +1794,13 @@ impl<'a> Resolver<'a> {
17901794
}
17911795
}
17921796

1793-
/// Searches the current set of local scopes for labels.
1797+
/// Searches the current set of local scopes for labels. Returns the first non-None label that
1798+
/// is returned by the given predicate function
1799+
///
17941800
/// Stops after meeting a closure.
1795-
fn search_label(&self, mut ident: Ident) -> Option<Def> {
1801+
fn search_label<P, R>(&self, mut ident: Ident, pred: P) -> Option<R>
1802+
where P: Fn(&Rib, Ident) -> Option<R>
1803+
{
17961804
for rib in self.label_ribs.iter().rev() {
17971805
match rib.kind {
17981806
NormalRibKind => {}
@@ -1808,9 +1816,9 @@ impl<'a> Resolver<'a> {
18081816
return None;
18091817
}
18101818
}
1811-
let result = rib.bindings.get(&ident).cloned();
1812-
if result.is_some() {
1813-
return result;
1819+
let r = pred(rib, ident);
1820+
if r.is_some() {
1821+
return r;
18141822
}
18151823
}
18161824
None
@@ -3202,12 +3210,20 @@ impl<'a> Resolver<'a> {
32023210
}
32033211

32043212
ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
3205-
match self.search_label(label.node) {
3213+
match self.search_label(label.node, |rib, id| rib.bindings.get(&id).cloned()) {
32063214
None => {
3215+
// Search again for close matches...
3216+
// Picks the first label that is "close enough", which is not necessarily
3217+
// the closest match
3218+
let close_match = self.search_label(label.node, |rib, ident| {
3219+
let names = rib.bindings.iter().map(|(id, _)| &id.name);
3220+
find_best_match_for_name(names, &*ident.name.as_str(), None)
3221+
});
32073222
self.record_def(expr.id, err_path_resolution());
32083223
resolve_error(self,
32093224
label.span,
3210-
ResolutionError::UndeclaredLabel(&label.node.name.as_str()));
3225+
ResolutionError::UndeclaredLabel(&label.node.name.as_str(),
3226+
close_match));
32113227
}
32123228
Some(def @ Def::Label(_)) => {
32133229
// Since this def is a label, it is never read.
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[allow(unreachable_code)]
12+
fn main() {
13+
'foo: loop {
14+
break 'fo;
15+
}
16+
17+
'bar: loop {
18+
continue 'bor;
19+
}
20+
21+
'longlabel: loop {
22+
'longlabel1: loop {
23+
break 'longlable;
24+
}
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0426]: use of undeclared label `'fo`
2+
--> $DIR/suggest-labels.rs:14:15
3+
|
4+
14 | break 'fo;
5+
| ^^^ did you mean `'foo`?
6+
7+
error[E0426]: use of undeclared label `'bor`
8+
--> $DIR/suggest-labels.rs:18:18
9+
|
10+
18 | continue 'bor;
11+
| ^^^^ did you mean `'bar`?
12+
13+
error[E0426]: use of undeclared label `'longlable`
14+
--> $DIR/suggest-labels.rs:23:19
15+
|
16+
23 | break 'longlable;
17+
| ^^^^^^^^^^ did you mean `'longlabel1`?
18+
19+
error: aborting due to 3 previous errors
20+

0 commit comments

Comments
 (0)