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
38pub type TypesItem = Item<ModuleDefId, ImportOrExternCrate>;
39pub type ValuesItem = Item<ModuleDefId, ImportOrGlob>;
40// May be Externcrate for `[macro_use]`'d macros
41pub type MacrosItem = Item<MacroId, ImportOrExternCrate>;
42
43#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
44pub struct PerNs {
45    pub types: Option<TypesItem>,
46    pub values: Option<ValuesItem>,
47    pub macros: Option<MacrosItem>,
48}
49
50impl PerNs {
51    pub(crate) fn availability(&self) -> NsAvailability {
52        let mut result = NsAvailability::empty();
53        result.set(NsAvailability::TYPES, self.types.is_some());
54        result.set(NsAvailability::VALUES, self.values.is_some());
55        result.set(NsAvailability::MACROS, self.macros.is_some());
56        result
57    }
58
59    pub fn none() -> PerNs {
60        PerNs { types: None, values: None, macros: None }
61    }
62
63    pub fn values(def: ModuleDefId, vis: Visibility, import: Option<ImportOrGlob>) -> PerNs {
64        PerNs { types: None, values: Some(Item { def, vis, import }), macros: None }
65    }
66
67    pub fn types(def: ModuleDefId, vis: Visibility, import: Option<ImportOrExternCrate>) -> PerNs {
68        PerNs { types: Some(Item { def, vis, import }), values: None, macros: None }
69    }
70
71    pub fn both(
72        types: ModuleDefId,
73        values: ModuleDefId,
74        vis: Visibility,
75        import: Option<ImportOrExternCrate>,
76    ) -> PerNs {
77        PerNs {
78            types: Some(Item { def: types, vis, import }),
79            values: Some(Item {
80                def: values,
81                vis,
82                import: import.and_then(ImportOrExternCrate::import_or_glob),
83            }),
84            macros: None,
85        }
86    }
87
88    pub fn macros(def: MacroId, vis: Visibility, import: Option<ImportOrExternCrate>) -> PerNs {
89        PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) }
90    }
91
92    pub fn is_none(&self) -> bool {
93        self.types.is_none() && self.values.is_none() && self.macros.is_none()
94    }
95
96    pub fn is_full(&self) -> bool {
97        self.types.is_some() && self.values.is_some() && self.macros.is_some()
98    }
99
100    pub fn take_types(self) -> Option<ModuleDefId> {
101        self.types.map(|it| it.def)
102    }
103
104    pub fn take_types_full(self) -> Option<TypesItem> {
105        self.types
106    }
107
108    pub fn take_values(self) -> Option<ModuleDefId> {
109        self.values.map(|it| it.def)
110    }
111
112    pub fn take_values_import(self) -> Option<(ModuleDefId, Option<ImportOrGlob>)> {
113        self.values.map(|it| (it.def, it.import))
114    }
115
116    pub fn take_macros(self) -> Option<MacroId> {
117        self.macros.map(|it| it.def)
118    }
119
120    pub fn take_macros_import(self) -> Option<(MacroId, Option<ImportOrExternCrate>)> {
121        self.macros.map(|it| (it.def, it.import))
122    }
123
124    pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
125        let _p = tracing::info_span!("PerNs::filter_visibility").entered();
126        PerNs {
127            types: self.types.filter(|def| f(def.vis)),
128            values: self.values.filter(|def| f(def.vis)),
129            macros: self.macros.filter(|def| f(def.vis)),
130        }
131    }
132
133    pub fn with_visibility(self, vis: Visibility) -> PerNs {
134        PerNs {
135            types: self.types.map(|def| Item { vis, ..def }),
136            values: self.values.map(|def| Item { vis, ..def }),
137            macros: self.macros.map(|def| Item { vis, ..def }),
138        }
139    }
140
141    pub fn or(self, other: PerNs) -> PerNs {
142        PerNs {
143            types: self.types.or(other.types),
144            values: self.values.or(other.values),
145            macros: self.macros.or(other.macros),
146        }
147    }
148
149    pub fn or_else(self, f: impl FnOnce() -> PerNs) -> PerNs {
150        if self.is_full() { self } else { self.or(f()) }
151    }
152
153    pub fn iter_items(self) -> impl Iterator<Item = (ItemInNs, Option<ImportOrExternCrate>)> {
154        let _p = tracing::info_span!("PerNs::iter_items").entered();
155        self.types
156            .map(|it| (ItemInNs::Types(it.def), it.import))
157            .into_iter()
158            .chain(
159                self.values
160                    .map(|it| (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::from))),
161            )
162            .chain(self.macros.map(|it| (ItemInNs::Macros(it.def), it.import)))
163    }
164}