summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_resolve/src/imports.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_resolve/src/imports.rs
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.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.rs197
1 files changed, 139 insertions, 58 deletions
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index d37fe783b..a175d9f6c 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -284,6 +284,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.arenas.alloc_name_binding(NameBindingData {
kind: NameBindingKind::Import { binding, import, used: Cell::new(false) },
ambiguity: None,
+ warn_ambiguity: false,
span: import.span,
vis,
expansion: import.parent_scope.expansion,
@@ -291,16 +292,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
/// Define the name or return the existing binding if there is a collision.
+ /// `update` indicates if the definition is a redefinition of an existing binding.
pub(crate) fn try_define(
&mut self,
module: Module<'a>,
key: BindingKey,
binding: NameBinding<'a>,
+ warn_ambiguity: bool,
) -> Result<(), NameBinding<'a>> {
let res = binding.res();
self.check_reserved_macro_name(key.ident, res);
self.set_binding_parent_module(binding, module);
- self.update_resolution(module, key, |this, resolution| {
+ self.update_resolution(module, key, warn_ambiguity, |this, resolution| {
if let Some(old_binding) = resolution.binding {
if res == Res::Err && old_binding.res() != Res::Err {
// Do not override real bindings with `Res::Err`s from error recovery.
@@ -308,15 +311,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
match (old_binding.is_glob_import(), binding.is_glob_import()) {
(true, true) => {
- if res != old_binding.res() {
- resolution.binding = Some(this.ambiguity(
- AmbiguityKind::GlobVsGlob,
- old_binding,
- binding,
- ));
+ // FIXME: remove `!binding.is_ambiguity()` after delete the warning ambiguity.
+ if !binding.is_ambiguity()
+ && let NameBindingKind::Import { import: old_import, .. } = old_binding.kind
+ && let NameBindingKind::Import { import, .. } = binding.kind
+ && old_import == import {
+ // We should replace the `old_binding` with `binding` regardless
+ // of whether they has same resolution or not when they are
+ // imported from the same glob-import statement.
+ // However we currently using `Some(old_binding)` for back compact
+ // purposes.
+ // This case can be removed after once `Undetermined` is prepared
+ // for glob-imports.
+ } else if res != old_binding.res() {
+ let binding = if warn_ambiguity {
+ this.warn_ambiguity(
+ AmbiguityKind::GlobVsGlob,
+ old_binding,
+ binding,
+ )
+ } else {
+ this.ambiguity(
+ AmbiguityKind::GlobVsGlob,
+ old_binding,
+ binding,
+ )
+ };
+ resolution.binding = Some(binding);
} 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);
+ } else if binding.is_ambiguity() {
+ resolution.binding =
+ Some(self.arenas.alloc_name_binding(NameBindingData {
+ warn_ambiguity: true,
+ ..(*binding).clone()
+ }));
}
}
(old_glob @ true, false) | (old_glob @ false, true) => {
@@ -374,29 +404,52 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
})
}
+ fn warn_ambiguity(
+ &self,
+ kind: AmbiguityKind,
+ primary_binding: NameBinding<'a>,
+ secondary_binding: NameBinding<'a>,
+ ) -> NameBinding<'a> {
+ self.arenas.alloc_name_binding(NameBindingData {
+ ambiguity: Some((secondary_binding, kind)),
+ warn_ambiguity: true,
+ ..(*primary_binding).clone()
+ })
+ }
+
// Use `f` to mutate the resolution of the name in the module.
// If the resolution becomes a success, define it in the module's glob importers.
- fn update_resolution<T, F>(&mut self, module: Module<'a>, key: BindingKey, f: F) -> T
+ fn update_resolution<T, F>(
+ &mut self,
+ module: Module<'a>,
+ key: BindingKey,
+ warn_ambiguity: bool,
+ f: F,
+ ) -> T
where
F: FnOnce(&mut Resolver<'a, 'tcx>, &mut NameResolution<'a>) -> T,
{
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
- let (binding, t) = {
+ let (binding, t, warn_ambiguity) = {
let resolution = &mut *self.resolution(module, key).borrow_mut();
let old_binding = resolution.binding();
let t = f(self, resolution);
- if old_binding.is_none() && let Some(binding) = resolution.binding() {
- (binding, t)
+ if let Some(binding) = resolution.binding() && old_binding != Some(binding) {
+ (binding, t, warn_ambiguity || old_binding.is_some())
} else {
return t;
}
};
- // Define `binding` in `module`s glob importers.
- for import in module.glob_importers.borrow_mut().iter() {
+ let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else {
+ return t;
+ };
+
+ // Define or update `binding` in `module`s glob importers.
+ for import in glob_importers.iter() {
let mut ident = key.ident;
let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) {
Some(Some(def)) => self.expn_def_scope(def),
@@ -406,7 +459,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if self.is_accessible_from(binding.vis, scope) {
let imported_binding = self.import(binding, *import);
let key = BindingKey { ident, ..key };
- let _ = self.try_define(import.parent_scope.module, key, imported_binding);
+ let _ = self.try_define(
+ import.parent_scope.module,
+ key,
+ imported_binding,
+ warn_ambiguity,
+ );
}
}
@@ -425,7 +483,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let dummy_binding = self.import(dummy_binding, import);
self.per_ns(|this, ns| {
let key = BindingKey::new(target, ns);
- let _ = this.try_define(import.parent_scope.module, key, dummy_binding);
+ let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false);
});
self.record_use(target, dummy_binding, false);
} else if import.imported_module.get().is_none() {
@@ -475,15 +533,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
for (is_indeterminate, import) in determined_imports
- .into_iter()
+ .iter()
.map(|i| (false, i))
- .chain(indeterminate_imports.into_iter().map(|i| (true, i)))
+ .chain(indeterminate_imports.iter().map(|i| (true, i)))
{
- let unresolved_import_error = self.finalize_import(import);
+ let unresolved_import_error = self.finalize_import(*import);
// If this import is unresolved then create a dummy import
// resolution for it so that later resolve stages won't complain.
- self.import_dummy_binding(import, is_indeterminate);
+ self.import_dummy_binding(*import, is_indeterminate);
if let Some(err) = unresolved_import_error {
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
@@ -505,27 +563,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
errors = vec![];
}
if seen_spans.insert(err.span) {
- errors.push((import, err));
+ errors.push((*import, err));
prev_root_id = import.root_id;
}
- } else if is_indeterminate {
- let path = import_path_to_string(
- &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
- &import.kind,
- import.span,
- );
- let err = UnresolvedImportError {
- span: import.span,
- label: None,
- note: None,
- suggestion: None,
- candidates: None,
- };
- // FIXME: there should be a better way of doing this than
- // formatting this as a string then checking for `::`
- if path.contains("::") {
- errors.push((import, err))
- }
+ }
+ }
+
+ if !errors.is_empty() {
+ self.throw_unresolved_import_error(errors);
+ return;
+ }
+
+ for import in &indeterminate_imports {
+ let path = import_path_to_string(
+ &import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
+ &import.kind,
+ import.span,
+ );
+ let err = UnresolvedImportError {
+ span: import.span,
+ label: None,
+ note: None,
+ suggestion: None,
+ candidates: None,
+ };
+ // FIXME: there should be a better way of doing this than
+ // formatting this as a string then checking for `::`
+ if path.contains("::") {
+ errors.push((*import, err))
}
}
@@ -700,7 +765,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Segment::names_to_string(&import.module_path),
module_to_string(import.parent_scope.module).unwrap_or_else(|| "???".to_string()),
);
-
let module = if let Some(module) = import.imported_module.get() {
module
} else {
@@ -773,7 +837,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.emit();
}
let key = BindingKey::new(target, ns);
- this.update_resolution(parent, key, |_, resolution| {
+ this.update_resolution(parent, key, false, |_, resolution| {
resolution.single_imports.remove(&import);
});
}
@@ -989,14 +1053,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
initial_binding.res()
});
let res = binding.res();
+ let has_ambiguity_error = this
+ .ambiguity_errors
+ .iter()
+ .filter(|error| !error.warning)
+ .next()
+ .is_some();
+ if res == Res::Err || has_ambiguity_error {
+ this.tcx
+ .sess
+ .delay_span_bug(import.span, "some error happened for an import");
+ return;
+ }
if let Ok(initial_res) = initial_res {
- if res != initial_res && this.ambiguity_errors.is_empty() {
+ if res != initial_res {
span_bug!(import.span, "inconsistent resolution for an import");
}
- } else if res != Res::Err
- && this.ambiguity_errors.is_empty()
- && this.privacy_errors.is_empty()
- {
+ } else if this.privacy_errors.is_empty() {
this.tcx
.sess
.create_err(CannotDetermineImportResolution { span: import.span })
@@ -1087,18 +1160,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ModuleOrUniformRoot::Module(module) => {
let module_str = module_to_string(module);
if let Some(module_str) = module_str {
- format!("no `{}` in `{}`", ident, module_str)
+ format!("no `{ident}` in `{module_str}`")
} else {
- format!("no `{}` in the root", ident)
+ format!("no `{ident}` in the root")
}
}
_ => {
if !ident.is_path_segment_keyword() {
- format!("no external crate `{}`", ident)
+ format!("no external crate `{ident}`")
} else {
// HACK(eddyb) this shows up for `self` & `super`, which
// should work instead - for now keep the same error message.
- format!("no `{}` in the root", ident)
+ format!("no `{ident}` in the root")
}
}
};
@@ -1146,10 +1219,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let (ns, binding) = reexport_error.unwrap();
if pub_use_of_private_extern_crate_hack(import, binding) {
let msg = format!(
- "extern crate `{}` is private, and cannot be \
+ "extern crate `{ident}` is private, and cannot be \
re-exported (error E0365), consider declaring with \
- `pub`",
- ident
+ `pub`"
);
self.lint_buffer.buffer_lint(
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
@@ -1289,7 +1361,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
UNUSED_IMPORTS,
id,
import.span,
- format!("the item `{}` is imported redundantly", ident),
+ format!("the item `{ident}` is imported redundantly"),
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
);
}
@@ -1300,9 +1372,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
- self.tcx.sess.create_err(CannotGlobImportAllCrates {
- span: import.span,
- }).emit();
+ self.tcx.sess.create_err(CannotGlobImportAllCrates { span: import.span }).emit();
return;
};
@@ -1337,7 +1407,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
};
if self.is_accessible_from(binding.vis, scope) {
let imported_binding = self.import(binding, import);
- let _ = self.try_define(import.parent_scope.module, key, imported_binding);
+ let warn_ambiguity = self
+ .resolution(import.parent_scope.module, key)
+ .borrow()
+ .binding()
+ .is_some_and(|binding| binding.is_warn_ambiguity());
+ let _ = self.try_define(
+ import.parent_scope.module,
+ key,
+ imported_binding,
+ warn_ambiguity,
+ );
}
}
@@ -1356,7 +1436,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
module.for_each_child(self, |this, ident, _, binding| {
let res = binding.res().expect_non_local();
- if res != def::Res::Err && !binding.is_ambiguity() {
+ let error_ambiguity = binding.is_ambiguity() && !binding.warn_ambiguity;
+ if res != def::Res::Err && !error_ambiguity {
let mut reexport_chain = SmallVec::new();
let mut next_binding = binding;
while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {