Skip to content

Commit cc630bc

Browse files
committed
resolve: Evaluate private visibilities eagerly in eff vis computation
1 parent ce89c89 commit cc630bc

3 files changed

Lines changed: 39 additions & 36 deletions

File tree

compiler/rustc_middle/src/middle/privacy.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,13 +226,13 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
226226
&mut self,
227227
id: Id,
228228
max_vis: Option<Visibility>,
229-
lazy_private_vis: impl FnOnce() -> Visibility,
229+
private_vis: Visibility,
230230
inherited_effective_vis: EffectiveVisibility,
231231
level: Level,
232232
tcx: TyCtxt<'_>,
233233
) -> bool {
234234
let mut changed = false;
235-
let current_effective_vis = self.effective_vis_or_private(id, lazy_private_vis);
235+
let current_effective_vis = self.effective_vis_or_private(id, || private_vis);
236236

237237
let mut inherited_effective_vis_at_prev_level = *inherited_effective_vis.at_level(level);
238238
let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;

compiler/rustc_privacy/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
476476
self.changed |= self.effective_visibilities.update(
477477
def_id,
478478
max_vis,
479-
|| private_vis,
479+
private_vis,
480480
inherited_effective_vis,
481481
level,
482482
self.tcx,

compiler/rustc_resolve/src/effective_visibilities.rs

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,18 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
3838
}
3939

4040
impl Resolver<'_, '_> {
41-
fn nearest_normal_mod(&self, def_id: LocalDefId) -> LocalDefId {
42-
self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local()
43-
}
44-
45-
fn private_vis_import(&self, decl: Decl<'_>) -> Visibility {
46-
let DeclKind::Import { import, .. } = decl.kind else { unreachable!() };
41+
fn private_vis_decl(&self, decl: Decl<'_>) -> Visibility {
4742
Visibility::Restricted(
48-
import.def_id().map(|id| self.nearest_normal_mod(id)).unwrap_or(CRATE_DEF_ID),
43+
decl.parent_module.map_or(CRATE_DEF_ID, |m| m.nearest_parent_mod().expect_local()),
4944
)
5045
}
5146

5247
fn private_vis_def(&self, def_id: LocalDefId) -> Visibility {
53-
// For mod items `nearest_normal_mod` returns its argument, but we actually need its parent.
54-
let normal_mod_id = self.nearest_normal_mod(def_id);
48+
// For mod items `normal_mod_id` will be equal to `def_id`, but we actually need its parent.
49+
let normal_mod_id = self
50+
.get_nearest_non_block_module(def_id.to_def_id())
51+
.nearest_parent_mod()
52+
.expect_local();
5553
if normal_mod_id == def_id {
5654
Visibility::Restricted(self.tcx.local_parent(def_id))
5755
} else {
@@ -117,14 +115,19 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
117115
// Set the given effective visibility level to `Level::Direct` and
118116
// sets the rest of the `use` chain to `Level::Reexported` until
119117
// we hit the actual exported item.
118+
let priv_vis = |this: &Self, parent_id, decl| match parent_id {
119+
ParentId::Def(_) => this.current_private_vis,
120+
ParentId::Import(_) => this.r.private_vis_decl(decl),
121+
};
120122
let mut parent_id = ParentId::Def(module_id);
121123
while let DeclKind::Import { source_decl, .. } = decl.kind {
122-
self.update_import(decl, parent_id);
124+
self.update_import(decl, parent_id, priv_vis(self, parent_id, decl));
123125
parent_id = ParentId::Import(decl);
124126
decl = source_decl;
125127
}
126128
if let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) {
127-
self.update_def(def_id, decl.vis().expect_local(), parent_id);
129+
let priv_vis = priv_vis(self, parent_id, decl);
130+
self.update_def(def_id, decl.vis().expect_local(), parent_id, priv_vis);
128131
}
129132
}
130133
}
@@ -138,50 +141,46 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
138141
.effective_vis_or_private(def_id, || self.r.private_vis_def(def_id)),
139142
ParentId::Import(binding) => self
140143
.import_effective_visibilities
141-
.effective_vis_or_private(binding, || self.r.private_vis_import(binding)),
144+
.effective_vis_or_private(binding, || self.r.private_vis_decl(binding)),
142145
}
143146
}
144147

