Rollup merge of #113331 - chenyukang:yukang-fix-112590-false-positive, r=estebank

Add filter with following segment while lookup typo for path

From the discussion: https://github.com/rust-lang/rust/pull/112917#discussion_r1239150173

Seems we can not get the assoc items for `Struct`, `Enum` in the resolving phase.
A obvious filter is avoid suggesting the same name with the following segment path.

Use `following_seg` can extend the function `smart_resolve_partial_mod_path_errors` for more scenarios, such as `std::sync_error::atomic::AtomicBool` in test case.

r? `@estebank`
This commit is contained in:
Matthias Krüger 2023-07-10 12:01:32 +02:00 committed by GitHub
commit 70c637808f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 301 additions and 46 deletions

View File

@ -3503,7 +3503,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let report_errors = |this: &mut Self, res: Option<Res>| { let report_errors = |this: &mut Self, res: Option<Res>| {
if this.should_report_errs() { if this.should_report_errs() {
let (err, candidates) = let (err, candidates) =
this.smart_resolve_report_errors(path, path, path_span, source, res); this.smart_resolve_report_errors(path, None, path_span, source, res);
let def_id = this.parent_scope.module.nearest_parent_mod(); let def_id = this.parent_scope.module.nearest_parent_mod();
let instead = res.is_some(); let instead = res.is_some();
@ -3555,14 +3555,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Before we start looking for candidates, we have to get our hands // Before we start looking for candidates, we have to get our hands
// on the type user is trying to perform invocation on; basically: // on the type user is trying to perform invocation on; basically:
// we're transforming `HashMap::new` into just `HashMap`. // we're transforming `HashMap::new` into just `HashMap`.
let prefix_path = match path.split_last() { let (following_seg, prefix_path) = match path.split_last() {
Some((_, path)) if !path.is_empty() => path, Some((last, path)) if !path.is_empty() => (Some(last), path),
_ => return Some(parent_err), _ => return Some(parent_err),
}; };
let (mut err, candidates) = this.smart_resolve_report_errors( let (mut err, candidates) = this.smart_resolve_report_errors(
prefix_path, prefix_path,
path, following_seg,
path_span, path_span,
PathSource::Type, PathSource::Type,
None, None,

View File

@ -332,15 +332,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
pub(crate) fn smart_resolve_partial_mod_path_errors( pub(crate) fn smart_resolve_partial_mod_path_errors(
&mut self, &mut self,
prefix_path: &[Segment], prefix_path: &[Segment],
path: &[Segment], following_seg: Option<&Segment>,
) -> Vec<ImportSuggestion> { ) -> Vec<ImportSuggestion> {
let next_seg = if path.len() >= prefix_path.len() + 1 && prefix_path.len() == 1 {
path.get(prefix_path.len())
} else {
None
};
if let Some(segment) = prefix_path.last() && if let Some(segment) = prefix_path.last() &&
let Some(next_seg) = next_seg { let Some(following_seg) = following_seg
{
let candidates = self.r.lookup_import_candidates( let candidates = self.r.lookup_import_candidates(
segment.ident, segment.ident,
Namespace::TypeNS, Namespace::TypeNS,
@ -353,9 +349,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.filter(|candidate| { .filter(|candidate| {
if let Some(def_id) = candidate.did && if let Some(def_id) = candidate.did &&
let Some(module) = self.r.get_module(def_id) { let Some(module) = self.r.get_module(def_id) {
self.r.resolutions(module).borrow().iter().any(|(key, _r)| { Some(def_id) != self.parent_scope.module.opt_def_id() &&
key.ident.name == next_seg.ident.name self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
}) key.ident.name == following_seg.ident.name
})
} else { } else {
false false
} }
@ -371,7 +368,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
pub(crate) fn smart_resolve_report_errors( pub(crate) fn smart_resolve_report_errors(
&mut self, &mut self,
path: &[Segment], path: &[Segment],
full_path: &[Segment], following_seg: Option<&Segment>,
span: Span, span: Span,
source: PathSource<'_>, source: PathSource<'_>,
res: Option<Res>, res: Option<Res>,
@ -412,8 +409,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
return (err, Vec::new()); return (err, Vec::new());
} }
let (found, candidates) = let (found, candidates) = self.try_lookup_name_relaxed(
self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error); &mut err,
source,
path,
following_seg,
span,
res,
&base_error,
);
if found { if found {
return (err, candidates); return (err, candidates);
} }
@ -422,7 +426,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
// if we have suggested using pattern matching, then don't add needless suggestions // if we have suggested using pattern matching, then don't add needless suggestions
// for typos. // for typos.
fallback |= self.suggest_typo(&mut err, source, path, span, &base_error); fallback |= self.suggest_typo(&mut err, source, path, following_seg, span, &base_error);
if fallback { if fallback {
// Fallback label. // Fallback label.
@ -519,7 +523,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err: &mut Diagnostic, err: &mut Diagnostic,
source: PathSource<'_>, source: PathSource<'_>,
path: &[Segment], path: &[Segment],
full_path: &[Segment], following_seg: Option<&Segment>,
span: Span, span: Span,
res: Option<Res>, res: Option<Res>,
base_error: &BaseError, base_error: &BaseError,
@ -590,8 +594,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
} }
// Try finding a suitable replacement. // Try finding a suitable replacement.
let typo_sugg = let typo_sugg = self
self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion(); .lookup_typo_candidate(path, following_seg, 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) = if let Some(candidate) =
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call()) self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
@ -690,7 +695,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
} }
if candidates.is_empty() { if candidates.is_empty() {
candidates = self.smart_resolve_partial_mod_path_errors(path, full_path); candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);
} }
return (false, candidates); return (false, candidates);
@ -776,12 +781,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err: &mut Diagnostic, err: &mut Diagnostic,
source: PathSource<'_>, source: PathSource<'_>,
path: &[Segment], path: &[Segment],
following_seg: Option<&Segment>,
span: Span, span: Span,
base_error: &BaseError, base_error: &BaseError,
) -> bool { ) -> bool {
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, following_seg, source.namespace(), is_expected);
let is_in_same_file = &|sp1, sp2| { let is_in_same_file = &|sp1, sp2| {
let source_map = self.r.tcx.sess.source_map(); let source_map = self.r.tcx.sess.source_map();
let file1 = source_map.span_to_filename(sp1); let file1 = source_map.span_to_filename(sp1);
@ -1715,6 +1722,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
fn lookup_typo_candidate( fn lookup_typo_candidate(
&mut self, &mut self,
path: &[Segment], path: &[Segment],
following_seg: Option<&Segment>,
ns: Namespace, ns: Namespace,
filter_fn: &impl Fn(Res) -> bool, filter_fn: &impl Fn(Res) -> bool,
) -> TypoCandidate { ) -> TypoCandidate {
@ -1793,6 +1801,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
} }
} }
// if next_seg is present, let's filter everything that does not continue the path
if let Some(following_seg) = following_seg {
names.retain(|suggestion| match suggestion.res {
Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _) => {
// FIXME: this is not totally accurate, but mostly works
suggestion.candidate != following_seg.ident.name
}
Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
|| false,
|module| {
self.r
.resolutions(module)
.borrow()
.iter()
.any(|(key, _)| key.ident.name == following_seg.ident.name)
},
),
_ => true,
});
}
let name = path[path.len() - 1].ident.name; let name = path[path.len() - 1].ident.name;
// Make sure error reporting is deterministic. // Make sure error reporting is deterministic.
names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str())); names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));

View File

@ -13,6 +13,15 @@ LL | let _: u8 = ::core::default::Default();
| ^^^^ maybe a missing crate `core`? | ^^^^ maybe a missing crate `core`?
| |
= help: consider adding `extern crate core` to use the `core` crate = help: consider adding `extern crate core` to use the `core` crate
help: consider importing this module
|
LL + use std::default;
|
help: if you import `default`, refer to it directly
|
LL - let _: u8 = ::core::default::Default();
LL + let _: u8 = default::Default();
|
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -0,0 +1,29 @@
// edition:2018
#![feature(decl_macro)]
macro a() {
extern crate core as my_core;
mod v {
// Early resolution.
use my_core; //~ ERROR unresolved import `my_core`
}
mod u {
// Late resolution.
fn f() { my_core::mem::drop(0); }
//~^ ERROR failed to resolve: use of undeclared crate or module `my_core`
}
}
a!();
mod v {
// Early resolution.
use my_core; //~ ERROR unresolved import `my_core`
}
mod u {
// Late resolution.
fn f() { my_core::mem::drop(0); }
//~^ ERROR failed to resolve: use of undeclared crate or module `my_core`
}
fn main() {}

View File

@ -0,0 +1,53 @@
error[E0432]: unresolved import `my_core`
--> $DIR/extern-prelude-from-opaque-fail-2018.rs:21:9
|
LL | use my_core;
| ^^^^^^^ no external crate `my_core`
error[E0432]: unresolved import `my_core`
--> $DIR/extern-prelude-from-opaque-fail-2018.rs:8:13
|
LL | use my_core;
| ^^^^^^^ no external crate `my_core`
...
LL | a!();
| ---- in this macro invocation
|
= note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0433]: failed to resolve: use of undeclared crate or module `my_core`
--> $DIR/extern-prelude-from-opaque-fail-2018.rs:12:18
|
LL | fn f() { my_core::mem::drop(0); }
| ^^^^^^^ use of undeclared crate or module `my_core`
...
LL | a!();
| ---- in this macro invocation
|
= help: consider importing one of these items:
std::mem
core::mem
= note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0433]: failed to resolve: use of undeclared crate or module `my_core`
--> $DIR/extern-prelude-from-opaque-fail-2018.rs:25:14
|
LL | fn f() { my_core::mem::drop(0); }
| ^^^^^^^ use of undeclared crate or module `my_core`
|
help: consider importing one of these items
|
LL + use core::mem;
|
LL + use std::mem;
|
help: if you import `mem`, refer to it directly
|
LL - fn f() { my_core::mem::drop(0); }
LL + fn f() { mem::drop(0); }
|
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0432, E0433.
For more information about an error, try `rustc --explain E0432`.

View File

@ -1,3 +1,4 @@
// edition:2015
#![feature(decl_macro)] #![feature(decl_macro)]
macro a() { macro a() {

View File

@ -1,11 +1,11 @@
error[E0432]: unresolved import `my_core` error[E0432]: unresolved import `my_core`
--> $DIR/extern-prelude-from-opaque-fail.rs:20:9 --> $DIR/extern-prelude-from-opaque-fail.rs:21:9
| |
LL | use my_core; LL | use my_core;
| ^^^^^^^ no `my_core` in the root | ^^^^^^^ no `my_core` in the root
error[E0432]: unresolved import `my_core` error[E0432]: unresolved import `my_core`
--> $DIR/extern-prelude-from-opaque-fail.rs:7:13 --> $DIR/extern-prelude-from-opaque-fail.rs:8:13
| |
LL | use my_core; LL | use my_core;
| ^^^^^^^ no `my_core` in the root | ^^^^^^^ no `my_core` in the root
@ -16,7 +16,7 @@ LL | a!();
= note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0433]: failed to resolve: use of undeclared crate or module `my_core` error[E0433]: failed to resolve: use of undeclared crate or module `my_core`
--> $DIR/extern-prelude-from-opaque-fail.rs:11:18 --> $DIR/extern-prelude-from-opaque-fail.rs:12:18
| |
LL | fn f() { my_core::mem::drop(0); } LL | fn f() { my_core::mem::drop(0); }
| ^^^^^^^ use of undeclared crate or module `my_core` | ^^^^^^^ use of undeclared crate or module `my_core`
@ -24,13 +24,25 @@ LL | fn f() { my_core::mem::drop(0); }
LL | a!(); LL | a!();
| ---- in this macro invocation | ---- in this macro invocation
| |
= help: consider importing this module:
my_core::mem
= note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0433]: failed to resolve: use of undeclared crate or module `my_core` error[E0433]: failed to resolve: use of undeclared crate or module `my_core`
--> $DIR/extern-prelude-from-opaque-fail.rs:24:14 --> $DIR/extern-prelude-from-opaque-fail.rs:25:14
| |
LL | fn f() { my_core::mem::drop(0); } LL | fn f() { my_core::mem::drop(0); }
| ^^^^^^^ use of undeclared crate or module `my_core` | ^^^^^^^ use of undeclared crate or module `my_core`
|
help: consider importing this module
|
LL + use my_core::mem;
|
help: if you import `mem`, refer to it directly
|
LL - fn f() { my_core::mem::drop(0); }
LL + fn f() { mem::drop(0); }
|
error: aborting due to 4 previous errors error: aborting due to 4 previous errors

