Skip to content

Commit 3143472

Browse files
authored
Rollup merge of rust-lang#103560 - zbyrn:issue-103358-fix, r=cjgillot
Point only to the identifiers in the typo suggestions of shadowed names instead of the entire struct Fixes rust-lang#103358. As discussed in the issue, the `Span` of the candidate `Ident` for a typo replacement is stored alongside its `Symbol` in `TypoSuggestion`. Then, the span of the identifier is what the "you might have meant to refer to" note is pointed at, rather than the entire struct definition. Comments in rust-lang#103111 and the issue both suggest that it is desirable to: 1. include names defined in the same crate as the typo, 2. ignore names defined elsewhere such as in `std`, _and_ 3. include names introduced indirectly via `use`. Since a name from another crate but introduced via `use` has non-local `def_id`, to achieve this, a suggestion is displayed if either the `def_id` of the suggested name is local, or the `span` of the suggested name is in the same file as the typo itself. Some UI tests have also been modified to reflect this change. r? `@cjgillot`
2 parents b4cf523 + 0eaf6d5 commit 3143472

File tree

5 files changed

+63
-39
lines changed

5 files changed

+63
-39
lines changed

compiler/rustc_resolve/src/diagnostics.rs

+31-14
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,32 @@ pub(crate) enum SuggestionTarget {
5858
#[derive(Debug)]
5959
pub(crate) struct TypoSuggestion {
6060
pub candidate: Symbol,
61+
/// The source location where the name is defined; None if the name is not defined
62+
/// in source e.g. primitives
63+
pub span: Option<Span>,
6164
pub res: Res,
6265
pub target: SuggestionTarget,
6366
}
6467

6568
impl TypoSuggestion {
66-
pub(crate) fn typo_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
67-
Self { candidate, res, target: SuggestionTarget::SimilarlyNamed }
69+
pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
70+
Self {
71+
candidate: ident.name,
72+
span: Some(ident.span),
73+
res,
74+
target: SuggestionTarget::SimilarlyNamed,
75+
}
76+
}
77+
pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
78+
Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
6879
}
69-
pub(crate) fn single_item_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
70-
Self { candidate, res, target: SuggestionTarget::SingleItem }
80+
pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
81+
Self {
82+
candidate: ident.name,
83+
span: Some(ident.span),
84+
res,
85+
target: SuggestionTarget::SingleItem,
86+
}
7187
}
7288
}
7389

@@ -490,7 +506,7 @@ impl<'a> Resolver<'a> {
490506
if let Some(binding) = resolution.borrow().binding {
491507
let res = binding.res();
492508
if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
493-
names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
509+
names.push(TypoSuggestion::typo_from_ident(key.ident, res));
494510
}
495511
}
496512
}
@@ -1145,7 +1161,7 @@ impl<'a> Resolver<'a> {
11451161
.get(&expn_id)
11461162
.into_iter()
11471163
.flatten()
1148-
.map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
1164+
.map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
11491165
);
11501166
}
11511167
}
@@ -1164,7 +1180,7 @@ impl<'a> Resolver<'a> {
11641180
suggestions.extend(
11651181
ext.helper_attrs
11661182
.iter()
1167-
.map(|name| TypoSuggestion::typo_from_res(*name, res)),
1183+
.map(|name| TypoSuggestion::typo_from_name(*name, res)),
11681184
);
11691185
}
11701186
}
@@ -1174,8 +1190,8 @@ impl<'a> Resolver<'a> {
11741190
if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
11751191
let res = macro_rules_binding.binding.res();
11761192
if filter_fn(res) {
1177-
suggestions.push(TypoSuggestion::typo_from_res(
1178-
macro_rules_binding.ident.name,
1193+
suggestions.push(TypoSuggestion::typo_from_ident(
1194+
macro_rules_binding.ident,
11791195
res,
11801196
))
11811197
}
@@ -1193,7 +1209,7 @@ impl<'a> Resolver<'a> {
11931209
suggestions.extend(this.macro_use_prelude.iter().filter_map(
11941210
|(name, binding)| {
11951211
let res = binding.res();
1196-
filter_fn(res).then_some(TypoSuggestion::typo_from_res(*name, res))
1212+
filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
11971213
},
11981214
));
11991215
}
@@ -1203,22 +1219,22 @@ impl<'a> Resolver<'a> {
12031219
suggestions.extend(
12041220
BUILTIN_ATTRIBUTES
12051221
.iter()
1206-
.map(|attr| TypoSuggestion::typo_from_res(attr.name, res)),
1222+
.map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
12071223
);
12081224
}
12091225
}
12101226
Scope::ExternPrelude => {
12111227
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
12121228
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
1213-
filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res))
1229+
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
12141230
}));
12151231
}
12161232
Scope::ToolPrelude => {
12171233
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
12181234
suggestions.extend(
12191235
this.registered_tools
12201236
.iter()
1221-
.map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
1237+
.map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
12221238
);
12231239
}
12241240
Scope::StdLibPrelude => {
@@ -1235,7 +1251,8 @@ impl<'a> Resolver<'a> {
12351251
Scope::BuiltinTypes => {
12361252
suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
12371253
let res = Res::PrimTy(*prim_ty);
1238-
filter_fn(res).then_some(TypoSuggestion::typo_from_res(prim_ty.name(), res))
1254+
filter_fn(res)
1255+
.then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
12391256
}))
12401257
}
12411258
}

