diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 141 |
1 files changed, 99 insertions, 42 deletions
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b89273990..f2cc50c19 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::{MacroNS, TypeNS}; -use crate::{module_to_string, names_to_string}; +use crate::Namespace::*; +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}; @@ -23,15 +23,13 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; -use tracing::*; - use std::cell::Cell; use std::{mem, ptr}; type Res = def::Res<NodeId>; /// Contains data for specific kinds of imports. -#[derive(Clone, Debug)] +#[derive(Clone)] pub enum ImportKind<'a> { Single { /// `source` in `use prefix::source as target`. @@ -52,8 +50,8 @@ pub enum ImportKind<'a> { }, Glob { is_prelude: bool, - max_vis: Cell<ty::Visibility>, // The visibility of the greatest re-export. - // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. + max_vis: Cell<Option<ty::Visibility>>, // The visibility of the greatest re-export. + // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. }, ExternCrate { source: Option<Symbol>, @@ -62,6 +60,44 @@ pub enum ImportKind<'a> { MacroUse, } +/// Manually implement `Debug` for `ImportKind` because the `source/target_bindings` +/// contain `Cell`s which can introduce infinite loops while printing. +impl<'a> std::fmt::Debug for ImportKind<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use ImportKind::*; + match self { + Single { + ref source, + ref target, + ref type_ns_only, + ref nested, + ref additional_ids, + // Ignore the following to avoid an infinite loop while printing. + source_bindings: _, + target_bindings: _, + } => f + .debug_struct("Single") + .field("source", source) + .field("target", target) + .field("type_ns_only", type_ns_only) + .field("nested", nested) + .field("additional_ids", additional_ids) + .finish_non_exhaustive(), + Glob { ref is_prelude, ref max_vis } => f + .debug_struct("Glob") + .field("is_prelude", is_prelude) + .field("max_vis", max_vis) + .finish(), + ExternCrate { ref source, ref target } => f + .debug_struct("ExternCrate") + .field("source", source) + .field("target", target) + .finish(), + MacroUse => f.debug_struct("MacroUse").finish(), + } + } +} + /// One import. #[derive(Debug, Clone)] pub(crate) struct Import<'a> { @@ -106,7 +142,7 @@ pub(crate) struct Import<'a> { pub module_path: Vec<Segment>, /// The resolution of `module_path`. pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>, - pub vis: Cell<ty::Visibility>, + pub vis: Cell<Option<ty::Visibility>>, pub used: Cell<bool>, } @@ -121,6 +157,10 @@ impl<'a> Import<'a> { _ => false, } } + + pub(crate) fn expect_vis(&self) -> ty::Visibility { + self.vis.get().expect("encountered cleared import visibility") + } } /// Records information about the resolution of a name in a namespace of a module. @@ -161,7 +201,7 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi import: Import { kind: ImportKind::ExternCrate { .. }, .. }, .. }, - ) => import.vis.get().is_public(), + ) => import.expect_vis().is_public(), _ => false, } } @@ -174,17 +214,20 @@ impl<'a> Resolver<'a> { binding: &'a NameBinding<'a>, import: &'a Import<'a>, ) -> &'a NameBinding<'a> { - let vis = if binding.vis.is_at_least(import.vis.get(), self) + let import_vis = import.expect_vis().to_def_id(); + let vis = if binding.vis.is_at_least(import_vis, self) || pub_use_of_private_extern_crate_hack(import, binding) { - import.vis.get() + import_vis } else { binding.vis }; if let ImportKind::Glob { ref max_vis, .. } = import.kind { - if vis == import.vis.get() || vis.is_at_least(max_vis.get(), self) { - max_vis.set(vis) + if vis == import_vis + || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self)) + { + max_vis.set(Some(vis.expect_local())) } } @@ -209,7 +252,7 @@ impl<'a> Resolver<'a> { self.set_binding_parent_module(binding, module); self.update_resolution(module, key, |this, resolution| { if let Some(old_binding) = resolution.binding { - if res == Res::Err { + if res == Res::Err && old_binding.res() != Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. return Ok(()); } @@ -338,6 +381,7 @@ struct UnresolvedImportError { label: Option<String>, note: Option<String>, suggestion: Option<Suggestion>, + candidate: Option<Vec<ImportSuggestion>>, } pub struct ImportResolver<'a, 'b> { @@ -429,6 +473,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: None, note: None, suggestion: None, + candidate: None, }; if path.contains("::") { errors.push((path, err)) @@ -479,6 +524,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(); @@ -498,7 +553,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } else { // For better failure detection, pretend that the import will // not define any names while resolving its module path. - let orig_vis = import.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.take(); let path_res = self.r.maybe_resolve_path(&import.module_path, None, &import.parent_scope); import.vis.set(orig_vis); @@ -533,7 +588,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let Err(Undetermined) = source_bindings[ns].get() { // For better failure detection, pretend that the import will // not define any names while resolving its module path. - let orig_vis = import.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.take(); let binding = this.resolve_ident_in_module( module, source, @@ -582,7 +637,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// Optionally returns an unresolved import error. This error is buffered and used to /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> { - let orig_vis = import.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.take(); let ignore_binding = match &import.kind { ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(), _ => None, @@ -596,6 +651,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 { @@ -638,12 +694,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); @@ -686,12 +744,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> { label: Some(String::from("cannot glob-import a module into itself")), note: None, suggestion: None, + candidate: None, }); } } - if !is_prelude && - max_vis.get() != ty::Visibility::Invisible && // Allow empty globs. - !max_vis.get().is_at_least(import.vis.get(), &*self.r) + if !is_prelude + && let Some(max_vis) = max_vis.get() + && !max_vis.is_at_least(import.expect_vis(), &*self.r) { let msg = "glob import doesn't reexport anything because no candidate is public enough"; self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); @@ -704,7 +763,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut all_ns_err = true; self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let orig_vis = import.vis.replace(ty::Visibility::Invisible); + let orig_vis = import.vis.take(); let binding = this.resolve_ident_in_module( module, ident, @@ -851,11 +910,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. @@ -868,8 +935,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let mut crate_private_reexport = false; self.r.per_ns(|this, ns| { if let Ok(binding) = source_bindings[ns].get() { - let vis = import.vis.get(); - if !binding.vis.is_at_least(vis, &*this) { + if !binding.vis.is_at_least(import.expect_vis(), &*this) { reexport_error = Some((ns, binding)); if let ty::Visibility::Restricted(binding_def_id) = binding.vis { if binding_def_id.is_top_level_module() { @@ -1091,24 +1157,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let Some(def_id) = module.opt_def_id() { let mut reexports = Vec::new(); - module.for_each_child(self.r, |_, ident, _, binding| { - // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` - // into the crate root to actual `NameBindingKind::Import`. - if binding.is_import() - || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) - { - let res = binding.res().expect_non_local(); - // Ambiguous imports are treated as errors at this point and are - // not exposed to other crates (see #36837 for more details). - if res != def::Res::Err && !binding.is_ambiguity() { - reexports.push(ModChild { - ident, - res, - vis: binding.vis, - span: binding.span, - macro_rules: false, - }); - } + module.for_each_child(self.r, |this, ident, _, binding| { + if let Some(res) = this.is_reexport(binding) { + reexports.push(ModChild { + ident, + res, + vis: binding.vis, + span: binding.span, + macro_rules: false, + }); } }); |