diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d3790394d2a9a..7dcd153dda2d2 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -41,8 +41,30 @@ use crate::{ type Res = def::Res; +/// The the side effect made when resolving the bindings for an underterminate import. +enum SideEffectBindings<'ra> { + None, + /// Side effect that should be applied to the field `bindings` of `ImportKind::Single`. + /// + /// The inner `Option` is the actual side effect, it tells us whether we found a binding + /// when resolving the import in this particular namespace. + /// The outer `Option` tells us if this side effect is present. + Single { + import_bindings: PerNS>>>, + }, + Glob { + import_bindings: Vec<(NameBinding<'ra>, BindingKey, bool /* warn_ambiguity */)>, + }, +} + +/// The side effect made when resolving an undeterminate import. +struct SideEffect<'ra> { + imported_module: ModuleOrUniformRoot<'ra>, + bindings: SideEffectBindings<'ra>, +} + /// A [`NameBinding`] in the process of being resolved. -#[derive(Clone, Copy, Default, PartialEq)] +#[derive(Clone, Copy, Default, PartialEq, Debug)] pub(crate) enum PendingBinding<'ra> { Ready(Option>), #[default] @@ -542,31 +564,139 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Import resolution // - // This is a fixed-point algorithm. We resolve imports until our efforts - // are stymied by an unresolved import; then we bail out of the current - // module and continue. We terminate successfully once no more imports - // remain or unsuccessfully when no forward progress in resolving imports - // is made. + // This is a batched fixed-point algorithm. Each import is resolved in + // isolation, with any side effects collected for later. + // After a full pass over the current set of `indeterminate_imports`, + // the collected side effects are committed together. The process + // repeats until either no imports remain or no further progress can + // be made. /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. pub(crate) fn resolve_imports(&mut self) { - self.assert_speculative = true; 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; + let mut import_resolutions = Vec::new(); + self.assert_speculative = true; for import in mem::take(&mut self.indeterminate_imports) { - let import_indeterminate_count = self.cm().resolve_import(import); + let (side_effect, import_indeterminate_count) = self.cm().resolve_import(import); indeterminate_count += import_indeterminate_count; match import_indeterminate_count { - 0 => self.determined_imports.push(import), + 0 => import_resolutions.push((import, side_effect)), _ => self.indeterminate_imports.push(import), } } + self.assert_speculative = false; + self.commit_import_resolutions(import_resolutions); + } + } + + fn commit_import_resolutions( + &mut self, + import_resolutions: Vec<(Import<'ra>, Option>)>, + ) { + self.determined_imports.reserve(self.determined_imports.len()); + for (import, side_effect) in import_resolutions.iter() { + self.determined_imports.push(*import); + let Some(SideEffect { imported_module, .. }) = side_effect else { + continue; + }; + import.imported_module.set(Some(*imported_module)); + + if import.is_glob() + && let ModuleOrUniformRoot::Module(module) = imported_module + { + module.glob_importers.borrow_mut().push(*import); + } + } + + for (import, side_effect) in import_resolutions { + let Some(SideEffect { imported_module, bindings: side_effect_bindings }) = side_effect + else { + continue; + }; + let parent = import.parent_scope.module; + + match (&import.kind, side_effect_bindings) { + ( + ImportKind::Single { target, bindings, .. }, + SideEffectBindings::Single { import_bindings }, + ) => { + self.per_ns(|this, ns| { + match import_bindings[ns] { + Some(Some(binding)) => { + if binding.is_assoc_item() + && !this.tcx.features().import_trait_associated_functions() + { + feature_err( + this.tcx.sess, + sym::import_trait_associated_functions, + import.span, + "`use` associated items of traits is unstable", + ) + .emit(); + } + this.define_binding_local(parent, *target, ns, binding); + bindings[ns].set(PendingBinding::Ready(Some(binding))); + } + Some(None) => { + // Don't remove underscores from `single_imports`, they were never added. + if target.name != kw::Underscore { + let key = BindingKey::new(*target, ns); + this.update_local_resolution( + parent, + key, + false, + |_, resolution| { + resolution.single_imports.swap_remove(&import); + }, + ); + } + bindings[ns].set(PendingBinding::Ready(None)); + } + None => return, + } + }); + } + (ImportKind::Glob { id, .. }, SideEffectBindings::Glob { import_bindings }) => { + let ModuleOrUniformRoot::Module(module) = imported_module else { + self.dcx().emit_err(CannotGlobImportAllCrates { span: import.span }); + continue; + }; + + if module.is_trait() && !self.tcx.features().import_trait_associated_functions() + { + feature_err( + self.tcx.sess, + sym::import_trait_associated_functions, + import.span, + "`use` associated items of traits is unstable", + ) + .emit(); + } + + for (binding, key, warn_ambiguity) in import_bindings { + let _ = self.try_define_local( + parent, + key.ident.0, + key.ns, + binding, + warn_ambiguity, + ); + } + + self.record_partial_res(*id, PartialRes::new(module.res().unwrap())); + } + + (_, SideEffectBindings::None) => {} + + // Something weird happened, which shouldn't have happened. + _ => unreachable!("Mismatched import kind and side effect"), + } } - self.assert_speculative = false; } pub(crate) fn finalize_imports(&mut self) { @@ -837,9 +967,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// - `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<'r>(mut self: CmResolver<'r, 'ra, 'tcx>, import: Import<'ra>) -> usize { + /// Meanwhile, if resolution is successful, the side effect of the resolution is returned. + fn resolve_import<'r>( + self: &mut CmResolver<'r, 'ra, 'tcx>, + import: Import<'ra>, + ) -> (Option>, usize) { debug!( "(resolving import for module) resolving import `{}::...` in `{}`", Segment::names_to_string(&import.module_path), @@ -857,27 +989,32 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match path_res { PathResult::Module(module) => module, - PathResult::Indeterminate => return 3, - PathResult::NonModule(..) | PathResult::Failed { .. } => return 0, + PathResult::Indeterminate => return (None, 3), + PathResult::NonModule(..) | PathResult::Failed { .. } => { + return (None, 0); + } } }; - import.imported_module.set(Some(module)); - let (source, target, bindings, type_ns_only) = match import.kind { + let (source, _, bindings, type_ns_only) = match import.kind { ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => { (source, target, bindings, type_ns_only) } ImportKind::Glob { .. } => { - // FIXME: Use mutable resolver directly as a hack, this should be an output of - // speculative resolution. - self.get_mut_unchecked().resolve_glob_import(import); - return 0; + return ( + Some(SideEffect { + imported_module: module, + bindings: self.resolve_glob_import(import, module), + }), + 0, + ); } _ => unreachable!(), }; + let mut import_bindings = PerNS::default(); let mut indeterminate_count = 0; - self.per_ns_cm(|this, ns| { + self.reborrow().per_ns_cm(|this, ns| { if !type_ns_only || ns == TypeNS { if bindings[ns].get() != PendingBinding::Pending { return; @@ -889,59 +1026,29 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import.parent_scope, Some(import), ); - let parent = import.parent_scope.module; - let binding = match binding_result { + let pending_binding = match binding_result { Ok(binding) => { - if binding.is_assoc_item() - && !this.tcx.features().import_trait_associated_functions() - { - feature_err( - this.tcx.sess, - sym::import_trait_associated_functions, - import.span, - "`use` associated items of traits is unstable", - ) - .emit(); - } // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - // FIXME: Use mutable resolver directly as a hack, this should be an output of - // speculative resolution. - this.get_mut_unchecked().define_binding_local( - parent, - target, - ns, - imported_binding, - ); - PendingBinding::Ready(Some(imported_binding)) - } - Err(Determinacy::Determined) => { - // Don't remove underscores from `single_imports`, they were never added. - if target.name != kw::Underscore { - let key = BindingKey::new(target, ns); - // FIXME: Use mutable resolver directly as a hack, this should be an output of - // speculative resolution. - this.get_mut_unchecked().update_local_resolution( - parent, - key, - false, - |_, resolution| { - resolution.single_imports.swap_remove(&import); - }, - ); - } - PendingBinding::Ready(None) + Some(Some(imported_binding)) } + Err(Determinacy::Determined) => Some(None), Err(Determinacy::Undetermined) => { indeterminate_count += 1; - PendingBinding::Pending + None } }; - bindings[ns].set(binding); + import_bindings[ns] = pending_binding; } }); - indeterminate_count + ( + Some(SideEffect { + imported_module: module, + bindings: SideEffectBindings::Single { import_bindings }, + }), + indeterminate_count, + ) } /// Performs final import resolution, consistency checks and error reporting. @@ -1484,66 +1591,47 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false } - fn resolve_glob_import(&mut self, import: Import<'ra>) { + fn resolve_glob_import<'r>( + self: &mut CmResolver<'r, 'ra, 'tcx>, + import: Import<'ra>, + imported_module: ModuleOrUniformRoot<'ra>, + ) -> SideEffectBindings<'ra> { // This function is only called for glob imports. - let ImportKind::Glob { id, .. } = import.kind else { unreachable!() }; + let ImportKind::Glob { .. } = import.kind else { unreachable!() }; - let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else { - self.dcx().emit_err(CannotGlobImportAllCrates { span: import.span }); - return; + let ModuleOrUniformRoot::Module(module) = imported_module else { + return SideEffectBindings::None; }; - if module.is_trait() && !self.tcx.features().import_trait_associated_functions() { - feature_err( - self.tcx.sess, - sym::import_trait_associated_functions, - import.span, - "`use` associated items of traits is unstable", - ) - .emit(); - } - if module == import.parent_scope.module { - return; + return SideEffectBindings::None; } - // Add to module's glob_importers - module.glob_importers.borrow_mut().push(import); - - // Ensure that `resolutions` isn't borrowed during `try_define`, - // since it might get updated via a glob cycle. - let bindings = self + let import_bindings = self .resolutions(module) .borrow() .iter() .filter_map(|(key, resolution)| { - resolution.borrow().binding().map(|binding| (*key, binding)) + let binding = resolution.borrow().binding()?; + let mut key = *key; + let scope = + match key.ident.0.span.reverse_glob_adjust(module.expansion, import.span) { + Some(Some(def)) => self.expn_def_scope(def), + Some(None) => import.parent_scope.module, + None => return None, + }; + self.is_accessible_from(binding.vis, scope).then(|| { + let imported_binding = self.import(binding, import); + let warn_ambiguity = self + .resolution(import.parent_scope.module, key) + .and_then(|r| r.binding()) + .is_some_and(|binding| binding.warn_ambiguity_recursive()); + (imported_binding, key, warn_ambiguity) + }) }) .collect::>(); - for (mut key, binding) in bindings { - let scope = match key.ident.0.span.reverse_glob_adjust(module.expansion, import.span) { - Some(Some(def)) => self.expn_def_scope(def), - Some(None) => import.parent_scope.module, - None => continue, - }; - if self.is_accessible_from(binding.vis, scope) { - let imported_binding = self.import(binding, import); - let warn_ambiguity = self - .resolution(import.parent_scope.module, key) - .and_then(|r| r.binding()) - .is_some_and(|binding| binding.warn_ambiguity_recursive()); - let _ = self.try_define_local( - import.parent_scope.module, - key.ident.0, - key.ns, - imported_binding, - warn_ambiguity, - ); - } - } - // Record the destination of this import - self.record_partial_res(id, PartialRes::new(module.res().unwrap())); + SideEffectBindings::Glob { import_bindings } } // Miscellaneous post-processing, including recording re-exports, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2063c46124c29..f8f3271c4c172 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2530,12 +2530,6 @@ mod ref_mut { true => self.p, } } - - /// Returns a mutable reference to the inner value without checking if - /// it's in a mutable state. - pub(crate) fn get_mut_unchecked(&mut self) -> &mut T { - self.p - } } } diff --git a/fail.rs b/fail.rs new file mode 100644 index 0000000000000..114e05ed76072 --- /dev/null +++ b/fail.rs @@ -0,0 +1,30 @@ +#![no_core] +#![feature(no_core)] +#![allow(internal_features)] +#![feature(lang_items)] + +#[lang = "sized"] +pub trait Sized: MetaSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +mod core_simd { + mod vector { + pub struct Simd {} + } + pub mod simd { + pub use crate::core_simd::vector::*; + } +} + +pub mod simd { + pub use crate::core_simd::simd::*; +} + +mod fail { + use crate::simd::Simd; +} diff --git a/tests/ui/imports/ambiguous-9.rs b/tests/ui/imports/ambiguous-9.rs index c10b1268060ce..cb352668e7599 100644 --- a/tests/ui/imports/ambiguous-9.rs +++ b/tests/ui/imports/ambiguous-9.rs @@ -4,7 +4,7 @@ pub mod dsl { mod range { pub fn date_range() {} } - pub use self::range::*; //~ WARNING ambiguous glob re-exports + pub use self::range::*; use super::prelude::*; } @@ -12,8 +12,8 @@ pub mod prelude { mod t { pub fn date_range() {} } - pub use self::t::*; //~ WARNING ambiguous glob re-exports - pub use super::dsl::*; + pub use self::t::*; + pub use super::dsl::*; //~ WARNING ambiguous glob re-exports } use dsl::*; @@ -23,6 +23,4 @@ fn main() { date_range(); //~^ ERROR `date_range` is ambiguous //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| ERROR `date_range` is ambiguous - //~| WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } diff --git a/tests/ui/imports/ambiguous-9.stderr b/tests/ui/imports/ambiguous-9.stderr index 800a2e10c9d78..9222f3f99c1e3 100644 --- a/tests/ui/imports/ambiguous-9.stderr +++ b/tests/ui/imports/ambiguous-9.stderr @@ -1,10 +1,10 @@ warning: ambiguous glob re-exports - --> $DIR/ambiguous-9.rs:7:13 + --> $DIR/ambiguous-9.rs:16:13 | -LL | pub use self::range::*; - | ^^^^^^^^^^^^^^ the name `date_range` in the value namespace is first re-exported here -LL | use super::prelude::*; - | ----------------- but the name `date_range` in the value namespace is also re-exported here +LL | pub use self::t::*; + | ---------- but the name `date_range` in the value namespace is also re-exported here +LL | pub use super::dsl::*; + | ^^^^^^^^^^^^^ the name `date_range` in the value namespace is first re-exported here | = note: `#[warn(ambiguous_glob_reexports)]` on by default @@ -18,10 +18,10 @@ LL | date_range(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `date_range` could refer to the function imported here - --> $DIR/ambiguous-9.rs:7:13 + --> $DIR/ambiguous-9.rs:16:13 | -LL | pub use self::range::*; - | ^^^^^^^^^^^^^^ +LL | pub use super::dsl::*; + | ^^^^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate note: `date_range` could also refer to the function imported here --> $DIR/ambiguous-9.rs:8:9 @@ -35,33 +35,11 @@ warning: ambiguous glob re-exports --> $DIR/ambiguous-9.rs:15:13 | LL | pub use self::t::*; - | ^^^^^^^^^^ the name `date_range` in the value namespace is first re-exported here -LL | pub use super::dsl::*; - | ------------- but the name `date_range` in the value namespace is also re-exported here - -error: `date_range` is ambiguous - --> $DIR/ambiguous-9.rs:23:5 - | -LL | date_range(); - | ^^^^^^^^^^ ambiguous name - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #114095 - = note: ambiguous because of multiple glob imports of a name in the same module -note: `date_range` could refer to the function imported here - --> $DIR/ambiguous-9.rs:19:5 - | -LL | use dsl::*; - | ^^^^^^ - = help: consider adding an explicit import of `date_range` to disambiguate -note: `date_range` could also refer to the function imported here - --> $DIR/ambiguous-9.rs:20:5 - | -LL | use prelude::*; - | ^^^^^^^^^^ + | ^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate + = note: `#[deny(ambiguous_glob_imports)]` on by default -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 1 previous error; 1 warning emitted Future incompatibility report: Future breakage diagnostic: error: `date_range` is ambiguous @@ -74,13 +52,13 @@ LL | date_range(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `date_range` could refer to the function imported here - --> $DIR/ambiguous-9.rs:7:13 + --> $DIR/ambiguous-9.rs:16:13 | -LL | pub use self::range::*; - | ^^^^^^^^^^^^^^ +LL | pub use super::dsl::*; + | ^^^^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate note: `date_range` could also refer to the function imported here - --> $DIR/ambiguous-9.rs:8:9 + --> $DIR/ambiguous-9.rs:15:13 | LL | use super::prelude::*; | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/imports/glob-conflict-cross-crate-1.rs b/tests/ui/imports/glob-conflict-cross-crate-1.rs index 5f0433d13fcfd..4ea6e131d2400 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-1.rs +++ b/tests/ui/imports/glob-conflict-cross-crate-1.rs @@ -6,7 +6,7 @@ fn main() { glob_conflict::f(); //~ ERROR cannot find function `f` in crate `glob_conflict` //^ FIXME: `glob_conflict::f` should raise an // ambiguity error instead of a not found error. - glob_conflict::glob::f(); //~ ERROR cannot find function `f` in module `glob_conflict::glob` + glob_conflict::glob::f(); //^ FIXME: `glob_conflict::glob::f` should raise an // ambiguity error instead of a not found error. } diff --git a/tests/ui/imports/glob-conflict-cross-crate-1.stderr b/tests/ui/imports/glob-conflict-cross-crate-1.stderr index 758087107f397..1f1217c25e626 100644 --- a/tests/ui/imports/glob-conflict-cross-crate-1.stderr +++ b/tests/ui/imports/glob-conflict-cross-crate-1.stderr @@ -3,13 +3,17 @@ error[E0425]: cannot find function `f` in crate `glob_conflict` | LL | glob_conflict::f(); | ^ not found in `glob_conflict` - -error[E0425]: cannot find function `f` in module `glob_conflict::glob` - --> $DIR/glob-conflict-cross-crate-1.rs:9:26 | -LL | glob_conflict::glob::f(); - | ^ not found in `glob_conflict::glob` +help: consider importing this function + | +LL + use glob_conflict::glob::f; + | +help: if you import `f`, refer to it directly + | +LL - glob_conflict::f(); +LL + f(); + | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/imports/reexports.stderr b/tests/ui/imports/reexports.stderr index 0ebcf8e58d627..dec8a60f93ca0 100644 --- a/tests/ui/imports/reexports.stderr +++ b/tests/ui/imports/reexports.stderr @@ -11,16 +11,16 @@ LL | pub use super::foo; | ^^^^^^^^^^ error[E0603]: module import `foo` is private - --> $DIR/reexports.rs:36:22 + --> $DIR/reexports.rs:37:22 | -LL | use crate::b::a::foo::S; +LL | use crate::b::b::foo::S as T; | ^^^ private module import | note: the module import `foo` is defined here... - --> $DIR/reexports.rs:24:17 + --> $DIR/reexports.rs:29:17 | -LL | pub use super::foo; // This is OK since the value `foo` is visible enough. - | ^^^^^^^^^^ +LL | pub use super::*; // This is also OK since the value `foo` is visible enough. + | ^^^^^^^^ note: ...and refers to the module `foo` which is defined here --> $DIR/reexports.rs:19:5 | @@ -28,16 +28,16 @@ LL | mod foo { | ^^^^^^^ error[E0603]: module import `foo` is private - --> $DIR/reexports.rs:37:22 + --> $DIR/reexports.rs:36:22 | -LL | use crate::b::b::foo::S as T; +LL | use crate::b::a::foo::S; | ^^^ private module import | note: the module import `foo` is defined here... - --> $DIR/reexports.rs:29:17 + --> $DIR/reexports.rs:24:17 | -LL | pub use super::*; // This is also OK since the value `foo` is visible enough. - | ^^^^^^^^ +LL | pub use super::foo; // This is OK since the value `foo` is visible enough. + | ^^^^^^^^^^ note: ...and refers to the module `foo` which is defined here --> $DIR/reexports.rs:19:5 | diff --git a/tests/ui/shadowed/shadowed-use-visibility.stderr b/tests/ui/shadowed/shadowed-use-visibility.stderr index b062341dc8be8..f3b81fcac99e0 100644 --- a/tests/ui/shadowed/shadowed-use-visibility.stderr +++ b/tests/ui/shadowed/shadowed-use-visibility.stderr @@ -1,31 +1,31 @@ -error[E0603]: module import `bar` is private - --> $DIR/shadowed-use-visibility.rs:9:21 +error[E0603]: module import `f` is private + --> $DIR/shadowed-use-visibility.rs:15:10 | -LL | use crate::foo::bar::f as g; - | ^^^ private module import +LL | use bar::f::f; + | ^ private module import | -note: the module import `bar` is defined here... - --> $DIR/shadowed-use-visibility.rs:4:9 +note: the module import `f` is defined here... + --> $DIR/shadowed-use-visibility.rs:11:9 | -LL | use crate::foo as bar; - | ^^^^^^^^^^^^^^^^^ +LL | use crate::foo as f; + | ^^^^^^^^^^^^^^^ note: ...and refers to the module `foo` which is defined here --> $DIR/shadowed-use-visibility.rs:1:1 | LL | mod foo { | ^^^^^^^ -error[E0603]: module import `f` is private - --> $DIR/shadowed-use-visibility.rs:15:10 +error[E0603]: module import `bar` is private + --> $DIR/shadowed-use-visibility.rs:9:21 | -LL | use bar::f::f; - | ^ private module import +LL | use crate::foo::bar::f as g; + | ^^^ private module import | -note: the module import `f` is defined here... - --> $DIR/shadowed-use-visibility.rs:11:9 +note: the module import `bar` is defined here... + --> $DIR/shadowed-use-visibility.rs:4:9 | -LL | use crate::foo as f; - | ^^^^^^^^^^^^^^^ +LL | use crate::foo as bar; + | ^^^^^^^^^^^^^^^^^ note: ...and refers to the module `foo` which is defined here --> $DIR/shadowed-use-visibility.rs:1:1 |