Skip to content

Commit 41a1cfd

Browse files
authored
Rollup merge of #103111 - cjgillot:shadow-label, r=estebank
Account for hygiene in typo suggestions, and use them to point to shadowed names Fixes #97459 r? `@estebank`
2 parents e11511d + 4bbb163 commit 41a1cfd

9 files changed

+102
-32
lines changed

Diff for: compiler/rustc_resolve/src/diagnostics.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_span::hygiene::MacroKind;
2424
use rustc_span::lev_distance::find_best_match_for_name;
2525
use rustc_span::source_map::SourceMap;
2626
use rustc_span::symbol::{kw, sym, Ident, Symbol};
27-
use rustc_span::{BytePos, Span};
27+
use rustc_span::{BytePos, Span, SyntaxContext};
2828

2929
use crate::imports::{Import, ImportKind, ImportResolver};
3030
use crate::late::{PatternSource, Rib};
@@ -47,13 +47,15 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
4747
/// similarly named label and whether or not it is reachable.
4848
pub(crate) type LabelSuggestion = (Ident, bool);
4949

50+
#[derive(Debug)]
5051
pub(crate) enum SuggestionTarget {
5152
/// The target has a similar name as the name used by the programmer (probably a typo)
5253
SimilarlyNamed,
5354
/// The target is the only valid item that can be used in the corresponding context
5455
SingleItem,
5556
}
5657

