Skip to content

Commit 69e5740

Browse files
Resolver: Batched import resolution.
Collect side effects from the current set of undetermined imports and only apply them at the end.
1 parent 4f08307 commit 69e5740

File tree

10 files changed

+242
-131
lines changed

10 files changed

+242
-131
lines changed

compiler/rustc_hir/src/def.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,24 @@ impl<T> PerNS<T> {
759759
pub fn iter(&self) -> IntoIter<&T, 3> {
760760
[&self.value_ns, &self.type_ns, &self.macro_ns].into_iter()
761761
}
762+
763+
pub fn into_iter_with(self) -> IntoIter<(Namespace, T), 3> {
764+
[
765+
(Namespace::TypeNS, self.type_ns),
766+
(Namespace::ValueNS, self.value_ns),
767+
(Namespace::MacroNS, self.macro_ns),
768+
]
769+
.into_iter()
770+
}
771+
772+
pub fn iter_with(&self) -> IntoIter<(Namespace, &T), 3> {
773+
[
774+
(Namespace::TypeNS, &self.type_ns),
775+
(Namespace::ValueNS, &self.value_ns),
776+
(Namespace::MacroNS, &self.macro_ns),
777+
]
778+
.into_iter()
779+
}
762780
}
763781

764782
impl<T> ::std::ops::Index<Namespace> for PerNS<T> {

compiler/rustc_resolve/src/imports.rs

Lines changed: 139 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! A bunch of methods and structures more or less related to resolving imports.
22
33
use std::mem;
4+
use std::ops::Deref;
45

56
use rustc_ast::NodeId;
67
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
@@ -41,6 +42,96 @@ use crate::{
4142

4243
type Res = def::Res<NodeId>;
4344

45+
struct ImportResolver<'r, 'ra, 'tcx> {
46+
r: CmResolver<'r, 'ra, 'tcx>, // always immutable
47+
outputs: ImportResolutionOutputs<'ra>,
48+
}
49+
50+
enum SideEffect<'ra> {
51+
None,
52+
Single { import_bindings: PerNS<PendingBinding<'ra>> },
53+
Glob { import_bindings: Vec<(NameBinding<'ra>, BindingKey, bool /* warn_ambiguity */)> },
54+
}
55+
56+
#[derive(Default)]
57+
struct ImportResolutionOutputs<'ra> {
58+
indeterminate_imports: Vec<Import<'ra>>,
59+
determined_imports: Vec<(Import<'ra>, SideEffect<'ra>)>,
60+
}
61+
62+
impl<'ra> ImportResolutionOutputs<'ra> {
63+
fn commit<'tcx>(self, r: &mut Resolver<'ra, 'tcx>) {
64+
r.indeterminate_imports = self.indeterminate_imports;
65+
r.determined_imports.reserve(self.determined_imports.len());
66+
67+
for (import, side_effect) in self.determined_imports {
68+
r.determined_imports.push(import);
69+
70+
let parent = import.parent_scope.module;
71+
match (&import.kind, side_effect) {
72+
(
73+
ImportKind::Single { target, bindings, .. },
74+
SideEffect::Single { import_bindings },
75+
) => {
76+
for (ns, pending_binding) in import_bindings.into_iter_with() {
77+
match pending_binding {
78+
PendingBinding::Ready(Some(binding)) => {
79+
r.define_binding_local(parent, *target, ns, binding);
80+
}
81+
PendingBinding::Ready(None) => {
82+
let key = BindingKey::new(*target, ns);
83+
r.update_local_resolution(parent, key, false, |_, resolution| {
84+
resolution.single_imports.swap_remove(&import);
85+
});
86+
}
87+
_ => {}
88+
}
89+
bindings[ns].set(pending_binding);
90+
}
91+
}
92+
(ImportKind::Glob { id, .. }, SideEffect::Glob { import_bindings }) => {
93+
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap()
94+
else {
95+
unreachable!();
96+
};
97+
98+
module.glob_importers.borrow_mut(r).push(import);
99+
100+
for (binding, key, warn_ambiguity) in import_bindings {
101+
let _ = r.try_define_local(
102+
parent,
103+
key.ident.0,
104+
key.ns,
105+
binding,
106+
warn_ambiguity,
107+
);
108+
}
109+
110+
r.record_partial_res(*id, PartialRes::new(module.res().unwrap()));
111+
}
112+
113+
(_, SideEffect::None) => {}
114+
// Something weird happened, which shouldn't have happened.
115+
_ => unreachable!("Mismatched import kind and side effect"),
116+
}
117+
}
118+
}
119+
}
120+
121+
impl<'r, 'ra, 'tcx> Deref for ImportResolver<'r, 'ra, 'tcx> {
122+
type Target = Resolver<'ra, 'tcx>;
123+
124+
fn deref(&self) -> &Self::Target {
125+
self.r.deref()
126+
}
127+
}
128+
129+
impl<'r, 'ra, 'tcx> AsRef<Resolver<'ra, 'tcx>> for ImportResolver<'r, 'ra, 'tcx> {
130+
fn as_ref(&self) -> &Resolver<'ra, 'tcx> {
131+
self.r.as_ref()
132+
}
133+
}
134+
44135
/// A [`NameBinding`] in the process of being resolved.
45136
#[derive(Clone, Copy, Default, PartialEq)]
46137
pub(crate) enum PendingBinding<'ra> {
@@ -555,18 +646,31 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
555646
let mut indeterminate_count = self.indeterminate_imports.len() * 3;
556647
while indeterminate_count < prev_indeterminate_count {
557648
prev_indeterminate_count = indeterminate_count;
558-
indeterminate_count = 0;
649+
let batch = mem::take(&mut self.indeterminate_imports);
559650
self.assert_speculative = true;
560-
for import in mem::take(&mut self.indeterminate_imports) {
561-
let import_indeterminate_count = self.cm().resolve_import(import);
562-
indeterminate_count += import_indeterminate_count;
563-
match import_indeterminate_count {
564-
0 => self.determined_imports.push(import),
565-
_ => self.indeterminate_imports.push(import),
566-
}
651+
let (outputs, count) =
652+
ImportResolver { r: self.cm(), outputs: Default::default() }.resolve_batch(batch);
653+
self.assert_speculative = false;
654+
indeterminate_count = count;
655+
outputs.commit(self);
656+
}
657+
}
658+
659+
fn resolve_batch<'r>(
660+
mut self: ImportResolver<'r, 'ra, 'tcx>,
661+
batch: Vec<Import<'ra>>,
662+
) -> (ImportResolutionOutputs<'ra>, usize) {
663+
let mut indeterminate_count = 0;
664+
for import in batch {
665+
let (side_effect, import_indeterminate_count) = self.resolve_import(import);
666+
indeterminate_count += import_indeterminate_count;
667+
match import_indeterminate_count {
668+
0 => self.outputs.determined_imports.push((import, side_effect)),
669+
_ => self.outputs.indeterminate_imports.push(import),
567670
}
568671
self.assert_speculative = false;
569672
}
673+
(self.outputs, indeterminate_count)
570674
}
571675