compiler/rustc_resolve/src/late/diagnostics.rs

+21-15
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,15 @@ struct BaseError {
150150
#[derive(Debug)]
151151
enum TypoCandidate {
152152
Typo(TypoSuggestion),
153-
Shadowed(Res),
153+
Shadowed(Res, Option<Span>),
154154
None,
155155
}
156156

157157
impl TypoCandidate {
158158
fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
159159
match self {
160160
TypoCandidate::Typo(sugg) => Some(sugg),
161-
TypoCandidate::Shadowed(_) | TypoCandidate::None => None,
161+
TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None,
162162
}
163163
}
164164
}
@@ -691,9 +691,20 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
691691
let is_expected = &|res| source.is_expected(res);
692692
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
693693
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
694-
if let TypoCandidate::Shadowed(res) = typo_sugg
695-
&& let Some(id) = res.opt_def_id()
696-
&& let Some(sugg_span) = self.r.opt_span(id)
694+
let is_in_same_file = &|sp1, sp2| {
695+
let source_map = self.r.session.source_map();
696+
let file1 = source_map.span_to_filename(sp1);
697+
let file2 = source_map.span_to_filename(sp2);
698+
file1 == file2
699+
};
700+
// print 'you might have meant' if the candidate is (1) is a shadowed name with
701+
// accessible definition and (2) either defined in the same crate as the typo
702+
// (could be in a different file) or introduced in the same file as the typo
703+
// (could belong to a different crate)
704+
if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg
705+
&& res
706+
.opt_def_id()
707+
.map_or(false, |id| id.is_local() || is_in_same_file(span, sugg_span))
697708
{
698709
err.span_label(
699710
sugg_span,
@@ -970,10 +981,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
970981
.collect();
971982
if targets.len() == 1 {
972983
let target = targets[0];
973-
return Some(TypoSuggestion::single_item_from_res(
974-
target.0.ident.name,
975-
target.1,
976-
));
984+
return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
977985
}
978986
}
979987
}
@@ -1615,7 +1623,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16151623
// Locals and type parameters
16161624
for (ident, &res) in &rib.bindings {
16171625
if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
1618-
names.push(TypoSuggestion::typo_from_res(ident.name, res));
1626+
names.push(TypoSuggestion::typo_from_ident(*ident, res));
16191627
}
16201628
}
16211629

@@ -1644,9 +1652,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16441652
Res::Def(DefKind::Mod, crate_id.as_def_id());
16451653

16461654
if filter_fn(crate_mod) {
1647-
Some(TypoSuggestion::typo_from_res(
1648-
ident.name, crate_mod,
1649-
))
1655+
Some(TypoSuggestion::typo_from_ident(*ident, crate_mod))
16501656
} else {
16511657
None
16521658
}
@@ -1665,7 +1671,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16651671
// Add primitive types to the mix
16661672
if filter_fn(Res::PrimTy(PrimTy::Bool)) {
16671673
names.extend(PrimTy::ALL.iter().map(|prim_ty| {
1668-
TypoSuggestion::typo_from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
1674+
TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty))
16691675
}))
16701676
}
16711677
} else {
@@ -1692,7 +1698,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16921698
return TypoCandidate::None;
16931699
};
16941700
if found == name {
1695-
TypoCandidate::Shadowed(sugg.res)
1701+
TypoCandidate::Shadowed(sugg.res, sugg.span)
16961702
} else {
16971703
TypoCandidate::Typo(sugg)
16981704
}

src/test/ui/lexical-scopes.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0574]: expected struct, variant or union type, found type parameter `T`
22
--> $DIR/lexical-scopes.rs:3:13
33
|
44
LL | struct T { i: i32 }
5-
| ------------------- you might have meant to refer to this struct
5+
| - you might have meant to refer to this struct
66
LL | fn f<T>() {
77
| - found this type parameter
88
LL | let t = T { i: 0 };

src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
error[E0574]: expected struct, variant or union type, found type parameter `Baz`
22
--> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13
33
|
4-
LL | / struct Baz {
5-
LL | | num: usize,
6-
LL | | }
7-
| |_- you might have meant to refer to this struct
8-
LL |
9-
LL | impl<Baz> Foo<Baz> for Bar {
10-
| --- found this type parameter
4+
LL | struct Baz {
5+
| --- you might have meant to refer to this struct
116
...
12-
LL | Baz { num } => num,
13-
| ^^^ not a struct, variant or union type
7+
LL | impl<Baz> Foo<Baz> for Bar {
8+
| --- found this type parameter
9+
...
10+
LL | Baz { num } => num,
11+
| ^^^ not a struct, variant or union type
1412

1513
error: aborting due to previous error
1614

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

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0404]: expected trait, found type parameter `Add`
22
--> $DIR/issue-35987.rs:5:21
33
|
4+
LL | use std::ops::Add;
5+
| --- you might have meant to refer to this trait
6+
LL |
47
LL | impl<T: Clone, Add> Add for Foo<T> {
58
| --- ^^^ not a trait
69
| |

0 commit comments

Comments
 (0)