145148
/// All effective visibilities for a node are larger or equal than private visibility
146149
/// for that node (see `check_invariants` in middle/privacy.rs).
147150
/// So if either parent or nominal visibility is the same as private visibility, then
148-
/// `min(parent_vis, nominal_vis) <= private_vis`, and the update logic is guaranteed
151+
/// `min(parent_vis, nominal_vis) <= priv_vis`, and the update logic is guaranteed
149152
/// to not update anything and we can skip it.
150-
///
151-
/// We are checking this condition only if the correct value of private visibility is
152-
/// cheaply available, otherwise it doesn't make sense performance-wise.
153-
///
154-
/// `None` is returned if the update can be skipped,
155-
/// and cheap private visibility is returned otherwise.
156153
fn may_update(
157154
&self,
158155
nominal_vis: Visibility,
159156
parent_id: ParentId<'_>,
160-
) -> Option<Option<Visibility>> {
161-
match parent_id {
162-
ParentId::Def(def_id) => (nominal_vis != self.current_private_vis
163-
&& self.r.tcx.local_visibility(def_id) != self.current_private_vis)
164-
.then_some(Some(self.current_private_vis)),
165-
ParentId::Import(_) => Some(None),
166-
}
157+
priv_vis: Visibility,
158+
) -> bool {
159+
nominal_vis != priv_vis
160+
&& match parent_id {
161+
ParentId::Def(def_id) => self.r.tcx.local_visibility(def_id),
162+
ParentId::Import(decl) => decl.vis().expect_local(),
163+
} != priv_vis
167164
}
168165

169-
fn update_import(&mut self, decl: Decl<'ra>, parent_id: ParentId<'ra>) {
166+
fn update_import(&mut self, decl: Decl<'ra>, parent_id: ParentId<'ra>, priv_vis: Visibility) {
170167
let nominal_vis = decl.vis().expect_local();
171-
let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return };
168+
if !self.may_update(nominal_vis, parent_id, priv_vis) {
169+
return;
170+
};
172171
let inherited_eff_vis = self.effective_vis_or_private(parent_id);
173172
let tcx = self.r.tcx;
174173
self.changed |= self.import_effective_visibilities.update(
175174
decl,
176175
Some(nominal_vis),
177-
|| cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(decl)),
176+
priv_vis,
178177
inherited_eff_vis,
179178
parent_id.level(),
180179
tcx,
181180
);
182181
if let Some(max_vis_decl) = decl.ambiguity_vis_max.get() {
183182
// Avoid the most visible import in an ambiguous glob set being reported as unused.
184-
self.update_import(max_vis_decl, parent_id);
183+
self.update_import(max_vis_decl, parent_id, priv_vis);
185184
}
186185
}
187186

@@ -190,22 +189,26 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
190189
def_id: LocalDefId,
191190
nominal_vis: Visibility,
192191
parent_id: ParentId<'ra>,
192+
priv_vis: Visibility,
193193
) {
194-
let Some(cheap_private_vis) = self.may_update(nominal_vis, parent_id) else { return };
194+
if !self.may_update(nominal_vis, parent_id, priv_vis) {
195+
return;
196+
};
195197
let inherited_eff_vis = self.effective_vis_or_private(parent_id);
196198
let tcx = self.r.tcx;
197199
self.changed |= self.def_effective_visibilities.update(
198200
def_id,
199201
Some(nominal_vis),
200-
|| cheap_private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)),
202+
priv_vis,
201203
inherited_eff_vis,
202204
parent_id.level(),
203205
tcx,
204206
);
205207
}
206208

207209
fn update_field(&mut self, def_id: LocalDefId, parent_id: LocalDefId) {
208-
self.update_def(def_id, self.r.tcx.local_visibility(def_id), ParentId::Def(parent_id));
210+
let nominal_vis = self.r.tcx.local_visibility(def_id);
211+
self.update_def(def_id, nominal_vis, ParentId::Def(parent_id), self.current_private_vis);
209212
}
210213
}
211214

0 commit comments

Comments
 (0)