572676
pub(crate) fn finalize_imports(&mut self) {
@@ -837,7 +941,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
837941
///
838942
/// Meanwhile, if resolve successful, the resolved bindings are written
839943
/// into the module.
840-
fn resolve_import<'r>(mut self: CmResolver<'r, 'ra, 'tcx>, import: Import<'ra>) -> usize {
944+
fn resolve_import<'r>(
945+
self: &mut ImportResolver<'r, 'ra, 'tcx>,
946+
import: Import<'ra>,
947+
) -> (SideEffect<'ra>, usize) {
841948
debug!(
842949
"(resolving import for module) resolving import `{}::...` in `{}`",
843950
Segment::names_to_string(&import.module_path),
@@ -846,7 +953,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
846953
let module = if let Some(module) = import.imported_module.get() {
847954
module
848955
} else {
849-
let path_res = self.reborrow().maybe_resolve_path(
956+
let path_res = self.r.reborrow().maybe_resolve_path(
850957
&import.module_path,
851958
None,
852959
&import.parent_scope,
@@ -855,8 +962,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
855962

856963
match path_res {
857964
PathResult::Module(module) => module,
858-
PathResult::Indeterminate => return 3,
859-
PathResult::NonModule(..) | PathResult::Failed { .. } => return 0,
965+
PathResult::Indeterminate => return (SideEffect::None, 3),
966+
PathResult::NonModule(..) | PathResult::Failed { .. } => {
967+
return (SideEffect::None, 0);
968+
}
860969
}
861970
};
862971

@@ -866,14 +975,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
866975
(source, target, bindings, type_ns_only)
867976
}
868977
ImportKind::Glob { .. } => {
869-
self.get_mut_unchecked().resolve_glob_import(import);
870-
return 0;
978+
return (self.resolve_glob_import(import), 0);
871979
}
872980
_ => unreachable!(),
873981
};
874982

983+
let mut import_bindings = PerNS::default();
875984
let mut indeterminate_count = 0;
876-
self.per_ns_cm(|this, ns| {
985+
self.r.reborrow().per_ns_cm(|this, ns| {
877986
if !type_ns_only || ns == TypeNS {
878987
if bindings[ns].get() != PendingBinding::Pending {
879988
return;
@@ -885,8 +994,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
885994
&import.parent_scope,
886995
Some(import),
887996
);
888-
let parent = import.parent_scope.module;
889-
let binding = match binding_result {
997+
let pending_binding = match binding_result {
890998
Ok(binding) => {
891999
if binding.is_assoc_item()
8921000
&& !this.tcx.features().import_trait_associated_functions()
@@ -901,39 +1009,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
9011009
}
9021010
// We need the `target`, `source` can be extracted.
9031011
let imported_binding = this.import(binding, import);
904-
this.get_mut_unchecked().define_binding_local(
905-
parent,
906-
target,
907-
ns,
908-
imported_binding,
909-
);
9101012
PendingBinding::Ready(Some(imported_binding))
9111013
}
9121014
Err(Determinacy::Determined) => {
9131015
// Don't remove underscores from `single_imports`, they were never added.
914-
if target.name != kw::Underscore {
915-
let key = BindingKey::new(target, ns);
916-
this.get_mut_unchecked().update_local_resolution(
917-
parent,
918-
key,
919-
false,
920-
|_, resolution| {
921-
resolution.single_imports.swap_remove(&import);
922-
},
923-
);
1016+
if target.name == kw::Underscore {
1017+
return;
9241018
}
9251019
PendingBinding::Ready(None)
9261020
}
9271021
Err(Determinacy::Undetermined) => {
9281022
indeterminate_count += 1;
929-
PendingBinding::Pending
1023+
return;
9301024
}
9311025
};
9321026
bindings[ns].set_unchecked(binding);
9331027
}
9341028
});
9351029

936-
indeterminate_count
1030+
(SideEffect::Single { import_bindings }, indeterminate_count)
9371031
}
9381032

9391033
/// Performs final import resolution, consistency checks and error reporting.
@@ -1476,13 +1570,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14761570
false
14771571
}
14781572

1479-
fn resolve_glob_import(&mut self, import: Import<'ra>) {
1573+
fn resolve_glob_import<'r>(
1574+
self: &mut ImportResolver<'r, 'ra, 'tcx>,
1575+
import: Import<'ra>,
1576+
) -> SideEffect<'ra> {
14801577
// This function is only called for glob imports.
1481-
let ImportKind::Glob { id, .. } = import.kind else { unreachable!() };
1578+
let ImportKind::Glob { .. } = import.kind else { unreachable!() };
14821579

14831580
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
14841581
self.dcx().emit_err(CannotGlobImportAllCrates { span: import.span });
1485-
return;
1582+
return SideEffect::None;
14861583
};
14871584

14881585
if module.is_trait() && !self.tcx.features().import_trait_associated_functions() {
@@ -1496,12 +1593,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14961593
}
14971594

14981595
if module == import.parent_scope.module {
1499-
return;
1596+
return SideEffect::None;
15001597
}
15011598

1502-
// Add to module's glob_importers
1503-
module.glob_importers.borrow_mut_unchecked().push(import);
1504-
15051599
// Ensure that `resolutions` isn't borrowed during `try_define`,
15061600
// since it might get updated via a glob cycle.
15071601
let bindings = self
@@ -1512,6 +1606,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
15121606
resolution.borrow().binding().map(|binding| (*key, binding))
15131607
})
15141608
.collect::<Vec<_>>();
1609+
let mut import_bindings = Vec::with_capacity(bindings.len());
15151610
for (mut key, binding) in bindings {
15161611
let scope = match key.ident.0.span.reverse_glob_adjust(module.expansion, import.span) {
15171612
Some(Some(def)) => self.expn_def_scope(def),
@@ -1524,18 +1619,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
15241619
.resolution(import.parent_scope.module, key)
15251620
.and_then(|r| r.binding())
15261621
.is_some_and(|binding| binding.warn_ambiguity_recursive());
1527-
let _ = self.try_define_local(
1528-
import.parent_scope.module,
1529-
key.ident.0,
1530-
key.ns,
1531-
imported_binding,
1532-
warn_ambiguity,
1533-
);
1622+
import_bindings.push((imported_binding, key, warn_ambiguity));
15341623
}
15351624
}
15361625