View File

@ -26,10 +26,6 @@ error[E0433]: failed to resolve: use of undeclared crate or module `vec`
LL | type B = vec::Vec<u8>; LL | type B = vec::Vec<u8>;
| ^^^ use of undeclared crate or module `vec` | ^^^ use of undeclared crate or module `vec`
| |
help: a struct with a similar name exists
|
LL | type B = Vec::Vec<u8>;
| ~~~
help: consider importing this module help: consider importing this module
| |
LL + use std::vec; LL + use std::vec;

View File

@ -0,0 +1,34 @@
// run-rustfix
use std::vec;
use std::sync::atomic::AtomicBool;
mod foo {
pub mod bar {
pub mod baz {
pub use std::vec::Vec as MyVec;
}
}
}
mod u {
use foo::bar::baz::MyVec;
fn _a() {
let _: Vec<i32> = MyVec::new(); //~ ERROR failed to resolve
}
}
mod v {
use foo::bar::baz::MyVec;
fn _b() {
let _: Vec<i32> = MyVec::new(); //~ ERROR failed to resolve
}
}
fn main() {
let _t: Vec<i32> = Vec::new(); //~ ERROR failed to resolve
type _B = vec::Vec::<u8>; //~ ERROR failed to resolve
let _t = AtomicBool::new(true); //~ ERROR failed to resolve
}

View File

@ -0,0 +1,26 @@
// run-rustfix
mod foo {
pub mod bar {
pub mod baz {
pub use std::vec::Vec as MyVec;
}
}
}
mod u {
fn _a() {
let _: Vec<i32> = super::foo::baf::baz::MyVec::new(); //~ ERROR failed to resolve
}
}
mod v {
fn _b() {
let _: Vec<i32> = fox::bar::baz::MyVec::new(); //~ ERROR failed to resolve
}
}
fn main() {
let _t: Vec<i32> = vec::new(); //~ ERROR failed to resolve
type _B = vec::Vec::<u8>; //~ ERROR failed to resolve
let _t = std::sync_error::atomic::AtomicBool::new(true); //~ ERROR failed to resolve
}

View File

@ -0,0 +1,71 @@
error[E0433]: failed to resolve: could not find `baf` in `foo`
--> $DIR/112590-2.rs:12:39
|
LL | let _: Vec<i32> = super::foo::baf::baz::MyVec::new();
| ^^^ could not find `baf` in `foo`
|
help: consider importing this struct through its public re-export
|
LL + use foo::bar::baz::MyVec;
|
help: if you import `MyVec`, refer to it directly
|
LL - let _: Vec<i32> = super::foo::baf::baz::MyVec::new();
LL + let _: Vec<i32> = MyVec::new();
|
error[E0433]: failed to resolve: use of undeclared crate or module `fox`
--> $DIR/112590-2.rs:18:27
|
LL | let _: Vec<i32> = fox::bar::baz::MyVec::new();
| ^^^ use of undeclared crate or module `fox`
|
help: consider importing this struct through its public re-export
|
LL + use foo::bar::baz::MyVec;
|
help: if you import `MyVec`, refer to it directly
|
LL - let _: Vec<i32> = fox::bar::baz::MyVec::new();
LL + let _: Vec<i32> = MyVec::new();
|
error[E0433]: failed to resolve: use of undeclared crate or module `vec`
--> $DIR/112590-2.rs:24:15
|
LL | type _B = vec::Vec::<u8>;
| ^^^ use of undeclared crate or module `vec`
|
help: consider importing this module
|
LL + use std::vec;
|
error[E0433]: failed to resolve: could not find `sync_error` in `std`
--> $DIR/112590-2.rs:25:19
|
LL | let _t = std::sync_error::atomic::AtomicBool::new(true);
| ^^^^^^^^^^ could not find `sync_error` in `std`
|
help: consider importing this struct
|
LL + use std::sync::atomic::AtomicBool;
|
help: if you import `AtomicBool`, refer to it directly
|
LL - let _t = std::sync_error::atomic::AtomicBool::new(true);
LL + let _t = AtomicBool::new(true);
|
error[E0433]: failed to resolve: use of undeclared crate or module `vec`
--> $DIR/112590-2.rs:23:24
|
LL | let _t: Vec<i32> = vec::new();
| ^^^
| |
| use of undeclared crate or module `vec`
| help: a struct with a similar name exists (notice the capitalization): `Vec`
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0433`.

View File

@ -3,11 +3,6 @@ error[E0433]: failed to resolve: use of undeclared crate or module `foo`
| |
LL | pub fn bar() { foo::baz(); } LL | pub fn bar() { foo::baz(); }
| ^^^ use of undeclared crate or module `foo` | ^^^ use of undeclared crate or module `foo`
|
help: consider importing this module
|
LL + use crate::foo;
|
error: aborting due to previous error error: aborting due to previous error

View File

@ -3,11 +3,6 @@ error[E0433]: failed to resolve: use of undeclared crate or module `foo`
| |
LL | pub fn bar() { foo::baz(); } LL | pub fn bar() { foo::baz(); }
| ^^^ use of undeclared crate or module `foo` | ^^^ use of undeclared crate or module `foo`
|
help: consider importing this module
|
LL + use foo;
|
error: aborting due to previous error error: aborting due to previous error

View File

@ -30,17 +30,23 @@ help: there is a crate or module with a similar name
| |
LL | bar: std::cell::Cell<bool> LL | bar: std::cell::Cell<bool>
| ~~~ | ~~~
help: consider importing one of these items
|
LL + use core::cell;
|
LL + use std::cell;
|
help: if you import `cell`, refer to it directly
|
LL - bar: st::cell::Cell<bool>
LL + bar: cell::Cell<bool>
|
error[E0433]: failed to resolve: use of undeclared crate or module `bar` error[E0433]: failed to resolve: use of undeclared crate or module `bar`
--> $DIR/crate-or-module-typo.rs:6:20 --> $DIR/crate-or-module-typo.rs:6:20
| |
LL | pub fn bar() { bar::baz(); } LL | pub fn bar() { bar::baz(); }
| ^^^ use of undeclared crate or module `bar` | ^^^ use of undeclared crate or module `bar`
|
help: consider importing this module
|
LL + use crate::bar;
|
error: aborting due to 4 previous errors error: aborting due to 4 previous errors