Skip to content

Commit e728b5b

Browse files
committed
Auto merge of rust-lang#112917 - chenyukang:yukang-fix-112590, r=estebank
Suggest importing for partial mod path matching in name resolving Fixes rust-lang#112590
2 parents 0ab38e9 + b26701e commit e728b5b

10 files changed

+174
-14
lines changed

compiler/rustc_resolve/src/late.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -3503,7 +3503,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
35033503
let report_errors = |this: &mut Self, res: Option<Res>| {
35043504
if this.should_report_errs() {
35053505
let (err, candidates) =
3506-
this.smart_resolve_report_errors(path, path_span, source, res);
3506+
this.smart_resolve_report_errors(path, path, path_span, source, res);
35073507

35083508
let def_id = this.parent_scope.module.nearest_parent_mod();
35093509
let instead = res.is_some();
@@ -3560,8 +3560,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
35603560
_ => return Some(parent_err),
35613561
};
35623562

3563-
let (mut err, candidates) =
3564-
this.smart_resolve_report_errors(prefix_path, path_span, PathSource::Type, None);
3563+
let (mut err, candidates) = this.smart_resolve_report_errors(
3564+
prefix_path,
3565+
path,
3566+
path_span,
3567+
PathSource::Type,
3568+
None,
3569+
);
35653570

35663571
// There are two different error messages user might receive at
35673572
// this point:

compiler/rustc_resolve/src/late/diagnostics.rs

+56-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseS
44
use crate::{errors, path_names_to_string};
55
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
66
use crate::{PathResult, PathSource, Segment};
7+
use rustc_hir::def::Namespace::{self, *};
78

89
use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
910
use rustc_ast::{
@@ -17,7 +18,6 @@ use rustc_errors::{
1718
MultiSpan,
1819
};
1920
use rustc_hir as hir;
20-
use rustc_hir::def::Namespace::{self, *};
2121
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
2222
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
2323
use rustc_hir::PrimTy;
@@ -221,10 +221,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
221221
let suggestion = if self.current_trait_ref.is_none()
222222
&& let Some((fn_kind, _)) = self.diagnostic_metadata.current_function
223223
&& let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
224+
&& let FnKind::Fn(_, _, sig, ..) = fn_kind
224225
&& let Some(items) = self.diagnostic_metadata.current_impl_items
225226
&& let Some(item) = items.iter().find(|i| {
226227
if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
227228
&& i.ident.name == item_str.name
229+
// don't suggest if the item is in Fn signature arguments
230+
// issue #112590
231+
&& !sig.span.contains(item_span)
228232
{
229233
debug!(?item_str.name);
230234
return true
@@ -318,11 +322,56 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
318322
}
319323
}
320324

325+
/// Try to suggest for a module path that cannot be resolved.
326+
/// Such as `fmt::Debug` where `fmt` is not resolved without importing,
327+
/// here we search with `lookup_import_candidates` for a module named `fmt`
328+
/// with `TypeNS` as namespace.
329+
///
330+
/// We need a separate function here because we won't suggest for a path with single segment
331+
/// and we won't change `SourcePath` api `is_expected` to match `Type` with `DefKind::Mod`
332+
pub(crate) fn smart_resolve_partial_mod_path_errors(
333+
&mut self,
334+
prefix_path: &[Segment],
335+
path: &[Segment],
336+
) -> Vec<ImportSuggestion> {
337+
let next_seg = if path.len() >= prefix_path.len() + 1 && prefix_path.len() == 1 {
338+
path.get(prefix_path.len())
339+
} else {
340+
None
341+
};
342+
if let Some(segment) = prefix_path.last() &&
343+
let Some(next_seg) = next_seg {
344+
let candidates = self.r.lookup_import_candidates(
345+
segment.ident,
346+
Namespace::TypeNS,
347+
&self.parent_scope,
348+
&|res: Res| matches!(res, Res::Def(DefKind::Mod, _)),
349+
);
350+
// double check next seg is valid
351+
candidates
352+
.into_iter()
353+
.filter(|candidate| {
354+
if let Some(def_id) = candidate.did &&
355+
let Some(module) = self.r.get_module(def_id) {
356+
self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
357+
key.ident.name == next_seg.ident.name
358+
})
359+
} else {
360+
false
361+
}
362+
})
363+
.collect::<Vec<_>>()
364+
} else {
365+
Vec::new()
366+
}
367+
}
368+
321369
/// Handles error reporting for `smart_resolve_path_fragment` function.
322370
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
323371
pub(crate) fn smart_resolve_report_errors(
324372
&mut self,
325373
path: &[Segment],
374+
full_path: &[Segment],
326375
span: Span,
327376
source: PathSource<'_>,
328377
res: Option<Res>,
@@ -364,7 +413,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
364413
}
365414

366415
let (found, candidates) =
367-
self.try_lookup_name_relaxed(&mut err, source, path, span, res, &base_error);
416+
self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error);
368417
if found {
369418
return (err, candidates);
370419
}
@@ -470,6 +519,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
470519
err: &mut Diagnostic,
471520
source: PathSource<'_>,
472521
path: &[Segment],
522+
full_path: &[Segment],
473523
span: Span,
474524
res: Option<Res>,
475525
base_error: &BaseError,
@@ -639,6 +689,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
639689
}
640690
}
641691

