1use std::cmp::Ordering;
6use std::hash::Hash;
7
8use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
9use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher};
10use rustc_hir::def::DefKind;
11use rustc_hir::{ItemKind, Node, UseKind};
12use rustc_macros::StableHash;
13use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId};
14use rustc_span::span_bug;
15
16use crate::ty::{TyCtxt, Visibility};
17
18#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Level { }
#[automatically_derived]
impl ::core::clone::Clone for Level {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Level { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for Level {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
Level::ReachableThroughImplTrait =>
"ReachableThroughImplTrait",
Level::Reachable => "Reachable",
Level::Reexported => "Reexported",
Level::Direct => "Direct",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Level { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Level {
#[inline]
fn eq(&self, other: &Self) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Level { }Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for Level {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for Level {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr)
}
}Ord, const _: () =
{
impl ::rustc_data_structures::stable_hash::StableHash for Level {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
match *self {
Level::ReachableThroughImplTrait => {}
Level::Reachable => {}
Level::Reexported => {}
Level::Direct => {}
}
}
}
};StableHash)]
22pub enum Level {
23 ReachableThroughImplTrait,
25 Reachable,
30 Reexported,
32 Direct,
34}
35
36impl Level {
37 pub fn all_levels() -> [Level; 4] {
38 [Level::Direct, Level::Reexported, Level::Reachable, Level::ReachableThroughImplTrait]
39 }
40}
41
42#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for EffectiveVisibility { }
#[automatically_derived]
impl ::core::clone::Clone for EffectiveVisibility {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<Visibility>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for EffectiveVisibility { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for EffectiveVisibility { }
#[automatically_derived]
impl ::core::cmp::PartialEq for EffectiveVisibility {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.direct == other.direct && self.reexported == other.reexported &&
self.reachable == other.reachable &&
self.reachable_through_impl_trait ==
other.reachable_through_impl_trait
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for EffectiveVisibility {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Visibility>;
}
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for EffectiveVisibility {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field4_finish(f,
"EffectiveVisibility", "direct", &self.direct, "reexported",
&self.reexported, "reachable", &self.reachable,
"reachable_through_impl_trait",
&&self.reachable_through_impl_trait)
}
}Debug, const _: () =
{
impl ::rustc_data_structures::stable_hash::StableHash for
EffectiveVisibility {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
EffectiveVisibility {
direct: ref __binding_0,
reexported: ref __binding_1,
reachable: ref __binding_2,
reachable_through_impl_trait: ref __binding_3 } => {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
{ __binding_2.stable_hash(__hcx, __hasher); }
{ __binding_3.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
43pub struct EffectiveVisibility {
44 direct: Visibility,
45 reexported: Visibility,
46 reachable: Visibility,
47 reachable_through_impl_trait: Visibility,
48}
49
50impl EffectiveVisibility {
51 pub fn at_level(&self, level: Level) -> &Visibility {
52 match level {
53 Level::Direct => &self.direct,
54 Level::Reexported => &self.reexported,
55 Level::Reachable => &self.reachable,
56 Level::ReachableThroughImplTrait => &self.reachable_through_impl_trait,
57 }
58 }
59
60 fn at_level_mut(&mut self, level: Level) -> &mut Visibility {
61 match level {
62 Level::Direct => &mut self.direct,
63 Level::Reexported => &mut self.reexported,
64 Level::Reachable => &mut self.reachable,
65 Level::ReachableThroughImplTrait => &mut self.reachable_through_impl_trait,
66 }
67 }
68
69 pub fn public_at_level(&self) -> Option<Level> {
70 Level::all_levels().into_iter().find(|&level| self.is_public_at_level(level))
71 }
72
73 pub fn is_public_at_level(&self, level: Level) -> bool {
74 self.at_level(level).is_public()
75 }
76
77 pub const fn from_vis(vis: Visibility) -> EffectiveVisibility {
78 EffectiveVisibility {
79 direct: vis,
80 reexported: vis,
81 reachable: vis,
82 reachable_through_impl_trait: vis,
83 }
84 }
85
86 #[must_use]
87 pub fn min(mut self, lhs: EffectiveVisibility, tcx: TyCtxt<'_>) -> Self {
88 for l in Level::all_levels() {
89 let rhs_vis = self.at_level_mut(l);
90 let lhs_vis = *lhs.at_level(l);
91 if rhs_vis.partial_cmp(lhs_vis, tcx) == Some(Ordering::Greater) {
94 *rhs_vis = lhs_vis;
95 };
96 }
97 self
98 }
99}
100
101#[derive(#[automatically_derived]
impl<Id: ::core::clone::Clone> ::core::clone::Clone for
EffectiveVisibilities<Id> {
#[inline]
fn clone(&self) -> Self {
EffectiveVisibilities { map: ::core::clone::Clone::clone(&self.map) }
}
}Clone, #[automatically_derived]
impl<Id: ::core::fmt::Debug> ::core::fmt::Debug for EffectiveVisibilities<Id>
{
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f,
"EffectiveVisibilities", "map", &&self.map)
}
}Debug)]
103pub struct EffectiveVisibilities<Id = LocalDefId> {
104 map: FxIndexMap<Id, EffectiveVisibility>,
105}
106
107impl EffectiveVisibilities {
108 pub fn is_public_at_level(&self, id: LocalDefId, level: Level) -> bool {
109 self.effective_vis(id).is_some_and(|effective_vis| effective_vis.is_public_at_level(level))
110 }
111
112 pub fn is_reachable(&self, id: LocalDefId) -> bool {
114 self.is_public_at_level(id, Level::Reachable)
115 }
116
117 pub fn is_exported(&self, id: LocalDefId) -> bool {
119 self.is_public_at_level(id, Level::Reexported)
120 }
121
122 pub fn is_directly_public(&self, id: LocalDefId) -> bool {
124 self.is_public_at_level(id, Level::Direct)
125 }
126
127 pub fn public_at_level(&self, id: LocalDefId) -> Option<Level> {
128 self.effective_vis(id).and_then(|effective_vis| effective_vis.public_at_level())
129 }
130
131 pub fn update_root(&mut self) {
132 self.map.insert(CRATE_DEF_ID, EffectiveVisibility::from_vis(Visibility::Public));
133 }
134
135 pub fn update_eff_vis(
137 &mut self,
138 def_id: LocalDefId,
139 eff_vis: &EffectiveVisibility,
140 tcx: TyCtxt<'_>,
141 ) {
142 match self.map.entry(def_id) {
143 IndexEntry::Occupied(mut occupied) => {
144 let old_eff_vis = occupied.get_mut();
145 for l in Level::all_levels() {
146 let vis_at_level = eff_vis.at_level(l);
147 let old_vis_at_level = old_eff_vis.at_level_mut(l);
148 if vis_at_level.greater_than(*old_vis_at_level, tcx) {
149 *old_vis_at_level = *vis_at_level
150 }
151 }
152 old_eff_vis
153 }
154 IndexEntry::Vacant(vacant) => vacant.insert(*eff_vis),
155 };
156 }
157
158 pub fn check_invariants(&self, tcx: TyCtxt<'_>) {
159 if !truecfg!(debug_assertions) {
160 return;
161 }
162 for (&def_id, ev) in &self.map {
163 let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id));
166 let span = tcx.def_span(def_id.to_def_id());
167 if private_vis.greater_than(ev.direct, tcx) {
168 ::rustc_span::macros::bug_impl(Some(span),
format_args!("private {0:?} > direct {1:?}", private_vis, ev.direct),
Location::caller());span_bug!(span, "private {:?} > direct {:?}", private_vis, ev.direct);
169 }
170 if ev.direct.greater_than(ev.reexported, tcx) {
171 ::rustc_span::macros::bug_impl(Some(span),
format_args!("direct {0:?} > reexported {1:?}", ev.direct, ev.reexported),
Location::caller());span_bug!(span, "direct {:?} > reexported {:?}", ev.direct, ev.reexported);
172 }
173 if ev.reexported.greater_than(ev.reachable, tcx) {
174 ::rustc_span::macros::bug_impl(Some(span),
format_args!("reexported {0:?} > reachable {1:?}", ev.reexported,
ev.reachable), Location::caller());span_bug!(span, "reexported {:?} > reachable {:?}", ev.reexported, ev.reachable);
175 }
176 if ev.reachable.greater_than(ev.reachable_through_impl_trait, tcx) {
177 ::rustc_span::macros::bug_impl(Some(span),
format_args!("reachable {0:?} > reachable_through_impl_trait {1:?}",
ev.reachable, ev.reachable_through_impl_trait), Location::caller());span_bug!(
178 span,
179 "reachable {:?} > reachable_through_impl_trait {:?}",
180 ev.reachable,
181 ev.reachable_through_impl_trait
182 );
183 }
184 let is_impl = #[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(def_id) {
DefKind::Impl { .. } => true,
_ => false,
}matches!(tcx.def_kind(def_id), DefKind::Impl { .. });
188 if !is_impl && tcx.trait_impl_of_assoc(def_id.to_def_id()).is_none() {
189 let nominal_vis = tcx.visibility(def_id);
190 if ev.reachable.greater_than(nominal_vis, tcx) {
191 if let Node::Item(item) = tcx.hir_node_by_def_id(def_id)
192 && let ItemKind::Use(_, UseKind::Glob) = item.kind
193 {
194 } else {
197 ::rustc_span::macros::bug_impl(Some(span),
format_args!("{0:?}: reachable {1:?} > nominal {2:?}", def_id,
ev.reachable, nominal_vis), Location::caller());span_bug!(
198 span,
199 "{:?}: reachable {:?} > nominal {:?}",
200 def_id,
201 ev.reachable,
202 nominal_vis,
203 );
204 }
205 }
206 }
207 }
208 }
209}
210
211impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
212 pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
213 self.map.iter()
214 }
215
216 pub fn effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
217 self.map.get(&id)
218 }
219
220 pub fn effective_vis_or_private(
221 &mut self,
222 id: Id,
223 lazy_private_vis: impl FnOnce() -> Visibility,
224 ) -> &mut EffectiveVisibility {
225 self.map.entry(id).or_insert_with(|| EffectiveVisibility::from_vis(lazy_private_vis()))
226 }
227
228 pub fn update(
229 &mut self,
230 id: Id,
231 max_vis: Option<Visibility>,
232 private_vis: Visibility,
233 inherited_effective_vis: EffectiveVisibility,
234 level: Level,
235 tcx: TyCtxt<'_>,
236 ) -> bool {
237 let mut changed = false;
238 let current_effective_vis = self.effective_vis_or_private(id, || private_vis);
239
240 let mut inherited_effective_vis_at_prev_level = *inherited_effective_vis.at_level(level);
241 let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
242 for l in Level::all_levels() {
243 if level >= l {
244 let inherited_effective_vis_at_level = *inherited_effective_vis.at_level(l);
245 let current_effective_vis_at_level = current_effective_vis.at_level_mut(l);
246 if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
249 && level != l)
250 {
251 calculated_effective_vis = if let Some(max_vis) = max_vis
254 && inherited_effective_vis_at_level.partial_cmp(max_vis, tcx)
255 == Some(Ordering::Greater)
256 {
257 max_vis
258 } else {
259 inherited_effective_vis_at_level
260 }
261 }
262 if calculated_effective_vis.partial_cmp(*current_effective_vis_at_level, tcx)
267 == Some(Ordering::Greater)
268 {
269 changed = true;
270 *current_effective_vis_at_level = calculated_effective_vis;
271 }
272 inherited_effective_vis_at_prev_level = inherited_effective_vis_at_level;
273 }
274 }
275
276 changed
277 }
278}
279
280impl<Id> Default for EffectiveVisibilities<Id> {
281 fn default() -> Self {
282 EffectiveVisibilities { map: Default::default() }
283 }
284}
285
286impl StableHash for EffectiveVisibilities {
287 fn stable_hash<Hcx: StableHashCtxt>(&self, hcx: &mut Hcx, hasher: &mut StableHasher) {
288 let EffectiveVisibilities { ref map } = *self;
289 map.stable_hash(hcx, hasher);
290 }
291}