Auto merge of #112917 - chenyukang:yukang-fix-112590, r=estebank
Suggest importing for partial mod path matching in name resolving Fixes #112590
This commit is contained in:
commit
e728b5b98d
10 changed files with 174 additions and 14 deletions
|
@ -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_span, source, res);
|
this.smart_resolve_report_errors(path, path, 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();
|
||||||
|
@ -3560,8 +3560,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
_ => return Some(parent_err),
|
_ => return Some(parent_err),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mut err, candidates) =
|
let (mut err, candidates) = this.smart_resolve_report_errors(
|
||||||
this.smart_resolve_report_errors(prefix_path, path_span, PathSource::Type, None);
|
prefix_path,
|
||||||
|
path,
|
||||||
|
path_span,
|
||||||
|
PathSource::Type,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
// There are two different error messages user might receive at
|
// There are two different error messages user might receive at
|
||||||
// this point:
|
// this point:
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseS
|
||||||
use crate::{errors, path_names_to_string};
|
use crate::{errors, path_names_to_string};
|
||||||
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
|
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
|
||||||
use crate::{PathResult, PathSource, Segment};
|
use crate::{PathResult, PathSource, Segment};
|
||||||
|
use rustc_hir::def::Namespace::{self, *};
|
||||||
|
|
||||||
use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
|
use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
|
||||||
use rustc_ast::{
|
use rustc_ast::{
|
||||||
|
@ -17,7 +18,6 @@ use rustc_errors::{
|
||||||
MultiSpan,
|
MultiSpan,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Namespace::{self, *};
|
|
||||||
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
|
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
|
||||||
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
||||||
use rustc_hir::PrimTy;
|
use rustc_hir::PrimTy;
|
||||||
|
@ -221,10 +221,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
let suggestion = if self.current_trait_ref.is_none()
|
let suggestion = if self.current_trait_ref.is_none()
|
||||||
&& let Some((fn_kind, _)) = self.diagnostic_metadata.current_function
|
&& let Some((fn_kind, _)) = self.diagnostic_metadata.current_function
|
||||||
&& let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
|
&& let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
|
||||||
|
&& let FnKind::Fn(_, _, sig, ..) = fn_kind
|
||||||
&& let Some(items) = self.diagnostic_metadata.current_impl_items
|
&& let Some(items) = self.diagnostic_metadata.current_impl_items
|
||||||
&& let Some(item) = items.iter().find(|i| {
|
&& let Some(item) = items.iter().find(|i| {
|
||||||
if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
|
if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
|
||||||
&& i.ident.name == item_str.name
|
&& i.ident.name == item_str.name
|
||||||
|
// don't suggest if the item is in Fn signature arguments
|
||||||
|
// issue #112590
|
||||||
|
&& !sig.span.contains(item_span)
|
||||||
{
|
{
|
||||||
debug!(?item_str.name);
|
debug!(?item_str.name);
|
||||||
return true
|
return true
|
||||||
|
@ -318,11 +322,56 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to suggest for a module path that cannot be resolved.
|
||||||
|
/// Such as `fmt::Debug` where `fmt` is not resolved without importing,
|
||||||
|
/// here we search with `lookup_import_candidates` for a module named `fmt`
|
||||||
|
/// with `TypeNS` as namespace.
|
||||||
|
///
|
||||||
|
/// We need a separate function here because we won't suggest for a path with single segment
|
||||||
|
/// and we won't change `SourcePath` api `is_expected` to match `Type` with `DefKind::Mod`
|
||||||
|
pub(crate) fn smart_resolve_partial_mod_path_errors(
|
||||||
|
&mut self,
|
||||||
|
prefix_path: &[Segment],
|
||||||
|
path: &[Segment],
|
||||||
|
) -> 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() &&
|
||||||
|
let Some(next_seg) = next_seg {
|
||||||
|
let candidates = self.r.lookup_import_candidates(
|
||||||
|
segment.ident,
|
||||||
|
Namespace::TypeNS,
|
||||||
|
&self.parent_scope,
|
||||||
|
&|res: Res| matches!(res, Res::Def(DefKind::Mod, _)),
|
||||||
|
);
|
||||||
|
// double check next seg is valid
|
||||||
|
candidates
|
||||||
|
.into_iter()
|
||||||
|
.filter(|candidate| {
|
||||||
|
if let Some(def_id) = candidate.did &&
|
||||||
|
let Some(module) = self.r.get_module(def_id) {
|
||||||
|
self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
|
||||||
|
key.ident.name == next_seg.ident.name
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handles error reporting for `smart_resolve_path_fragment` function.
|
/// Handles error reporting for `smart_resolve_path_fragment` function.
|
||||||
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
|
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
|
||||||
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],
|
||||||
span: Span,
|
span: Span,
|
||||||
source: PathSource<'_>,
|
source: PathSource<'_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
|
@ -364,7 +413,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let (found, candidates) =
|
let (found, candidates) =
|
||||||
self.try_lookup_name_relaxed(&mut err, source, path, span, res, &base_error);
|
self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error);
|
||||||
if found {
|
if found {
|
||||||
return (err, candidates);
|
return (err, candidates);
|
||||||
}
|
}
|
||||||
|
@ -470,6 +519,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],
|
||||||
span: Span,
|
span: Span,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
base_error: &BaseError,
|
base_error: &BaseError,
|
||||||
|
@ -639,6 +689,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if candidates.is_empty() {
|
||||||
|
candidates = self.smart_resolve_partial_mod_path_errors(path, full_path);
|
||||||
|
}
|
||||||
|
|
||||||
return (false, candidates);
|
return (false, candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,21 +3,37 @@ error[E0433]: failed to resolve: use of undeclared crate or module `env`
|
||||||
|
|
|
|
||||||
LL | env::current_dir;
|
LL | env::current_dir;
|
||||||
| ^^^ use of undeclared crate or module `env`
|
| ^^^ use of undeclared crate or module `env`
|
||||||
|
|
||||||
error[E0433]: failed to resolve: use of undeclared crate or module `vec`
|
|
||||||
--> $DIR/builtin-prelude-no-accidents.rs:7:14
|
|
||||||
|
|
|
|
||||||
LL | type B = vec::Vec<u8>;
|
help: consider importing this module
|
||||||
| ^^^
|
|
|
||||||
| |
|
LL + use std::env;
|
||||||
| use of undeclared crate or module `vec`
|
|
|
||||||
| help: a struct with a similar name exists (notice the capitalization): `Vec`
|
|
||||||
|
|
||||||
error[E0433]: failed to resolve: use of undeclared crate or module `panic`
|
error[E0433]: failed to resolve: use of undeclared crate or module `panic`
|
||||||
--> $DIR/builtin-prelude-no-accidents.rs:6:14
|
--> $DIR/builtin-prelude-no-accidents.rs:6:14
|
||||||
|
|
|
|
||||||
LL | type A = panic::PanicInfo;
|
LL | type A = panic::PanicInfo;
|
||||||
| ^^^^^ use of undeclared crate or module `panic`
|
| ^^^^^ use of undeclared crate or module `panic`
|
||||||
|
|
|
||||||
|
help: consider importing this module
|
||||||
|
|
|
||||||
|
LL + use std::panic;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared crate or module `vec`
|
||||||
|
--> $DIR/builtin-prelude-no-accidents.rs:7:14
|
||||||
|
|
|
||||||
|
LL | type B = vec::Vec<u8>;
|
||||||
|
| ^^^ 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
|
||||||
|
|
|
||||||
|
LL + use std::vec;
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
13
tests/ui/resolve/export-fully-qualified-2018.rs
Normal file
13
tests/ui/resolve/export-fully-qualified-2018.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
// In this test baz isn't resolved when called as foo.baz even though
|
||||||
|
// it's called from inside foo. This is somewhat surprising and may
|
||||||
|
// want to change eventually.
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared crate or module `foo`
|
||||||
|
|
||||||
|
fn baz() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
14
tests/ui/resolve/export-fully-qualified-2018.stderr
Normal file
14
tests/ui/resolve/export-fully-qualified-2018.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0433]: failed to resolve: use of undeclared crate or module `foo`
|
||||||
|
--> $DIR/export-fully-qualified-2018.rs:8:20
|
||||||
|
|
|
||||||
|
LL | pub fn bar() { foo::baz(); }
|
||||||
|
| ^^^ use of undeclared crate or module `foo`
|
||||||
|
|
|
||||||
|
help: consider importing this module
|
||||||
|
|
|
||||||
|
LL + use crate::foo;
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0433`.
|
|
@ -1,3 +1,5 @@
|
||||||
|
// edition:2015
|
||||||
|
|
||||||
// In this test baz isn't resolved when called as foo.baz even though
|
// In this test baz isn't resolved when called as foo.baz even though
|
||||||
// it's called from inside foo. This is somewhat surprising and may
|
// it's called from inside foo. This is somewhat surprising and may
|
||||||
// want to change eventually.
|
// want to change eventually.
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
error[E0433]: failed to resolve: use of undeclared crate or module `foo`
|
error[E0433]: failed to resolve: use of undeclared crate or module `foo`
|
||||||
--> $DIR/export-fully-qualified.rs:6:20
|
--> $DIR/export-fully-qualified.rs:8:20
|
||||||
|
|
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,11 @@ error[E0433]: failed to resolve: use of undeclared crate or module `bar`
|
||||||
|
|
|
|
||||||
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
|
||||||
|
|
||||||
|
|
10
tests/ui/suggestions/issue-112590-suggest-import.rs
Normal file
10
tests/ui/suggestions/issue-112590-suggest-import.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
pub struct S;
|
||||||
|
|
||||||
|
impl fmt::Debug for S { //~ ERROR failed to resolve: use of undeclared crate or module `fmt`
|
||||||
|
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { //~ ERROR failed to resolve: use of undeclared crate or module `fmt`
|
||||||
|
//~^ ERROR failed to resolve: use of undeclared crate or module `fmt`
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
36
tests/ui/suggestions/issue-112590-suggest-import.stderr
Normal file
36
tests/ui/suggestions/issue-112590-suggest-import.stderr
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
error[E0433]: failed to resolve: use of undeclared crate or module `fmt`
|
||||||
|
--> $DIR/issue-112590-suggest-import.rs:3:6
|
||||||
|
|
|
||||||
|
LL | impl fmt::Debug for S {
|
||||||
|
| ^^^ use of undeclared crate or module `fmt`
|
||||||
|
|
|
||||||
|
help: consider importing this module
|
||||||
|
|
|
||||||
|
LL + use std::fmt;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared crate or module `fmt`
|
||||||
|
--> $DIR/issue-112590-suggest-import.rs:4:28
|
||||||
|
|
|
||||||
|
LL | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
| ^^^ use of undeclared crate or module `fmt`
|
||||||
|
|
|
||||||
|
help: consider importing this module
|
||||||
|
|
|
||||||
|
LL + use std::fmt;
|
||||||
|
|
|
||||||
|
|
||||||
|
error[E0433]: failed to resolve: use of undeclared crate or module `fmt`
|
||||||
|
--> $DIR/issue-112590-suggest-import.rs:4:51
|
||||||
|
|
|
||||||
|
LL | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
| ^^^ use of undeclared crate or module `fmt`
|
||||||
|
|
|
||||||
|
help: consider importing this module
|
||||||
|
|
|
||||||
|
LL + use std::fmt;
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0433`.
|
Loading…
Add table
Add a link
Reference in a new issue