Rollup merge of #103111 - cjgillot:shadow-label, r=estebank
Account for hygiene in typo suggestions, and use them to point to shadowed names Fixes https://github.com/rust-lang/rust/issues/97459 r? `@estebank`
This commit is contained in:
commit
41a1cfdbaf
9 changed files with 102 additions and 32 deletions
|
@ -24,7 +24,7 @@ use rustc_span::hygiene::MacroKind;
|
||||||
use rustc_span::lev_distance::find_best_match_for_name;
|
use rustc_span::lev_distance::find_best_match_for_name;
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::{BytePos, Span, SyntaxContext};
|
||||||
|
|
||||||
use crate::imports::{Import, ImportKind, ImportResolver};
|
use crate::imports::{Import, ImportKind, ImportResolver};
|
||||||
use crate::late::{PatternSource, Rib};
|
use crate::late::{PatternSource, Rib};
|
||||||
|
@ -47,6 +47,7 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability);
|
||||||
/// similarly named label and whether or not it is reachable.
|
/// similarly named label and whether or not it is reachable.
|
||||||
pub(crate) type LabelSuggestion = (Ident, bool);
|
pub(crate) type LabelSuggestion = (Ident, bool);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) enum SuggestionTarget {
|
pub(crate) enum SuggestionTarget {
|
||||||
/// The target has a similar name as the name used by the programmer (probably a typo)
|
/// The target has a similar name as the name used by the programmer (probably a typo)
|
||||||
SimilarlyNamed,
|
SimilarlyNamed,
|
||||||
|
@ -54,6 +55,7 @@ pub(crate) enum SuggestionTarget {
|
||||||
SingleItem,
|
SingleItem,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct TypoSuggestion {
|
pub(crate) struct TypoSuggestion {
|
||||||
pub candidate: Symbol,
|
pub candidate: Symbol,
|
||||||
pub res: Res,
|
pub res: Res,
|
||||||
|
@ -482,11 +484,12 @@ impl<'a> Resolver<'a> {
|
||||||
module: Module<'a>,
|
module: Module<'a>,
|
||||||
names: &mut Vec<TypoSuggestion>,
|
names: &mut Vec<TypoSuggestion>,
|
||||||
filter_fn: &impl Fn(Res) -> bool,
|
filter_fn: &impl Fn(Res) -> bool,
|
||||||
|
ctxt: Option<SyntaxContext>,
|
||||||
) {
|
) {
|
||||||
for (key, resolution) in self.resolutions(module).borrow().iter() {
|
for (key, resolution) in self.resolutions(module).borrow().iter() {
|
||||||
if let Some(binding) = resolution.borrow().binding {
|
if let Some(binding) = resolution.borrow().binding {
|
||||||
let res = binding.res();
|
let res = binding.res();
|
||||||
if filter_fn(res) {
|
if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
|
||||||
names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
|
names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1181,10 +1184,10 @@ impl<'a> Resolver<'a> {
|
||||||
Scope::CrateRoot => {
|
Scope::CrateRoot => {
|
||||||
let root_ident = Ident::new(kw::PathRoot, ident.span);
|
let root_ident = Ident::new(kw::PathRoot, ident.span);
|
||||||
let root_module = this.resolve_crate_root(root_ident);
|
let root_module = this.resolve_crate_root(root_ident);
|
||||||
this.add_module_candidates(root_module, &mut suggestions, filter_fn);
|
this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
|
||||||
}
|
}
|
||||||
Scope::Module(module, _) => {
|
Scope::Module(module, _) => {
|
||||||
this.add_module_candidates(module, &mut suggestions, filter_fn);
|
this.add_module_candidates(module, &mut suggestions, filter_fn, None);
|
||||||
}
|
}
|
||||||
Scope::MacroUsePrelude => {
|
Scope::MacroUsePrelude => {
|
||||||
suggestions.extend(this.macro_use_prelude.iter().filter_map(
|
suggestions.extend(this.macro_use_prelude.iter().filter_map(
|
||||||
|
@ -1221,7 +1224,7 @@ impl<'a> Resolver<'a> {
|
||||||
Scope::StdLibPrelude => {
|
Scope::StdLibPrelude => {
|
||||||
if let Some(prelude) = this.prelude {
|
if let Some(prelude) = this.prelude {
|
||||||
let mut tmp_suggestions = Vec::new();
|
let mut tmp_suggestions = Vec::new();
|
||||||
this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn);
|
this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None);
|
||||||
suggestions.extend(
|
suggestions.extend(
|
||||||
tmp_suggestions
|
tmp_suggestions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -131,6 +131,7 @@ pub(super) enum LifetimeElisionCandidate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only used for diagnostics.
|
/// Only used for diagnostics.
|
||||||
|
#[derive(Debug)]
|
||||||
struct BaseError {
|
struct BaseError {
|
||||||
msg: String,
|
msg: String,
|
||||||
fallback_label: String,
|
fallback_label: String,
|
||||||
|
@ -140,6 +141,22 @@ struct BaseError {
|
||||||
suggestion: Option<(Span, &'static str, String)>,
|
suggestion: Option<(Span, &'static str, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum TypoCandidate {
|
||||||
|
Typo(TypoSuggestion),
|
||||||
|
Shadowed(Res),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypoCandidate {
|
||||||
|
fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
|
||||||
|
match self {
|
||||||
|
TypoCandidate::Typo(sugg) => Some(sugg),
|
||||||
|
TypoCandidate::Shadowed(_) | TypoCandidate::None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
fn def_span(&self, def_id: DefId) -> Option<Span> {
|
fn def_span(&self, def_id: DefId) -> Option<Span> {
|
||||||
match def_id.krate {
|
match def_id.krate {
|
||||||
|
@ -496,7 +513,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try Levenshtein algorithm.
|
// Try Levenshtein algorithm.
|
||||||
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
|
let typo_sugg =
|
||||||
|
self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
|
||||||
if path.len() == 1 && self.self_type_is_available() {
|
if path.len() == 1 && self.self_type_is_available() {
|
||||||
if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
|
if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) {
|
||||||
let self_is_available = self.self_value_is_available(path[0].ident.span);
|
let self_is_available = self.self_value_is_available(path[0].ident.span);
|
||||||
|
@ -660,7 +678,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
let is_expected = &|res| source.is_expected(res);
|
let is_expected = &|res| source.is_expected(res);
|
||||||
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
|
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
|
||||||
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
|
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
|
||||||
|
if let TypoCandidate::Shadowed(res) = typo_sugg
|
||||||
|
&& let Some(id) = res.opt_def_id()
|
||||||
|
&& let Some(sugg_span) = self.r.opt_span(id)
|
||||||
|
{
|
||||||
|
err.span_label(
|
||||||
|
sugg_span,
|
||||||
|
format!("you might have meant to refer to this {}", res.descr()),
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
let mut fallback = false;
|
let mut fallback = false;
|
||||||
|
let typo_sugg = typo_sugg.to_opt_suggestion();
|
||||||
if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
|
if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) {
|
||||||
fallback = true;
|
fallback = true;
|
||||||
match self.diagnostic_metadata.current_let_binding {
|
match self.diagnostic_metadata.current_let_binding {
|
||||||
|
@ -1581,22 +1610,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
ns: Namespace,
|
ns: Namespace,
|
||||||
filter_fn: &impl Fn(Res) -> bool,
|
filter_fn: &impl Fn(Res) -> bool,
|
||||||
) -> Option<TypoSuggestion> {
|
) -> TypoCandidate {
|
||||||
let mut names = Vec::new();
|
let mut names = Vec::new();
|
||||||
if path.len() == 1 {
|
if path.len() == 1 {
|
||||||
|
let mut ctxt = path.last().unwrap().ident.span.ctxt();
|
||||||
|
|
||||||
// Search in lexical scope.
|
// Search in lexical scope.
|
||||||
// Walk backwards up the ribs in scope and collect candidates.
|
// Walk backwards up the ribs in scope and collect candidates.
|
||||||
for rib in self.ribs[ns].iter().rev() {
|
for rib in self.ribs[ns].iter().rev() {
|
||||||
|
let rib_ctxt = if rib.kind.contains_params() {
|
||||||
|
ctxt.normalize_to_macros_2_0()
|
||||||
|
} else {
|
||||||
|
ctxt.normalize_to_macro_rules()
|
||||||
|
};
|
||||||
|
|
||||||
// Locals and type parameters
|
// Locals and type parameters
|
||||||
for (ident, &res) in &rib.bindings {
|
for (ident, &res) in &rib.bindings {
|
||||||
if filter_fn(res) {
|
if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
|
||||||
names.push(TypoSuggestion::typo_from_res(ident.name, res));
|
names.push(TypoSuggestion::typo_from_res(ident.name, res));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) {
|
||||||
|
// If an invocation of this macro created `ident`, give up on `ident`
|
||||||
|
// and switch to `ident`'s source from the macro definition.
|
||||||
|
ctxt.remove_mark();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Items in scope
|
// Items in scope
|
||||||
if let RibKind::ModuleRibKind(module) = rib.kind {
|
if let RibKind::ModuleRibKind(module) = rib.kind {
|
||||||
// Items from this module
|
// Items from this module
|
||||||
self.r.add_module_candidates(module, &mut names, &filter_fn);
|
self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
|
||||||
|
|
||||||
if let ModuleKind::Block = module.kind {
|
if let ModuleKind::Block = module.kind {
|
||||||
// We can see through blocks
|
// We can see through blocks
|
||||||
|
@ -1622,7 +1667,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if let Some(prelude) = self.r.prelude {
|
if let Some(prelude) = self.r.prelude {
|
||||||
self.r.add_module_candidates(prelude, &mut names, &filter_fn);
|
self.r.add_module_candidates(prelude, &mut names, &filter_fn, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1641,7 +1686,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
|
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
|
||||||
self.resolve_path(mod_path, Some(TypeNS), None)
|
self.resolve_path(mod_path, Some(TypeNS), None)
|
||||||
{
|
{
|
||||||
self.r.add_module_candidates(module, &mut names, &filter_fn);
|
self.r.add_module_candidates(module, &mut names, &filter_fn, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1654,10 +1699,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||||
name,
|
name,
|
||||||
None,
|
None,
|
||||||
) {
|
) {
|
||||||
Some(found) if found != name => {
|
Some(found) => {
|
||||||
names.into_iter().find(|suggestion| suggestion.candidate == found)
|
let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else {
|
||||||
|
return TypoCandidate::None;
|
||||||
|
};
|
||||||
|
if found == name {
|
||||||
|
TypoCandidate::Shadowed(sugg.res)
|
||||||
|
} else {
|
||||||
|
TypoCandidate::Typo(sugg)
|
||||||
}
|
}
|
||||||
_ => None,
|
}
|
||||||
|
_ => TypoCandidate::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
error[E0425]: cannot find function `f` in this scope
|
error[E0425]: cannot find function `f` in this scope
|
||||||
--> $DIR/globs.rs:22:9
|
--> $DIR/globs.rs:22:9
|
||||||
|
|
|
|
||||||
|
LL | pub fn g() {}
|
||||||
|
| ---------- similarly named function `g` defined here
|
||||||
|
...
|
||||||
LL | f();
|
LL | f();
|
||||||
| ^ not found in this scope
|
| ^
|
||||||
|
|
|
|
||||||
|
help: a function with a similar name exists
|
||||||
|
|
|
||||||
|
LL | g();
|
||||||
|
| ~
|
||||||
help: consider importing this function
|
help: consider importing this function
|
||||||
|
|
|
|
||||||
LL | use foo::f;
|
LL | use foo::f;
|
||||||
|
@ -12,8 +19,11 @@ LL | use foo::f;
|
||||||
error[E0425]: cannot find function `g` in this scope
|
error[E0425]: cannot find function `g` in this scope
|
||||||
--> $DIR/globs.rs:15:5
|
--> $DIR/globs.rs:15:5
|
||||||
|
|
|
|
||||||
|
LL | pub fn f() {}
|
||||||
|
| ---------- similarly named function `f` defined here
|
||||||
|
...
|
||||||
LL | g();
|
LL | g();
|
||||||
| ^ not found in this scope
|
| ^
|
||||||
...
|
...
|
||||||
LL | / m! {
|
LL | / m! {
|
||||||
LL | | use bar::*;
|
LL | | use bar::*;
|
||||||
|
@ -23,6 +33,10 @@ LL | | }
|
||||||
| |_____- in this macro invocation
|
| |_____- in this macro invocation
|
||||||
|
|
|
|
||||||
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: a function with a similar name exists
|
||||||
|
|
|
||||||
|
LL | f();
|
||||||
|
| ~
|
||||||
help: consider importing this function
|
help: consider importing this function
|
||||||
|
|
|
|
||||||
LL | use bar::g;
|
LL | use bar::g;
|
||||||
|
|
|
@ -19,14 +19,8 @@ LL | semitransparent;
|
||||||
error[E0423]: expected value, found macro `opaque`
|
error[E0423]: expected value, found macro `opaque`
|
||||||
--> $DIR/rustc-macro-transparency.rs:30:5
|
--> $DIR/rustc-macro-transparency.rs:30:5
|
||||||
|
|
|
|
||||||
LL | struct Opaque;
|
|
||||||
| -------------- similarly named unit struct `Opaque` defined here
|
|
||||||
...
|
|
||||||
LL | opaque;
|
LL | opaque;
|
||||||
| ^^^^^^
|
| ^^^^^^ not a value
|
||||||
| |
|
|
||||||
| not a value
|
|
||||||
| help: a unit struct with a similar name exists (notice the capitalization): `Opaque`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
error[E0574]: expected struct, variant or union type, found type parameter `T`
|
error[E0574]: expected struct, variant or union type, found type parameter `T`
|
||||||
--> $DIR/lexical-scopes.rs:3:13
|
--> $DIR/lexical-scopes.rs:3:13
|
||||||
|
|
|
|
||||||
|
LL | struct T { i: i32 }
|
||||||
|
| ------------------- you might have meant to refer to this struct
|
||||||
LL | fn f<T>() {
|
LL | fn f<T>() {
|
||||||
| - found this type parameter
|
| - found this type parameter
|
||||||
LL | let t = T { i: 0 };
|
LL | let t = T { i: 0 };
|
||||||
|
|
|
@ -57,7 +57,7 @@ error[E0425]: cannot find value `i` in this scope
|
||||||
--> $DIR/macro-context.rs:3:13
|
--> $DIR/macro-context.rs:3:13
|
||||||
|
|
|
|
||||||
LL | () => ( i ; typeof );
|
LL | () => ( i ; typeof );
|
||||||
| ^ help: a local variable with a similar name exists: `a`
|
| ^ not found in this scope
|
||||||
...
|
...
|
||||||
LL | let i = m!();
|
LL | let i = m!();
|
||||||
| ---- in this macro invocation
|
| ---- in this macro invocation
|
||||||
|
|
|
@ -13,7 +13,7 @@ error[E0425]: cannot find value `local_use` in this scope
|
||||||
--> $DIR/gen-macro-rules-hygiene.rs:12:1
|
--> $DIR/gen-macro-rules-hygiene.rs:12:1
|
||||||
|
|
|
|
||||||
LL | gen_macro_rules!();
|
LL | gen_macro_rules!();
|
||||||
| ^^^^^^^^^^^^^^^^^^ not found in this scope
|
| ^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def`
|
||||||
...
|
...
|
||||||
LL | generated!();
|
LL | generated!();
|
||||||
| ------------ in this macro invocation
|
| ------------ in this macro invocation
|
||||||
|
@ -24,7 +24,7 @@ error[E0425]: cannot find value `local_def` in this scope
|
||||||
--> $DIR/gen-macro-rules-hygiene.rs:21:9
|
--> $DIR/gen-macro-rules-hygiene.rs:21:9
|
||||||
|
|
|
|
||||||
LL | local_def;
|
LL | local_def;
|
||||||
| ^^^^^^^^^ not found in this scope
|
| ^^^^^^^^^ help: a local variable with a similar name exists: `local_use`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ error[E0425]: cannot find value `local_use` in this scope
|
||||||
--> $DIR/mixed-site-span.rs:13:9
|
--> $DIR/mixed-site-span.rs:13:9
|
||||||
|
|
|
|
||||||
LL | proc_macro_rules!();
|
LL | proc_macro_rules!();
|
||||||
| ^^^^^^^^^^^^^^^^^^^ not found in this scope
|
| ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def`
|
||||||
|
|
|
|
||||||
= note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ error[E0425]: cannot find value `local_def` in this scope
|
||||||
--> $DIR/mixed-site-span.rs:17:9
|
--> $DIR/mixed-site-span.rs:17:9
|
||||||
|
|
|
|
||||||
LL | local_def;
|
LL | local_def;
|
||||||
| ^^^^^^^^^ not found in this scope
|
| ^^^^^^^^^ help: a local variable with a similar name exists: `local_use`
|
||||||
|
|
||||||
error[E0412]: cannot find type `ItemUse` in crate `$crate`
|
error[E0412]: cannot find type `ItemUse` in crate `$crate`
|
||||||
--> $DIR/mixed-site-span.rs:24:1
|
--> $DIR/mixed-site-span.rs:24:1
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
error[E0574]: expected struct, variant or union type, found type parameter `Baz`
|
error[E0574]: expected struct, variant or union type, found type parameter `Baz`
|
||||||
--> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13
|
--> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13
|
||||||
|
|
|
|
||||||
|
LL | / struct Baz {
|
||||||
|
LL | | num: usize,
|
||||||
|
LL | | }
|
||||||
|
| |_- you might have meant to refer to this struct
|
||||||
|
LL |
|
||||||
LL | impl<Baz> Foo<Baz> for Bar {
|
LL | impl<Baz> Foo<Baz> for Bar {
|
||||||
| --- found this type parameter
|
| --- found this type parameter
|
||||||
...
|
...
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue