Skip to content

Commit 7766f27

Browse files
authored
Rollup merge of rust-lang#102876 - SparrowLii:import-candidate, r=fee1-dead
suggest candidates for unresolved import Currently we prompt suggestion of candidates(help notes of `use xxx::yyy`) for names which cannot be resolved, but we don't do that for import statements themselves that couldn't be resolved. It seems reasonable to add candidate help information for these statements as well. Fixes rust-lang#102711
2 parents 9eefa23 + 0571b0a commit 7766f27

File tree

10 files changed

+145
-8
lines changed

10 files changed

+145
-8
lines changed

compiler/rustc_resolve/src/diagnostics.rs

+36-2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ impl TypoSuggestion {
7070
}
7171

7272
/// A free importable items suggested in case of resolution failure.
73+
#[derive(Debug, Clone)]
7374
pub(crate) struct ImportSuggestion {
7475
pub did: Option<DefId>,
7576
pub descr: &'static str,
@@ -139,6 +140,7 @@ impl<'a> Resolver<'a> {
139140
if instead { Instead::Yes } else { Instead::No },
140141
found_use,
141142
IsPattern::No,
143+
IsImport::No,
142144
path,
143145
);
144146
err.emit();
@@ -698,6 +700,7 @@ impl<'a> Resolver<'a> {
698700
Instead::No,
699701
FoundUse::Yes,
700702
IsPattern::Yes,
703+
IsImport::No,
701704
vec![],
702705
);
703706
}
@@ -1481,6 +1484,7 @@ impl<'a> Resolver<'a> {
14811484
Instead::No,
14821485
FoundUse::Yes,
14831486
IsPattern::No,
1487+
IsImport::No,
14841488
vec![],
14851489
);
14861490

@@ -2449,6 +2453,34 @@ enum IsPattern {
24492453
No,
24502454
}
24512455

2456+
/// Whether a binding is part of a use statement. Used for diagnostics.
2457+
enum IsImport {
2458+
Yes,
2459+
No,
2460+
}
2461+
2462+
pub(crate) fn import_candidates(
2463+
session: &Session,
2464+
source_span: &IndexVec<LocalDefId, Span>,
2465+
err: &mut Diagnostic,
2466+
// This is `None` if all placement locations are inside expansions
2467+
use_placement_span: Option<Span>,
2468+
candidates: &[ImportSuggestion],
2469+
) {
2470+
show_candidates(
2471+
session,
2472+
source_span,
2473+
err,
2474+
use_placement_span,
2475+
candidates,
2476+
Instead::Yes,
2477+
FoundUse::Yes,
2478+
IsPattern::No,
2479+
IsImport::Yes,
2480+
vec![],
2481+
);
2482+
}
2483+
24522484
/// When an entity with a given name is not available in scope, we search for
24532485
/// entities with that name in all crates. This method allows outputting the
24542486
/// results of this search in a programmer-friendly way
@@ -2462,6 +2494,7 @@ fn show_candidates(
24622494
instead: Instead,
24632495
found_use: FoundUse,
24642496
is_pattern: IsPattern,
2497+
is_import: IsImport,
24652498
path: Vec<Segment>,
24662499
) {
24672500
if candidates.is_empty() {
@@ -2521,7 +2554,8 @@ fn show_candidates(
25212554
// produce an additional newline to separate the new use statement
25222555
// from the directly following item.
25232556
let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" };
2524-
candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline);
2557+
let add_use = if let IsImport::Yes = is_import { "" } else { "use " };
2558+
candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline);
25252559
}
25262560

25272561
err.span_suggestions(
@@ -2551,7 +2585,7 @@ fn show_candidates(
25512585

25522586
err.note(&msg);
25532587
}
2554-
} else {
2588+
} else if matches!(is_import, IsImport::No) {
25552589
assert!(!inaccessible_path_strings.is_empty());
25562590

25572591
let prefix =

compiler/rustc_resolve/src/imports.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! A bunch of methods and structures more or less related to resolving imports.
22
3-
use crate::diagnostics::Suggestion;
3+
use crate::diagnostics::{import_candidates, Suggestion};
44
use crate::Determinacy::{self, *};
55
use crate::Namespace::{self, *};
6-
use crate::{module_to_string, names_to_string};
6+
use crate::{module_to_string, names_to_string, ImportSuggestion};
77
use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
88
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
99
use crate::{NameBinding, NameBindingKind, PathResult};
@@ -406,6 +406,7 @@ struct UnresolvedImportError {
406406
label: Option<String>,
407407
note: Option<String>,
408408
suggestion: Option<Suggestion>,
409+
candidate: Option<Vec<ImportSuggestion>>,
409410
}
410411

411412
pub struct ImportResolver<'a, 'b> {
@@ -497,6 +498,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
497498
label: None,
498499
note: None,
499500
suggestion: None,
501+
candidate: None,
500502
};
501503
if path.contains("::") {
502504
errors.push((path, err))
@@ -547,6 +549,16 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
547549
}
548550
diag.multipart_suggestion(&msg, suggestions, applicability);
549551
}
552+
553+
if let Some(candidate) = &err.candidate {
554+
import_candidates(
555+
self.r.session,
556+
&self.r.source_span,
557+
&mut diag,
558+
Some(err.span),
559+
&candidate,
560+
)
561+
}
550562
}
551563

