Skip to content

Commit ee4faf9

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 82224f6 commit ee4faf9

File tree

10 files changed

+243
-139
lines changed

10 files changed

+243
-139
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: 140 additions & 58 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> {
@@ -553,22 +644,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
553644
/// Resolves all imports for the crate. This method performs the fixed-
554645
/// point iteration.
555646
pub(crate) fn resolve_imports(&mut self) {
556-
self.assert_speculative = true;
557647
let mut prev_indeterminate_count = usize::MAX;
558648
let mut indeterminate_count = self.indeterminate_imports.len() * 3;
559649
while indeterminate_count < prev_indeterminate_count {
560650
prev_indeterminate_count = indeterminate_count;
561-
indeterminate_count = 0;
562-
for import in mem::take(&mut self.indeterminate_imports) {
563-
let import_indeterminate_count = self.cm().resolve_import(import);
564-
indeterminate_count += import_indeterminate_count;
565-
match import_indeterminate_count {
566-
0 => self.determined_imports.push(import),
567-
_ => self.indeterminate_imports.push(import),
568-
}
651+
let batch = mem::take(&mut self.indeterminate_imports);
652+
self.assert_speculative = true;
653+
let (outputs, count) =
654+
ImportResolver { r: self.cm(), outputs: Default::default() }.resolve_batch(batch);
655+
self.assert_speculative = false;
656+
indeterminate_count = count;
657+
outputs.commit(self);
658+
}
659+
}
660+
661+
fn resolve_batch<'r>(
662+
mut self: ImportResolver<'r, 'ra, 'tcx>,
663+
batch: Vec<Import<'ra>>,
664+
) -> (ImportResolutionOutputs<'ra>, usize) {
665+
let mut indeterminate_count = 0;
666+
for import in batch {
667+
let (side_effect, import_indeterminate_count) = self.resolve_import(import);
668+
indeterminate_count += import_indeterminate_count;
669+
match import_indeterminate_count {
670+
0 => self.outputs.determined_imports.push((import, side_effect)),
671+
_ => self.outputs.indeterminate_imports.push(import),
569672
}
570673
}
571-
self.assert_speculative = false;
674+
(self.outputs, indeterminate_count)
572675
}
573676

574677
pub(crate) fn finalize_imports(&mut self) {
@@ -837,7 +940,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
837940
///
838941
/// Meanwhile, if resolve successful, the resolved bindings are written
839942
/// into the module.
840-
fn resolve_import<'r>(mut self: CmResolver<'r, 'ra, 'tcx>, import: Import<'ra>) -> usize {
943+
fn resolve_import<'r>(
944+
self: &mut ImportResolver<'r, 'ra, 'tcx>,
945+
import: Import<'ra>,
946+
) -> (SideEffect<'ra>, usize) {
841947
debug!(
842948
"(resolving import for module) resolving import `{}::...` in `{}`",
843949
Segment::names_to_string(&import.module_path),
@@ -846,7 +952,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
846952
let module = if let Some(module) = import.imported_module.get() {
847953
module
848954
} else {
849-
let path_res = self.reborrow().maybe_resolve_path(
955+
let path_res = self.r.reborrow().maybe_resolve_path(
850956
&import.module_path,
851957
None,
852958
&import.parent_scope,
@@ -855,8 +961,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
855961

856962
match path_res {
857963
PathResult::Module(module) => module,
858-
PathResult::Indeterminate => return 3,
859-
PathResult::NonModule(..) | PathResult::Failed { .. } => return 0,
964+
PathResult::Indeterminate => return (SideEffect::None, 3),
965+
PathResult::NonModule(..) | PathResult::Failed { .. } => {
966+
return (SideEffect::None, 0);
967+
}
860968
}
861969
};
862970

@@ -867,16 +975,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
867975
(source, target, bindings, type_ns_only)
868976
}
869977
ImportKind::Glob { .. } => {
870-
// FIXME: Use mutable resolver directly as a hack, this should be an output of
871-
// speculative resolution.
872-
self.get_mut_unchecked().resolve_glob_import(import);
873-
return 0;
978+
return (self.resolve_glob_import(import), 0);
874979
}
875980
_ => unreachable!(),
876981
};
877982

983+
let mut import_bindings = PerNS::default();
878984
let mut indeterminate_count = 0;
879-
self.per_ns_cm(|this, ns| {
985+
self.r.reborrow().per_ns_cm(|this, ns| {
880986
if !type_ns_only || ns == TypeNS {
881987
if bindings[ns].get() != PendingBinding::Pending {
882988
return;
@@ -888,8 +994,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
888994
&import.parent_scope,
889995
Some(import),
890996
);
891-
let parent = import.parent_scope.module;
892-
let binding = match binding_result {
997+
let pending_binding = match binding_result {
893998
Ok(binding) => {
894999
if binding.is_assoc_item()
8951000
&& !this.tcx.features().import_trait_associated_functions()
@@ -904,44 +1009,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
9041009
}
9051010
// We need the `target`, `source` can be extracted.
9061011
let imported_binding = this.import(binding, import);
907-
// FIXME: Use mutable resolver directly as a hack, this should be an output of
908-
// speculative resolution.
909-
this.get_mut_unchecked().define_binding_local(
910-
parent,
911-
target,
912-
ns,
913-
imported_binding,
914-
);
9151012
PendingBinding::Ready(Some(imported_binding))
9161013
}
9171014
Err(Determinacy::Determined) => {
9181015
// Don't remove underscores from `single_imports`, they were never added.
919-
if target.name != kw::Underscore {
920-
let key = BindingKey::new(target, ns);
921-
// FIXME: Use mutable resolver directly as a hack, this should be an output of
922-
// speculative resolution.
923-
this.get_mut_unchecked().update_local_resolution(
924-
parent,
925-
key,
926-
false,
927-
|_, resolution| {
928-
resolution.single_imports.swap_remove(&import);
929-
},
930-
);
1016+
if target.name == kw::Underscore {
1017+
return;
9311018
}
9321019
PendingBinding::Ready(None)
9331020
}
9341021
Err(Determinacy::Undetermined) => {
9351022
indeterminate_count += 1;
936-
PendingBinding::Pending
1023+
return;
9371024
}
9381025
};
9391026
// FIXME(batched): Will be fixed in batched import resolution.
9401027
bindings[ns].set_unchecked(binding);
9411028
}
9421029
});
9431030

944-
indeterminate_count
1031+
(SideEffect::Single { import_bindings }, indeterminate_count)
9451032
}
9461033

9471034
/// Performs final import resolution, consistency checks and error reporting.
@@ -1484,13 +1571,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
14841571
false
14851572
}
14861573

1487-
fn resolve_glob_import(&mut self, import: Import<'ra>) {
1574+
fn resolve_glob_import<'r>(
1575+
self: &mut ImportResolver<'r, 'ra, 'tcx>,
1576+
import: Import<'ra>,
1577+
) -> SideEffect<'ra> {
14881578
// This function is only called for glob imports.
1489-
let ImportKind::Glob { id, .. } = import.kind else { unreachable!() };
1579+
let ImportKind::Glob { .. } = import.kind else { unreachable!() };
14901580

14911581
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
14921582
self.dcx().emit_err(CannotGlobImportAllCrates { span: import.span });
1493-
return;
1583+
return SideEffect::None;
14941584
};
14951585

14961586
if module.is_trait() && !self.tcx.features().import_trait_associated_functions() {
@@ -1504,12 +1594,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
15041594
}
15051595

15061596
if module == import.parent_scope.module {
1507-
return;
1597+
return SideEffect::None;
15081598
}
15091599

1510-
// Add to module's glob_importers
1511-
module.glob_importers.borrow_mut_unchecked().push(import);
1512-
15131600
// Ensure that `resolutions` isn't borrowed during `try_define`,
15141601
// since it might get updated via a glob cycle.
15151602
let bindings = self
@@ -1520,6 +1607,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
15201607
resolution.borrow().binding().map(|binding| (*key, binding))
15211608
})
15221609
.collect::<Vec<_>>();
1610+
let mut import_bindings = Vec::with_capacity(bindings.len());
15231611
for (mut key, binding) in bindings {
15241612
let scope = match key.ident.0.span.reverse_glob_adjust(module.expansion, import.span) {
15251613
Some(Some(def)) => self.expn_def_scope(def),
@@ -1532,18 +1620,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
15321620
.resolution(import.parent_scope.module, key)
15331621
.and_then(|r| r.binding())
15341622
.is_some_and(|binding| binding.warn_ambiguity_recursive());
1535-
let _ = self.try_define_local(
1536-
import.parent_scope.module,
1537-
key.ident.0,
1538-
key.ns,
1539-
imported_binding,
1540-
warn_ambiguity,
1541-
);
1623+
import_bindings.push((imported_binding, key, warn_ambiguity));
15421624
}
15431625
}
15441626

15451627
// Record the destination of this import
1546-
self.record_partial_res(id, PartialRes::new(module.res().unwrap()));
1628+
SideEffect::Glob { import_bindings }
15471629
}
15481630

15491631
// 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
@@ -2569,12 +2569,6 @@ mod ref_mut {
25692569
true => self.p,
25702570
}
25712571
}
2572-
2573-
/// Returns a mutable reference to the inner value without checking if
2574-
/// it's in a mutable state.
2575-
pub(crate) fn get_mut_unchecked(&mut self) -> &mut T {
2576-
self.p
2577-
}
25782572
}
25792573

25802574
/// 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)