summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve/src/imports.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
commit1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch)
tree3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /compiler/rustc_resolve/src/imports.rs
parentReleasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz
rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_resolve/src/imports.rs')
-rw-r--r--compiler/rustc_resolve/src/imports.rs133
1 files changed, 103 insertions, 30 deletions
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 4dab0836d..3c22d51c3 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -17,14 +17,18 @@ use rustc_data_structures::intern::Interned;
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_hir::def::{self, DefKind, PartialRes};
use rustc_middle::metadata::ModChild;
+use rustc_middle::metadata::Reexport;
use rustc_middle::span_bug;
use rustc_middle::ty;
-use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
+use rustc_session::lint::builtin::{
+ AMBIGUOUS_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS,
+};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::hygiene::LocalExpnId;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
+use smallvec::SmallVec;
use std::cell::Cell;
use std::{mem, ptr};
@@ -85,20 +89,28 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
Single {
ref source,
ref target,
+ ref source_bindings,
+ ref target_bindings,
ref type_ns_only,
ref nested,
ref id,
- // Ignore the following to avoid an infinite loop while printing.
- source_bindings: _,
- target_bindings: _,
} => f
.debug_struct("Single")
.field("source", source)
.field("target", target)
+ // Ignore the nested bindings to avoid an infinite loop while printing.
+ .field(
+ "source_bindings",
+ &source_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))),
+ )
+ .field(
+ "target_bindings",
+ &target_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))),
+ )
.field("type_ns_only", type_ns_only)
.field("nested", nested)
.field("id", id)
- .finish_non_exhaustive(),
+ .finish(),
Glob { ref is_prelude, ref max_vis, ref id } => f
.debug_struct("Glob")
.field("is_prelude", is_prelude)
@@ -180,6 +192,17 @@ impl<'a> Import<'a> {
ImportKind::MacroUse | ImportKind::MacroExport => None,
}
}
+
+ fn simplify(&self, r: &Resolver<'_, '_>) -> Reexport {
+ let to_def_id = |id| r.local_def_id(id).to_def_id();
+ match self.kind {
+ ImportKind::Single { id, .. } => Reexport::Single(to_def_id(id)),
+ ImportKind::Glob { id, .. } => Reexport::Glob(to_def_id(id)),
+ ImportKind::ExternCrate { id, .. } => Reexport::ExternCrate(to_def_id(id)),
+ ImportKind::MacroUse => Reexport::MacroUse,
+ ImportKind::MacroExport => Reexport::MacroExport,
+ }
+ }
}
/// Records information about the resolution of a name in a namespace of a module.
@@ -245,7 +268,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
import: &'a Import<'a>,
) -> &'a NameBinding<'a> {
let import_vis = import.expect_vis().to_def_id();
- let vis = if binding.vis.is_at_least(import_vis, self)
+ let vis = if binding.vis.is_at_least(import_vis, self.tcx)
|| pub_use_of_private_extern_crate_hack(import, binding)
{
import_vis
@@ -255,7 +278,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let ImportKind::Glob { ref max_vis, .. } = import.kind {
if vis == import_vis
- || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self))
+ || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self.tcx))
{
max_vis.set(Some(vis.expect_local()))
}
@@ -294,7 +317,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
old_binding,
binding,
));
- } else if !old_binding.vis.is_at_least(binding.vis, &*this) {
+ } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
// We are glob-importing the same item but with greater visibility.
resolution.binding = Some(binding);
}
@@ -415,13 +438,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Resolves all imports for the crate. This method performs the fixed-
/// point iteration.
pub(crate) fn resolve_imports(&mut self) {
- let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
- while self.indeterminate_imports.len() < prev_num_indeterminates {
- prev_num_indeterminates = self.indeterminate_imports.len();
+ let mut prev_indeterminate_count = usize::MAX;
+ let mut indeterminate_count = self.indeterminate_imports.len() * 3;
+ while indeterminate_count < prev_indeterminate_count {
+ prev_indeterminate_count = indeterminate_count;
+ indeterminate_count = 0;
for import in mem::take(&mut self.indeterminate_imports) {
- match self.resolve_import(&import) {
- true => self.determined_imports.push(import),
- false => self.indeterminate_imports.push(import),
+ let import_indeterminate_count = self.resolve_import(&import);
+ indeterminate_count += import_indeterminate_count;
+ match import_indeterminate_count {
+ 0 => self.determined_imports.push(import),
+ _ => self.indeterminate_imports.push(import),
}
}
}
@@ -498,6 +525,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
+ pub(crate) fn check_reexport_ambiguities(
+ &mut self,
+ exported_ambiguities: FxHashSet<Interned<'a, NameBinding<'a>>>,
+ ) {
+ for module in self.arenas.local_modules().iter() {
+ module.for_each_child(self, |this, ident, ns, binding| {
+ if let NameBindingKind::Import { import, .. } = binding.kind
+ && let Some((amb_binding, _)) = binding.ambiguity
+ && binding.res() != Res::Err
+ && exported_ambiguities.contains(&Interned::new_unchecked(binding))
+ {
+ this.lint_buffer.buffer_lint_with_diagnostic(
+ AMBIGUOUS_GLOB_REEXPORTS,
+ import.root_id,
+ import.root_span,
+ "ambiguous glob re-exports",
+ BuiltinLintDiagnostics::AmbiguousGlobReexports {
+ name: ident.to_string(),
+ namespace: ns.descr().to_string(),
+ first_reexport_span: import.root_span,
+ duplicate_reexport_span: amb_binding.span,
+ },
+ );
+ }
+ });
+ }
+ }
+
fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
if errors.is_empty() {
return;
@@ -573,9 +628,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
diag.emit();
}
- /// Attempts to resolve the given import, returning true if its resolution is determined.
- /// If successful, the resolved bindings are written into the module.
- fn resolve_import(&mut self, import: &'a Import<'a>) -> bool {
+ /// Attempts to resolve the given import, returning:
+ /// - `0` means its resolution is determined.
+ /// - Other values mean that indeterminate exists under certain namespaces.
+ ///
+ /// Meanwhile, if resolve successful, the resolved bindings are written
+ /// into the module.
+ fn resolve_import(&mut self, import: &'a Import<'a>) -> usize {
debug!(
"(resolving import for module) resolving import `{}::...` in `{}`",
Segment::names_to_string(&import.module_path),
@@ -593,8 +652,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
match path_res {
PathResult::Module(module) => module,
- PathResult::Indeterminate => return false,
- PathResult::NonModule(..) | PathResult::Failed { .. } => return true,
+ PathResult::Indeterminate => return 3,
+ PathResult::NonModule(..) | PathResult::Failed { .. } => return 0,
}
};
@@ -610,12 +669,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} => (source, target, source_bindings, target_bindings, type_ns_only),
ImportKind::Glob { .. } => {
self.resolve_glob_import(import);
- return true;
+ return 0;
}
_ => unreachable!(),
};
- let mut indeterminate = false;
+ let mut indeterminate_count = 0;
self.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
if let Err(Undetermined) = source_bindings[ns].get() {
@@ -638,7 +697,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let parent = import.parent_scope.module;
match source_bindings[ns].get() {
- Err(Undetermined) => indeterminate = true,
+ Err(Undetermined) => indeterminate_count += 1,
// Don't update the resolution, because it was never added.
Err(Determined) if target.name == kw::Underscore => {}
Ok(binding) if binding.is_importable() => {
@@ -662,7 +721,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
});
- !indeterminate
+ indeterminate_count
}
/// Performs final import resolution, consistency checks and error reporting.
@@ -786,7 +845,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
if !is_prelude
&& let Some(max_vis) = max_vis.get()
- && !max_vis.is_at_least(import.expect_vis(), &*self)
+ && !max_vis.is_at_least(import.expect_vis(), self.tcx)
{
let msg = "glob import doesn't reexport anything because no candidate is public enough";
self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
@@ -977,7 +1036,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let mut crate_private_reexport = false;
self.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
- if !binding.vis.is_at_least(import.expect_vis(), &*this) {
+ if !binding.vis.is_at_least(import.expect_vis(), this.tcx) {
reexport_error = Some((ns, binding));
if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
if binding_def_id.is_top_level_module() {
@@ -1202,24 +1261,38 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
*module.globs.borrow_mut() = Vec::new();
if let Some(def_id) = module.opt_def_id() {
+ let mut non_reexports = Vec::new();
let mut reexports = Vec::new();
module.for_each_child(self, |this, ident, _, binding| {
- if let Some(res) = this.is_reexport(binding) {
+ let res = binding.res().expect_non_local();
+ if !binding.is_import() {
+ non_reexports.push(res.def_id().expect_local());
+ } else if res != def::Res::Err && !binding.is_ambiguity() {
+ let mut reexport_chain = SmallVec::new();
+ let mut next_binding = binding;
+ while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
+ reexport_chain.push(import.simplify(this));
+ next_binding = binding;
+ }
+
reexports.push(ModChild {
ident,
res,
vis: binding.vis,
span: binding.span,
- macro_rules: false,
+ reexport_chain,
});
}
});
+ // Should be fine because this code is only called for local modules.
+ let def_id = def_id.expect_local();
+ if !non_reexports.is_empty() {
+ self.module_children_non_reexports.insert(def_id, non_reexports);
+ }
if !reexports.is_empty() {
- // Call to `expect_local` should be fine because current
- // code is only called for local modules.
- self.reexport_map.insert(def_id.expect_local(), reexports);
+ self.module_children_reexports.insert(def_id, reexports);
}
}
}