Skip to main content

hir_def/
per_ns.rs

1//! In rust, it is possible to have a value, a type and a macro with the same
2//! name without conflicts.
3//!
4//! `PerNs` (per namespace) captures this.
5
6use bitflags::bitflags;
7
8use crate::{
9    MacroId, ModuleDefId,
10    item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob, ItemInNs},
11    visibility::Visibility,
12};
13
14#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
15pub enum Namespace {
16    Types,
17    Values,
18    Macros,
19}
20
21bitflags! {
22    /// Describes only the presence/absence of each namespace, without its value.
23    #[derive(Debug, PartialEq, Eq)]
24    pub(crate) struct NsAvailability : u32 {
25        const TYPES = 1 << 0;
26        const VALUES = 1 << 1;
27        const MACROS = 1 << 2;
28    }
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub struct Item<Def, Import = ImportId> {
33    pub def: Def,
34    pub vis: Visibility,
35    pub import: Option<Import>,
36}
37
38impl<Def: PartialEq, Import: Copy + PartialEq> Item<Def, Import> {
39    /// Whether `import` is the same import that produced `self`, now resolving to a different
40    /// `def`. This happens when an import is first recorded as an indeterminate resolution
41    /// (e.g. only one namespace was available at the time) and later re-resolves to another
42    /// def, such as an explicit import that shadows a glob only after the glob has been seen.
43    pub(crate) fn is_reresolved_by(&self, def: &Def, import: Option<Import>) -> bool {
44        import.is_some() && self.import == import && self.def != *def
45    }
46}
47
48pub type TypesItem = Item<ModuleDefId, ImportOrExternCrate>;
49pub type ValuesItem = Item<ModuleDefId, ImportOrGlob>;
50// May be Externcrate for `[macro_use]`'d macros
51pub type MacrosItem = Item<MacroId, ImportOrExternCrate>;
52
53#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
54pub struct PerNs {
55    pub types: Option<TypesItem>,
56    pub values: Option<ValuesItem>,
57    pub macros: Option<MacrosItem>,
58}
59
60impl PerNs {
61    pub(crate) fn availability(&self) -> NsAvailability {
62        let mut result = NsAvailability::empty();
63        result.set(NsAvailability::TYPES, self.types.is_some());
64        result.set(NsAvailability::VALUES, self.values.is_some());
65        result.set(NsAvailability::MACROS, self.macros.is_some());
66        result
67    }
68
69    pub fn none() -> PerNs {
70        PerNs { types: None, values: None, macros: None }
71    }
72
73    pub fn values(def: ModuleDefId, vis: Visibility, import: Option<ImportOrGlob>) -> PerNs {
74        PerNs { types: None, values: Some(Item { def, vis, import }), macros: None }
75    }
76
77    pub fn types(def: ModuleDefId, vis: Visibility, import: Option<ImportOrExternCrate>) -> PerNs {
78        PerNs { types: Some(Item { def, vis, import }), values: None, macros: None }
79    }
80
81    pub fn both(
82        types: ModuleDefId,
83        values: ModuleDefId,
84        vis: Visibility,
85        import: Option<ImportOrExternCrate>,
86    ) -> PerNs {
87        PerNs {
88            types: Some(Item { def: types, vis, import }),
89            values: Some(Item {
90                def: values,
91                vis,
92                import: import.and_then(ImportOrExternCrate::import_or_glob),
93            }),
94            macros: None,
95        }
96    }
97
98    pub fn macros(def: MacroId, vis: Visibility, import: Option<ImportOrExternCrate>) -> PerNs {
99        PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) }
100    }
101
102    pub fn is_none(&self) -> bool {
103        self.types.is_none() && self.values.is_none() && self.macros.is_none()
104    }
105
106    pub fn is_full(&self) -> bool {
107        self.types.is_some() && self.values.is_some() && self.macros.is_some()
108    }
109
110    pub fn take_types(self) -> Option<ModuleDefId> {
111        self.types.map(|it| it.def)
112    }
113
114    pub fn take_types_full(self) -> Option<TypesItem> {
115        self.types
116    }
117
118    pub fn take_values(self) -> Option<ModuleDefId> {
119        self.values.map(|it| it.def)
120    }
121
122    pub fn take_values_full(self) -> Option<ValuesItem> {
123        self.values
124    }
125
126    pub fn take_macros(self) -> Option<MacroId> {
127        self.macros.map(|it| it.def)
128    }
129
130    pub fn take_macros_full(self) -> Option<MacrosItem> {
131        self.macros
132    }
133
134    pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
135        let _p = tracing::info_span!("PerNs::filter_visibility").entered();
136        PerNs {
137            types: self.types.filter(|def| f(def.vis)),
138            values: self.values.filter(|def| f(def.vis)),
139            macros: self.macros.filter(|def| f(def.vis)),
140        }
141    }
142
143    pub fn with_visibility(self, vis: Visibility) -> PerNs {
144        PerNs {
145            types: self.types.map(|def| Item { vis, ..def }),
146            values: self.values.map(|def| Item { vis, ..def }),
147            macros: self.macros.map(|def| Item { vis, ..def }),
148        }
149    }
150
151    pub fn or(self, other: PerNs) -> PerNs {
152        PerNs {
153            types: self.types.or(other.types),
154            values: self.values.or(other.values),
155            macros: self.macros.or(other.macros),
156        }
157    }
158
159    pub fn or_else(self, f: impl FnOnce() -> PerNs) -> PerNs {
160        if self.is_full() { self } else { self.or(f()) }
161    }
162
163    pub fn iter_items(self) -> impl Iterator<Item = (ItemInNs, Option<ImportOrExternCrate>)> {
164        let _p = tracing::info_span!("PerNs::iter_items").entered();
165        self.types
166            .map(|it| (ItemInNs::Types(it.def), it.import))
167            .into_iter()
168            .chain(
169                self.values
170                    .map(|it| (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::from))),
171            )
172            .chain(self.macros.map(|it| (ItemInNs::Macros(it.def), it.import)))
173    }
174}