Skip to content

Commit 477dac3

Browse files
committed
Suggest correct raw identifier in case of typo
1 parent 85ffd44 commit 477dac3

File tree

4 files changed

+72
-40
lines changed

4 files changed

+72
-40
lines changed

src/librustc_resolve/diagnostics.rs

+31-31
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ type Res = def::Res<ast::NodeId>;
3333
crate type Suggestion = (Vec<(Span, String)>, String, Applicability);
3434

3535
crate struct TypoSuggestion {
36-
pub candidate: Symbol,
36+
pub candidate: Ident,
3737
pub res: Res,
3838
}
3939

4040
impl TypoSuggestion {
41-
crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
41+
crate fn from_res(candidate: Ident, res: Res) -> TypoSuggestion {
4242
TypoSuggestion { candidate, res }
4343
}
4444
}
@@ -107,7 +107,7 @@ impl<'a> Resolver<'a> {
107107
if let Some(binding) = resolution.borrow().binding {
108108
let res = binding.res();
109109
if filter_fn(res) {
110-
names.push(TypoSuggestion::from_res(key.ident.name, res));
110+
names.push(TypoSuggestion::from_res(key.ident, res));
111111
}
112112
}
113113
}
@@ -509,7 +509,7 @@ impl<'a> Resolver<'a> {
509509
.get(&expn_id)
510510
.into_iter()
511511
.flatten()
512-
.map(|ident| TypoSuggestion::from_res(ident.name, res)),
512+
.map(|ident| TypoSuggestion::from_res(*ident, res)),
513513
);
514514
}
515515
}
@@ -525,11 +525,9 @@ impl<'a> Resolver<'a> {
525525
false,
526526
false,
527527
) {
528-
suggestions.extend(
529-
ext.helper_attrs
530-
.iter()
531-
.map(|name| TypoSuggestion::from_res(*name, res)),
532-
);
528+
suggestions.extend(ext.helper_attrs.iter().map(|name| {
529+
TypoSuggestion::from_res(Ident::new(*name, derive.span), res)
530+
}));
533531
}
534532
}
535533
}
@@ -538,8 +536,7 @@ impl<'a> Resolver<'a> {
538536
if let LegacyScope::Binding(legacy_binding) = legacy_scope {
539537
let res = legacy_binding.binding.res();
540538
if filter_fn(res) {
541-
suggestions
542-
.push(TypoSuggestion::from_res(legacy_binding.ident.name, res))
539+
suggestions.push(TypoSuggestion::from_res(legacy_binding.ident, res))
543540
}
544541
}
545542
}
@@ -557,40 +554,40 @@ impl<'a> Resolver<'a> {
557554
suggestions.extend(
558555
this.registered_attrs
559556
.iter()
560-
.map(|ident| TypoSuggestion::from_res(ident.name, res)),
557+
.map(|ident| TypoSuggestion::from_res(*ident, res)),
561558
);
562559
}
563560
}
564561
Scope::MacroUsePrelude => {
565562
suggestions.extend(this.macro_use_prelude.iter().filter_map(
566563
|(name, binding)| {
567564
let res = binding.res();
568-
filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
565+
let span = binding.span;
566+
filter_fn(res)
567+
.then_some(TypoSuggestion::from_res(Ident::new(*name, span), res))
569568
},
570569
));
571570
}
572571
Scope::BuiltinAttrs => {
573572
let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
574573
if filter_fn(res) {
575-
suggestions.extend(
576-
BUILTIN_ATTRIBUTES
577-
.iter()
578-
.map(|(name, ..)| TypoSuggestion::from_res(*name, res)),
579-
);
574+
suggestions.extend(BUILTIN_ATTRIBUTES.iter().map(|(name, ..)| {
575+
TypoSuggestion::from_res(Ident::with_dummy_span(*name), res)
576+
}));
580577
}
581578
}
582579
Scope::ExternPrelude => {
583580
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
584581
let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
585-
filter_fn(res).then_some(TypoSuggestion::from_res(ident.name, res))
582+
filter_fn(res).then_some(TypoSuggestion::from_res(*ident, res))
586583
}));
587584
}
588585
Scope::ToolPrelude => {
589586
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
590587
suggestions.extend(
591588
this.registered_tools
592589
.iter()
593-
.map(|ident| TypoSuggestion::from_res(ident.name, res)),
590+
.map(|ident| TypoSuggestion::from_res(*ident, res)),
594591
);
595592
}
596593
Scope::StdLibPrelude => {
@@ -608,7 +605,8 @@ impl<'a> Resolver<'a> {
608605
let primitive_types = &this.primitive_type_table.primitive_types;
609606
suggestions.extend(primitive_types.iter().flat_map(|(name, prim_ty)| {
610607
let res = Res::PrimTy(*prim_ty);
611-
filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
608+
filter_fn(res)
609+
.then_some(TypoSuggestion::from_res(Ident::with_dummy_span(*name), res))
612610
}))
613611
}
614612
}
@@ -620,12 +618,12 @@ impl<'a> Resolver<'a> {
620618
suggestions.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
621619

622620
match find_best_match_for_name(
623-
suggestions.iter().map(|suggestion| &suggestion.candidate),
621+
suggestions.iter().map(|suggestion| &suggestion.candidate.name),
624622
&ident.as_str(),
625623
None,
626624
) {
627625
Some(found) if found != ident.name => {
628-
suggestions.into_iter().find(|suggestion| suggestion.candidate == found)
626+
suggestions.into_iter().find(|suggestion| suggestion.candidate.name == found)
629627
}
630628
_ => None,
631629
}
@@ -805,7 +803,7 @@ impl<'a> Resolver<'a> {
805803
) -> bool {
806804
if let Some(suggestion) = suggestion {
807805
// We shouldn't suggest underscore.
808-
if suggestion.candidate == kw::Underscore {
806+
if suggestion.candidate.name == kw::Underscore {
809807
return false;
810808
}
811809

@@ -814,12 +812,6 @@ impl<'a> Resolver<'a> {
814812
suggestion.res.article(),
815813
suggestion.res.descr()
816814
);
817-
err.span_suggestion(
818-
span,
819-
&msg,
820-
suggestion.candidate.to_string(),
821-
Applicability::MaybeIncorrect,
822-
);
823815
let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
824816
LOCAL_CRATE => self.definitions.opt_span(def_id),
825817
_ => Some(
@@ -828,16 +820,24 @@ impl<'a> Resolver<'a> {
828820
.def_span(self.cstore().get_span_untracked(def_id, self.session)),
829821
),
830822
});
823+
let candidate = def_span
824+
.as_ref()
825+
.map(|span| Ident::new(suggestion.candidate.name, *span))
826+
.unwrap_or(suggestion.candidate);
827+
828+
err.span_suggestion(span, &msg, candidate.to_string(), Applicability::MaybeIncorrect);
829+
831830
if let Some(span) = def_span {
832831
err.span_label(
833832
span,
834833
&format!(
835834
"similarly named {} `{}` defined here",
836835
suggestion.res.descr(),
837-
suggestion.candidate.as_str(),
836+
candidate.to_string(),
838837
),
839838
);
840839
}
840+
841841
return true;
842842
}
843843
false

src/librustc_resolve/late/diagnostics.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
647647
// Locals and type parameters
648648
for (ident, &res) in &rib.bindings {
649649
if filter_fn(res) {
650-
names.push(TypoSuggestion::from_res(ident.name, res));
650+
names.push(TypoSuggestion::from_res(*ident, res));
651651
}
652652
}
653653
// Items in scope
@@ -672,7 +672,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
672672
);
673673

674674
if filter_fn(crate_mod) {
675-
Some(TypoSuggestion::from_res(ident.name, crate_mod))
675+
Some(TypoSuggestion::from_res(*ident, crate_mod))
676676
} else {
677677
None
678678
}
@@ -689,11 +689,14 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
689689
}
690690
// Add primitive types to the mix
691691
if filter_fn(Res::PrimTy(PrimTy::Bool)) {
692-
names.extend(
693-
self.r.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
694-
TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
695-
}),
696-
)
692+
names.extend(self.r.primitive_type_table.primitive_types.iter().map(
693+
|(name, prim_ty)| {
694+
TypoSuggestion::from_res(
695+
Ident::with_dummy_span(*name),
696+
Res::PrimTy(*prim_ty),
697+
)
698+
},
699+
))
697700
}
698701
} else {
699702
// Search in module.
@@ -712,12 +715,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
712715
names.sort_by_cached_key(|suggestion| suggestion.candidate.as_str());
713716

714717
match find_best_match_for_name(
715-
names.iter().map(|suggestion| &suggestion.candidate),
718+
names.iter().map(|suggestion| &suggestion.candidate.name),
716719
&name.as_str(),
717720
None,
718721
) {
719722
Some(found) if found != name => {
720-
names.into_iter().find(|suggestion| suggestion.candidate == found)
723+
names.into_iter().find(|suggestion| suggestion.candidate.name == found)
721724
}
722725
_ => None,
723726
}

src/test/ui/span/issue-68962.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn r#fn() {}
2+
3+
fn main() {
4+
let r#final = 1;
5+
6+
// Should correctly suggest variable defined using raw identifier.
7+
fina; //~ ERROR cannot find value
8+
9+
// Should correctly suggest function defined using raw identifier.
10+
f(); //~ ERROR cannot find function
11+
}

src/test/ui/span/issue-68962.stderr

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0425]: cannot find value `fina` in this scope
2+
--> $DIR/issue-68962.rs:7:5
3+
|
4+
LL | fina;
5+
| ^^^^ help: a local variable with a similar name exists: `r#final`
6+
7+
error[E0425]: cannot find function `f` in this scope
8+
--> $DIR/issue-68962.rs:10:5
9+
|
10+
LL | fn r#fn() {}
11+
| ------------ similarly named function `r#fn` defined here
12+
...
13+
LL | f();
14+
| ^ help: a function with a similar name exists: `r#fn`
15+
16+
error: aborting due to 2 previous errors
17+
18+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)