552564
diag.emit();
@@ -664,6 +676,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
664676
Some(finalize),
665677
ignore_binding,
666678
);
679+
667680
let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
668681
import.vis.set(orig_vis);
669682
let module = match path_res {
@@ -706,12 +719,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
706719
String::from("a similar path exists"),
707720
Applicability::MaybeIncorrect,
708721
)),
722+
candidate: None,
709723
},
710724
None => UnresolvedImportError {
711725
span,
712726
label: Some(label),
713727
note: None,
714728
suggestion,
729+
candidate: None,
715730
},
716731
};
717732
return Some(err);
@@ -754,6 +769,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
754769
label: Some(String::from("cannot glob-import a module into itself")),
755770
note: None,
756771
suggestion: None,
772+
candidate: None,
757773
});
758774
}
759775
}
@@ -919,11 +935,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
919935
}
920936
};
921937

938+
let parent_suggestion =
939+
self.r.lookup_import_candidates(ident, TypeNS, &import.parent_scope, |_| true);
940+
922941
Some(UnresolvedImportError {
923942
span: import.span,
924943
label: Some(label),
925944
note,
926945
suggestion,
946+
candidate: if !parent_suggestion.is_empty() {
947+
Some(parent_suggestion)
948+
} else {
949+
None
950+
},
927951
})
928952
} else {
929953
// `resolve_ident_in_module` reported a privacy error.

src/test/ui/extenv/issue-55897.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ error[E0432]: unresolved import `env`
2626
|
2727
LL | use env;
2828
| ^^^ no `env` in the root
29+
|
30+
help: consider importing this module instead
31+
|
32+
LL | use std::env;
33+
| ~~~~~~~~~
2934

3035
error: cannot determine resolution for the macro `env`
3136
--> $DIR/issue-55897.rs:6:22

src/test/ui/imports/issue-56125.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@ error[E0432]: unresolved import `empty::issue_56125`
33
|
44
LL | use empty::issue_56125;
55
| ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty`
6+
|
7+
help: consider importing one of these items instead
8+
|
9+
LL | use crate::m3::last_segment::issue_56125;
10+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11+
LL | use crate::m3::non_last_segment::non_last_segment::issue_56125;
12+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13+
LL | use issue_56125::issue_56125;
14+
| ~~~~~~~~~~~~~~~~~~~~~~~~~
15+
LL | use issue_56125::last_segment::issue_56125;
16+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17+
and 1 other candidate
618

719
error[E0659]: `issue_56125` is ambiguous
820
--> $DIR/issue-56125.rs:6:9

src/test/ui/imports/issue-57015.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error[E0432]: unresolved import `single_err::something`
33
|
44
LL | use single_err::something;
55
| ^^^^^^^^^^^^^^^^^^^^^ no `something` in `single_err`
6+
|
7+
help: consider importing this module instead
8+
|
9+
LL | use glob_ok::something;
10+
| ~~~~~~~~~~~~~~~~~~~
611

712
error: aborting due to previous error
813

src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ error[E0432]: unresolved import `alloc`
33
|
44
LL | use alloc;
55
| ^^^^^ no external crate `alloc`
6+
|
7+
help: consider importing one of these items instead
8+
|
9+
LL | use core::alloc;
10+
| ~~~~~~~~~~~~
11+
LL | use std::alloc;
12+
| ~~~~~~~~~~~
613

714
error: aborting due to previous error
815

src/test/ui/simd/portable-intrinsics-arent-exposed.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ error[E0432]: unresolved import `std::simd::intrinsics`
1111
|
1212
LL | use std::simd::intrinsics;
1313
| ^^^^^^^^^^^^^^^^^^^^^ no `intrinsics` in `simd`
14+
|
15+
help: consider importing this module instead
16+
|
17+
LL | use std::intrinsics;
18+
| ~~~~~~~~~~~~~~~~
1419

1520
error: aborting due to 2 previous errors
1621

src/test/ui/test-attrs/inaccessible-test-modules.stderr

+10-4
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,16 @@ error[E0432]: unresolved import `test`
1111
--> $DIR/inaccessible-test-modules.rs:6:5
1212
|
1313
LL | use test as y;
14-
| ----^^^^^
15-
| |
16-
| no `test` in the root
17-
| help: a similar name exists in the module: `test`
14+
| ^^^^^^^^^ no `test` in the root
15+
|
16+
help: a similar name exists in the module
17+
|
18+
LL | use test as y;
19+
| ~~~~
20+
help: consider importing this module instead
21+
|
22+
LL | use test::test;
23+
| ~~~~~~~~~~~
1824

1925
error: aborting due to 2 previous errors
2026

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
mod a {
2+
pub trait Trait {}
3+
}
4+
5+
mod b {
6+
use Trait; //~ ERROR unresolved import `Trait`
7+
}
8+
9+
mod c {
10+
impl Trait for () {} //~ ERROR cannot find trait `Trait` in this scope
11+
}
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0432]: unresolved import `Trait`
2+
--> $DIR/unresolved-candidates.rs:6:9
3+
|
4+
LL | use Trait;
5+
| ^^^^^ no `Trait` in the root
6+
|
7+
help: consider importing this trait instead
8+
|
9+
LL | use a::Trait;
10+
| ~~~~~~~~~
11+
12+
error[E0405]: cannot find trait `Trait` in this scope
13+
--> $DIR/unresolved-candidates.rs:10:10
14+
|
15+
LL | impl Trait for () {}
16+
| ^^^^^ not found in this scope
17+
|
18+
help: consider importing this trait
19+
|
20+
LL | use a::Trait;
21+
|
22+
23+
error: aborting due to 2 previous errors
24+
25+
Some errors have detailed explanations: E0405, E0432.
26+
For more information about an error, try `rustc --explain E0405`.

0 commit comments

Comments
 (0)