58+
#[derive(Debug)]
5759
pub(crate) struct TypoSuggestion {
5860
pub candidate: Symbol,
5961
pub res: Res,
@@ -482,11 +484,12 @@ impl<'a> Resolver<'a> {
482484
module: Module<'a>,
483485
names: &mut Vec<TypoSuggestion>,
484486
filter_fn: &impl Fn(Res) -> bool,
487+
ctxt: Option<SyntaxContext>,
485488
) {
486489
for (key, resolution) in self.resolutions(module).borrow().iter() {
487490
if let Some(binding) = resolution.borrow().binding {
488491
let res = binding.res();
489-
if filter_fn(res) {
492+
if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
490493
names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
491494
}
492495
}
@@ -1181,10 +1184,10 @@ impl<'a> Resolver<'a> {
11811184
Scope::CrateRoot => {
11821185
let root_ident = Ident::new(kw::PathRoot, ident.span);
11831186
let root_module = this.resolve_crate_root(root_ident);
1184-
this.add_module_candidates(root_module, &mut suggestions, filter_fn);
1187+
this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
11851188
}
11861189
Scope::Module(module, _) => {
1187-
this.add_module_candidates(module, &mut suggestions, filter_fn);
1190+
this.add_module_candidates(module, &mut suggestions, filter_fn, None);
11881191
}
11891192
Scope::MacroUsePrelude => {
11901193
suggestions.extend(this.macro_use_prelude.iter().filter_map(
@@ -1221,7 +1224,7 @@ impl<'a> Resolver<'a> {
12211224
Scope::StdLibPrelude => {
12221225
if let Some(prelude) = this.prelude {
12231226
let mut tmp_suggestions = Vec::new();
1224-
this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn);
1227+
this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
12251228
suggestions.extend(
12261229
tmp_suggestions
12271230
.into_iter()

Diff for: compiler/rustc_resolve/src/late/diagnostics.rs

+61-9
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ pub(super) enum LifetimeElisionCandidate {
131131
}
132132

133133
/// Only used for diagnostics.
134+
#[derive(Debug)]
134135
struct BaseError {
135136
msg: String,
136137
fallback_label: String,
@@ -140,6 +141,22 @@ struct BaseError {
140141
suggestion: Option<(Span, &'static str, String)>,
141142
}
142143

144+
#[derive(Debug)]
145+
enum TypoCandidate {
146+
Typo(TypoSuggestion),
147+
Shadowed(Res),
148+
None,
149+
}
150+
151+
impl TypoCandidate {
152+
fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
153+
match self {
154+
TypoCandidate::Typo(sugg) => Some(sugg),
155+
TypoCandidate::Shadowed(_) | TypoCandidate::None => None,
156+
}
157+
}
158+
}
159+
143160
impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
144161
fn def_span(&self, def_id: DefId) -> Option<Span> {
145162
match def_id.krate {
@@ -496,7 +513,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
496513
}
497514

498515
// Try Levenshtein algorithm.
499-
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
516+
let typo_sugg =
517+
self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
500518
if path.len() == 1 && self.self_type_is_available() {
501519
if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
502520
let self_is_available = self.self_value_is_available(path[0].ident.span);
@@ -660,7 +678,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
660678
let is_expected = &|res| source.is_expected(res);
661679
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
662680
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
681+
if let TypoCandidate::Shadowed(res) = typo_sugg
682+
&& let Some(id) = res.opt_def_id()
683+
&& let Some(sugg_span) = self.r.opt_span(id)
684+
{
685+
err.span_label(
686+
sugg_span,
687+
format!("you might have meant to refer to this {}", res.descr()),
688+
);
689+
return true;
690+
}
663691
let mut fallback = false;
692+
let typo_sugg = typo_sugg.to_opt_suggestion();
664693
if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
665694
fallback = true;
666695
match self.diagnostic_metadata.current_let_binding {
@@ -1581,22 +1610,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
15811610
path: &[Segment],
15821611
ns: Namespace,
15831612
filter_fn: &impl Fn(Res) -> bool,
1584-
) -> Option<TypoSuggestion> {
1613+
) -> TypoCandidate {
15851614
let mut names = Vec::new();
15861615
if path.len() == 1 {
1616+
let mut ctxt = path.last().unwrap().ident.span.ctxt();
1617+
15871618
// Search in lexical scope.
15881619
// Walk backwards up the ribs in scope and collect candidates.
15891620
for rib in self.ribs[ns].iter().rev() {
1621+
let rib_ctxt = if rib.kind.contains_params() {
1622+
ctxt.normalize_to_macros_2_0()
1623+
} else {
1624+
ctxt.normalize_to_macro_rules()
1625+
};
1626+
15901627
// Locals and type parameters
15911628
for (ident, &res) in &rib.bindings {
1592-
if filter_fn(res) {
1629+
if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
15931630
names.push(TypoSuggestion::typo_from_res(ident.name, res));
15941631
}
15951632
}
1633+
1634+
if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) {
1635+
// If an invocation of this macro created `ident`, give up on `ident`
1636+
// and switch to `ident`'s source from the macro definition.
1637+
ctxt.remove_mark();
1638+
continue;
1639+
}
1640+
15961641
// Items in scope
15971642
if let RibKind::ModuleRibKind(module) = rib.kind {
15981643
// Items from this module
1599-
self.r.add_module_candidates(module, &mut names, &filter_fn);
1644+
self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
16001645

16011646
if let ModuleKind::Block = module.kind {
16021647
// We can see through blocks
@@ -1622,7 +1667,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16221667
}));
16231668

16241669
if let Some(prelude) = self.r.prelude {
1625-
self.r.add_module_candidates(prelude, &mut names, &filter_fn);
1670+
self.r.add_module_candidates(prelude, &mut names, &filter_fn, None);
16261671
}
16271672
}
16281673
break;
@@ -1641,7 +1686,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16411686
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
16421687
self.resolve_path(mod_path, Some(TypeNS), None)
16431688
{
1644-
self.r.add_module_candidates(module, &mut names, &filter_fn);
1689+
self.r.add_module_candidates(module, &mut names, &filter_fn, None);
16451690
}
16461691
}
16471692

@@ -1654,10 +1699,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
16541699
name,
16551700
None,
16561701
) {
1657-
Some(found) if found != name => {
1658-
names.into_iter().find(|suggestion| suggestion.candidate == found)
1702+
Some(found) => {
1703+
let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else {
1704+
return TypoCandidate::None;
1705+
};
1706+
if found == name {
1707+
TypoCandidate::Shadowed(sugg.res)
1708+
} else {
1709+
TypoCandidate::Typo(sugg)
1710+
}
16591711
}
1660-
_ => None,
1712+
_ => TypoCandidate::None,
16611713
}
16621714
}
16631715

Diff for: src/test/ui/hygiene/globs.stderr

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
error[E0425]: cannot find function `f` in this scope
22
--> $DIR/globs.rs:22:9
33
|
4+
LL | pub fn g() {}
5+
| ---------- similarly named function `g` defined here
6+
...
47
LL | f();
5-
| ^ not found in this scope
8+
| ^
9+
|
10+
help: a function with a similar name exists
611
|
12+
LL | g();
13+
| ~
714
help: consider importing this function
815
|
916
LL | use foo::f;
@@ -12,8 +19,11 @@ LL | use foo::f;
1219
error[E0425]: cannot find function `g` in this scope
1320
--> $DIR/globs.rs:15:5
1421
|
22+
LL | pub fn f() {}
23+
| ---------- similarly named function `f` defined here
24+
...
1525
LL | g();
16-
| ^ not found in this scope
26+
| ^
1727
...
1828
LL | / m! {
1929
LL | | use bar::*;
@@ -23,6 +33,10 @@ LL | | }
2333
| |_____- in this macro invocation
2434
|
2535
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
36+
help: a function with a similar name exists
37+
|
38+
LL | f();
39+
| ~
2640
help: consider importing this function
2741
|
2842
LL | use bar::g;

Diff for: src/test/ui/hygiene/rustc-macro-transparency.stderr

+1-7
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,8 @@ LL | semitransparent;
1919
error[E0423]: expected value, found macro `opaque`
2020
--> $DIR/rustc-macro-transparency.rs:30:5
2121
|
22-
LL | struct Opaque;
23-
| -------------- similarly named unit struct `Opaque` defined here
24-
...
2522
LL | opaque;
26-
| ^^^^^^
27-
| |
28-
| not a value
29-
| help: a unit struct with a similar name exists (notice the capitalization): `Opaque`
23+
| ^^^^^^ not a value
3024

3125
error: aborting due to 3 previous errors
3226

Diff for: src/test/ui/lexical-scopes.stderr

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

Diff for: src/test/ui/macros/macro-context.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ error[E0425]: cannot find value `i` in this scope
5757
--> $DIR/macro-context.rs:3:13
5858
|
5959
LL | () => ( i ; typeof );
60-
| ^ help: a local variable with a similar name exists: `a`
60+
| ^ not found in this scope
6161
...
6262
LL | let i = m!();
6363
| ---- in this macro invocation

Diff for: src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ error[E0425]: cannot find value `local_use` in this scope
1313
--> $DIR/gen-macro-rules-hygiene.rs:12:1
1414
|
1515
LL | gen_macro_rules!();
16-
| ^^^^^^^^^^^^^^^^^^ not found in this scope
16+
| ^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def`
1717
...
1818
LL | generated!();
1919
| ------------ in this macro invocation
@@ -24,7 +24,7 @@ error[E0425]: cannot find value `local_def` in this scope
2424
--> $DIR/gen-macro-rules-hygiene.rs:21:9
2525
|
2626
LL | local_def;
27-
| ^^^^^^^^^ not found in this scope
27+
| ^^^^^^^^^ help: a local variable with a similar name exists: `local_use`
2828

2929
error: aborting due to 3 previous errors
3030

Diff for: src/test/ui/proc-macro/mixed-site-span.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ error[E0425]: cannot find value `local_use` in this scope
1010
--> $DIR/mixed-site-span.rs:13:9
1111
|
1212
LL | proc_macro_rules!();
13-
| ^^^^^^^^^^^^^^^^^^^ not found in this scope
13+
| ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def`
1414
|
1515
= note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info)
1616

1717
error[E0425]: cannot find value `local_def` in this scope
1818
--> $DIR/mixed-site-span.rs:17:9
1919
|
2020
LL | local_def;
21-
| ^^^^^^^^^ not found in this scope
21+
| ^^^^^^^^^ help: a local variable with a similar name exists: `local_use`
2222

2323
error[E0412]: cannot find type `ItemUse` in crate `$crate`
2424
--> $DIR/mixed-site-span.rs:24:1

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

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
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 | impl<Baz> Foo<Baz> for Bar {
5-
| --- found this type parameter
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
611
...
7-
LL | Baz { num } => num,
8-
| ^^^ not a struct, variant or union type
12+
LL | Baz { num } => num,
13+
| ^^^ not a struct, variant or union type
914

1015
error: aborting due to previous error
1116

0 commit comments

Comments
 (0)