diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 28 |
2 files changed, 62 insertions, 4 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 98982240af2..9a3eac2f866 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -70,6 +70,7 @@ impl TypoSuggestion { } /// A free importable items suggested in case of resolution failure. +#[derive(Debug, Clone)] pub(crate) struct ImportSuggestion { pub did: Option<DefId>, pub descr: &'static str, @@ -139,6 +140,7 @@ impl<'a> Resolver<'a> { if instead { Instead::Yes } else { Instead::No }, found_use, IsPattern::No, + IsImport::No, path, ); err.emit(); @@ -698,6 +700,7 @@ impl<'a> Resolver<'a> { Instead::No, FoundUse::Yes, IsPattern::Yes, + IsImport::No, vec![], ); } @@ -1481,6 +1484,7 @@ impl<'a> Resolver<'a> { Instead::No, FoundUse::Yes, IsPattern::No, + IsImport::No, vec![], ); @@ -2449,6 +2453,34 @@ enum IsPattern { No, } +/// Whether a binding is part of a use statement. Used for diagnostics. +enum IsImport { + Yes, + No, +} + +pub(crate) fn import_candidates( + session: &Session, + source_span: &IndexVec<LocalDefId, Span>, + err: &mut Diagnostic, + // This is `None` if all placement locations are inside expansions + use_placement_span: Option<Span>, + candidates: &[ImportSuggestion], +) { + show_candidates( + session, + source_span, + err, + use_placement_span, + candidates, + Instead::Yes, + FoundUse::Yes, + IsPattern::No, + IsImport::Yes, + vec![], + ); +} + /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way @@ -2462,6 +2494,7 @@ fn show_candidates( instead: Instead, found_use: FoundUse, is_pattern: IsPattern, + is_import: IsImport, path: Vec<Segment>, ) { if candidates.is_empty() { @@ -2521,7 +2554,8 @@ fn show_candidates( // produce an additional newline to separate the new use statement // from the directly following item. let additional_newline = if let FoundUse::Yes = found_use { "" } else { "\n" }; - candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline); + let add_use = if let IsImport::Yes = is_import { "" } else { "use " }; + candidate.0 = format!("{}{};\n{}", add_use, &candidate.0, additional_newline); } err.span_suggestions( @@ -2551,7 +2585,7 @@ fn show_candidates( err.note(&msg); } - } else { + } else if matches!(is_import, IsImport::No) { assert!(!inaccessible_path_strings.is_empty()); let prefix = diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 5bdb4274781..9e2234ae4a5 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1,9 +1,9 @@ //! A bunch of methods and structures more or less related to resolving imports. -use crate::diagnostics::Suggestion; +use crate::diagnostics::{import_candidates, Suggestion}; use crate::Determinacy::{self, *}; use crate::Namespace::{self, *}; -use crate::{module_to_string, names_to_string}; +use crate::{module_to_string, names_to_string, ImportSuggestion}; use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet}; use crate::{NameBinding, NameBindingKind, PathResult}; @@ -406,6 +406,7 @@ struct UnresolvedImportError { label: Option<String>, note: Option<String>, suggestion: Option<Suggestion>, + candidate: Option<Vec<ImportSuggestion>>, } pub struct ImportResolver<'a, 'b> { @@ -497,6 +498,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: None, note: None, suggestion: None, + candidate: None, }; if path.contains("::") { errors.push((path, err)) @@ -547,6 +549,16 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } diag.multipart_suggestion(&msg, suggestions, applicability); } + + if let Some(candidate) = &err.candidate { + import_candidates( + self.r.session, + &self.r.source_span, + &mut diag, + Some(err.span), + &candidate, + ) + } } diag.emit(); @@ -664,6 +676,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { Some(finalize), ignore_binding, ); + let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len; import.vis.set(orig_vis); let module = match path_res { @@ -706,12 +719,14 @@ impl<'a, 'b> ImportResolver<'a, 'b> { String::from("a similar path exists"), Applicability::MaybeIncorrect, )), + candidate: None, }, None => UnresolvedImportError { span, label: Some(label), note: None, suggestion, + candidate: None, }, }; return Some(err); @@ -754,6 +769,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: Some(String::from("cannot glob-import a module into itself")), note: None, suggestion: None, + candidate: None, }); } } @@ -919,11 +935,19 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } }; + let parent_suggestion = + self.r.lookup_import_candidates(ident, TypeNS, &import.parent_scope, |_| true); + Some(UnresolvedImportError { span: import.span, label: Some(label), note, suggestion, + candidate: if !parent_suggestion.is_empty() { + Some(parent_suggestion) + } else { + None + }, }) } else { // `resolve_ident_in_module` reported a privacy error. |
