]> git.lizzy.rs Git - rust.git/blob - crates/ra_hir_def/src/item_scope.rs
Revert "Merge #2629"
[rust.git] / crates / ra_hir_def / src / item_scope.rs
1 //! Describes items defined or visible (ie, imported) in a certain scope.
2 //! This is shared between modules and blocks.
3
4 use hir_expand::name::Name;
5 use once_cell::sync::Lazy;
6 use rustc_hash::FxHashMap;
7
8 use crate::{per_ns::PerNs, BuiltinType, ImplId, LocalImportId, MacroDefId, ModuleDefId, TraitId};
9
10 #[derive(Debug, Default, PartialEq, Eq)]
11 pub struct ItemScope {
12     items: FxHashMap<Name, Resolution>,
13     impls: Vec<ImplId>,
14     /// Macros visible in current module in legacy textual scope
15     ///
16     /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
17     /// If it yields no result, then it turns to module scoped `macros`.
18     /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
19     /// and only normal scoped `macros` will be searched in.
20     ///
21     /// Note that this automatically inherit macros defined textually before the definition of module itself.
22     ///
23     /// Module scoped macros will be inserted into `items` instead of here.
24     // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
25     // be all resolved to the last one defined if shadowing happens.
26     legacy_macros: FxHashMap<Name, MacroDefId>,
27 }
28
29 static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
30     BuiltinType::ALL
31         .iter()
32         .map(|(name, ty)| {
33             (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
34         })
35         .collect()
36 });
37
38 /// Shadow mode for builtin type which can be shadowed by module.
39 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
40 pub(crate) enum BuiltinShadowMode {
41     // Prefer Module
42     Module,
43     // Prefer Other Types
44     Other,
45 }
46
47 /// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
48 /// Other methods will only resolve values, types and module scoped macros only.
49 impl ItemScope {
50     pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
51         //FIXME: shadowing
52         self.items.iter().chain(BUILTIN_SCOPE.iter())
53     }
54
55     pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
56         self.entries()
57             .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None })
58             .flat_map(|per_ns| {
59                 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
60             })
61     }
62
63     pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
64         self.impls.iter().copied()
65     }
66
67     /// Iterate over all module scoped macros
68     pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
69         self.items
70             .iter()
71             .filter_map(|(name, res)| res.def.take_macros().map(|macro_| (name, macro_)))
72     }
73
74     /// Iterate over all legacy textual scoped macros visible at the end of the module
75     pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
76         self.legacy_macros.iter().map(|(name, def)| (name, *def))
77     }
78
79     /// Get a name from current module scope, legacy macros are not included
80     pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> Option<&Resolution> {
81         match shadow {
82             BuiltinShadowMode::Module => self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)),
83             BuiltinShadowMode::Other => {
84                 let item = self.items.get(name);
85                 if let Some(res) = item {
86                     if let Some(ModuleDefId::ModuleId(_)) = res.def.take_types() {
87                         return BUILTIN_SCOPE.get(name).or(item);
88                     }
89                 }
90
91                 item.or_else(|| BUILTIN_SCOPE.get(name))
92             }
93         }
94     }
95
96     pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
97         self.items.values().filter_map(|r| match r.def.take_types() {
98             Some(ModuleDefId::TraitId(t)) => Some(t),
99             _ => None,
100         })
101     }
102
103     pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
104         self.legacy_macros.get(name).copied()
105     }
106
107     pub(crate) fn define_impl(&mut self, imp: ImplId) {
108         self.impls.push(imp)
109     }
110
111     pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
112         self.legacy_macros.insert(name, mac);
113     }
114
115     pub(crate) fn push_res(
116         &mut self,
117         name: Name,
118         res: &Resolution,
119         import: Option<LocalImportId>,
120     ) -> bool {
121         let mut changed = false;
122         let existing = self.items.entry(name.clone()).or_default();
123
124         if existing.def.types.is_none() && res.def.types.is_some() {
125             existing.def.types = res.def.types;
126             existing.import = import.or(res.import);
127             changed = true;
128         }
129         if existing.def.values.is_none() && res.def.values.is_some() {
130             existing.def.values = res.def.values;
131             existing.import = import.or(res.import);
132             changed = true;
133         }
134         if existing.def.macros.is_none() && res.def.macros.is_some() {
135             existing.def.macros = res.def.macros;
136             existing.import = import.or(res.import);
137             changed = true;
138         }
139
140         if existing.def.is_none()
141             && res.def.is_none()
142             && existing.import.is_none()
143             && res.import.is_some()
144         {
145             existing.import = res.import;
146         }
147         changed
148     }
149
150     pub(crate) fn collect_resolutions(&self) -> Vec<(Name, Resolution)> {
151         self.items.iter().map(|(name, res)| (name.clone(), res.clone())).collect()
152     }
153
154     pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
155         self.legacy_macros.clone()
156     }
157 }
158
159 #[derive(Debug, Clone, PartialEq, Eq, Default)]
160 pub struct Resolution {
161     /// None for unresolved
162     pub def: PerNs,
163     /// ident by which this is imported into local scope.
164     pub import: Option<LocalImportId>,
165 }