15371626
// Record the destination of this import
1538-
self.record_partial_res(id, PartialRes::new(module.res().unwrap()));
1627+
SideEffect::Glob { import_bindings }
15391628
}
15401629

15411630
// Miscellaneous post-processing, including recording re-exports,

compiler/rustc_resolve/src/lib.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,12 +2581,6 @@ mod ref_mut {
25812581
true => self.p,
25822582
}
25832583
}
2584-
2585-
/// Returns a mutable reference to the inner value without checking if
2586-
/// it's in a mutable state.
2587-
pub(crate) fn get_mut_unchecked(&mut self) -> &mut T {
2588-
self.p
2589-
}
25902584
}
25912585

25922586
/// A wrapper around a [`Cell`] that only allows mutation based on a condition in the resolver.

fail.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![no_core]
2+
#![feature(no_core)]
3+
#![allow(internal_features)]
4+
#![feature(lang_items)]
5+
6+
#[lang = "sized"]
7+
pub trait Sized: MetaSized {}
8+
9+
#[lang = "meta_sized"]
10+
pub trait MetaSized: PointeeSized {}
11+
12+
#[lang = "pointee_sized"]
13+
pub trait PointeeSized {}
14+
15+
mod core_simd {
16+
mod vector {
17+
pub struct Simd {}
18+
}
19+
pub mod simd {
20+
pub use crate::core_simd::vector::*;
21+
}
22+
}
23+
24+
pub mod simd {
25+
pub use crate::core_simd::simd::*;
26+
}
27+
28+
mod fail {
29+
use crate::simd::Simd;
30+
}

0 commit comments

Comments
 (0)