692+
if candidates.is_empty() {
693+
candidates = self.smart_resolve_partial_mod_path_errors(path, full_path);
694+
}
695+
642696
return (false, candidates);
643697
}
644698

tests/ui/macros/builtin-prelude-no-accidents.stderr

+24-8
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,37 @@ error[E0433]: failed to resolve: use of undeclared crate or module `env`
33
|
44
LL | env::current_dir;
55
| ^^^ use of undeclared crate or module `env`
6-
7-
error[E0433]: failed to resolve: use of undeclared crate or module `vec`
8-
--> $DIR/builtin-prelude-no-accidents.rs:7:14
96
|
10-
LL | type B = vec::Vec<u8>;
11-
| ^^^
12-
| |
13-
| use of undeclared crate or module `vec`
14-
| help: a struct with a similar name exists (notice the capitalization): `Vec`
7+
help: consider importing this module
8+
|
9+
LL + use std::env;
10+
|
1511

1612
error[E0433]: failed to resolve: use of undeclared crate or module `panic`
1713
--> $DIR/builtin-prelude-no-accidents.rs:6:14
1814
|
1915
LL | type A = panic::PanicInfo;
2016
| ^^^^^ use of undeclared crate or module `panic`
17+
|
18+
help: consider importing this module
19+
|
20+
LL + use std::panic;
21+
|
22+
23+
error[E0433]: failed to resolve: use of undeclared crate or module `vec`
24+
--> $DIR/builtin-prelude-no-accidents.rs:7:14
25+
|
26+
LL | type B = vec::Vec<u8>;
27+
| ^^^ use of undeclared crate or module `vec`
28+
|
29+
help: a struct with a similar name exists
30+
|
31+
LL | type B = Vec::Vec<u8>;
32+
| ~~~
33+
help: consider importing this module
34+
|
35+
LL + use std::vec;
36+
|
2137

2238
error: aborting due to 3 previous errors
2339

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// edition:2018
2+
3+
// In this test baz isn't resolved when called as foo.baz even though
4+
// it's called from inside foo. This is somewhat surprising and may
5+
// want to change eventually.
6+
7+
mod foo {
8+
pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared crate or module `foo`
9+
10+
fn baz() { }
11+
}
12+
13+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0433]: failed to resolve: use of undeclared crate or module `foo`
2+
--> $DIR/export-fully-qualified-2018.rs:8:20
3+
|
4+
LL | pub fn bar() { foo::baz(); }
5+
| ^^^ use of undeclared crate or module `foo`
6+
|
7+
help: consider importing this module
8+
|
9+
LL + use crate::foo;
10+
|
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0433`.

tests/ui/resolve/export-fully-qualified.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// edition:2015
2+
13
// In this test baz isn't resolved when called as foo.baz even though
24
// it's called from inside foo. This is somewhat surprising and may
35
// want to change eventually.

tests/ui/resolve/export-fully-qualified.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
error[E0433]: failed to resolve: use of undeclared crate or module `foo`
2-
--> $DIR/export-fully-qualified.rs:6:20
2+
--> $DIR/export-fully-qualified.rs:8:20
33
|
44
LL | pub fn bar() { foo::baz(); }
55
| ^^^ use of undeclared crate or module `foo`
6+
|
7+
help: consider importing this module
8+
|
9+
LL + use foo;
10+
|
611

712
error: aborting due to previous error
813

tests/ui/suggestions/crate-or-module-typo.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ error[E0433]: failed to resolve: use of undeclared crate or module `bar`
3636
|
3737
LL | pub fn bar() { bar::baz(); }
3838
| ^^^ use of undeclared crate or module `bar`
39+
|
40+
help: consider importing this module
41+
|
42+
LL + use crate::bar;
43+
|
3944

4045
error: aborting due to 4 previous errors
4146

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
pub struct S;
2+
3+
impl fmt::Debug for S { //~ ERROR failed to resolve: use of undeclared crate or module `fmt`
4+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { //~ ERROR failed to resolve: use of undeclared crate or module `fmt`
5+
//~^ ERROR failed to resolve: use of undeclared crate or module `fmt`
6+
Ok(())
7+
}
8+
}
9+
10+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
error[E0433]: failed to resolve: use of undeclared crate or module `fmt`
2+
--> $DIR/issue-112590-suggest-import.rs:3:6
3+
|
4+
LL | impl fmt::Debug for S {
5+
| ^^^ use of undeclared crate or module `fmt`
6+
|
7+
help: consider importing this module
8+
|
9+
LL + use std::fmt;
10+
|
11+
12+
error[E0433]: failed to resolve: use of undeclared crate or module `fmt`
13+
--> $DIR/issue-112590-suggest-import.rs:4:28
14+
|
15+
LL | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
16+
| ^^^ use of undeclared crate or module `fmt`
17+
|
18+
help: consider importing this module
19+
|
20+
LL + use std::fmt;
21+
|
22+
23+
error[E0433]: failed to resolve: use of undeclared crate or module `fmt`
24+
--> $DIR/issue-112590-suggest-import.rs:4:51
25+
|
26+
LL | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
27+
| ^^^ use of undeclared crate or module `fmt`
28+
|
29+
help: consider importing this module
30+
|
31+
LL + use std::fmt;
32+
|
33+
34+
error: aborting due to 3 previous errors
35+
36+
For more information about this error, try `rustc --explain E0433`.

0 commit comments

Comments
 (0)