diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-07-31 03:12:44 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-07-31 03:12:44 +0100 |
commit | f05d7b41a719d848844b054a16477b29d0f063c6 (patch) | |
tree | 0a8a0946e8aef2ce64d4c13d0035ba41cce2daf3 /crates/ra_hir_def/src/item_scope.rs | |
parent | 73ff610e41959e3e7c78a2b4b25b086883132956 (diff) | |
parent | 6b7cb8b5ab539fc4333ce34bc29bf77c976f232a (diff) |
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Hasn't fixed tests yet.
Diffstat (limited to 'crates/ra_hir_def/src/item_scope.rs')
-rw-r--r-- | crates/ra_hir_def/src/item_scope.rs | 132 |
1 files changed, 90 insertions, 42 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index 4d446c707..8fee4b15e 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! Describes items defined or visible (ie, imported) in a certain scope. | 1 | //! Describes items defined or visible (ie, imported) in a certain scope. |
2 | //! This is shared between modules and blocks. | 2 | //! This is shared between modules and blocks. |
3 | 3 | ||
4 | use std::collections::hash_map::Entry; | ||
5 | |||
4 | use hir_expand::name::Name; | 6 | use hir_expand::name::Name; |
5 | use once_cell::sync::Lazy; | 7 | use once_cell::sync::Lazy; |
6 | use ra_db::CrateId; | 8 | use ra_db::CrateId; |
@@ -27,9 +29,15 @@ pub struct PerNsGlobImports { | |||
27 | 29 | ||
28 | #[derive(Debug, Default, PartialEq, Eq)] | 30 | #[derive(Debug, Default, PartialEq, Eq)] |
29 | pub struct ItemScope { | 31 | pub struct ItemScope { |
30 | visible: FxHashMap<Name, PerNs>, | 32 | types: FxHashMap<Name, (ModuleDefId, Visibility)>, |
33 | values: FxHashMap<Name, (ModuleDefId, Visibility)>, | ||
34 | macros: FxHashMap<Name, (MacroDefId, Visibility)>, | ||
35 | unresolved: FxHashSet<Name>, | ||
36 | |||
31 | defs: Vec<ModuleDefId>, | 37 | defs: Vec<ModuleDefId>, |
32 | impls: Vec<ImplId>, | 38 | impls: Vec<ImplId>, |
39 | /// Traits imported via `use Trait as _;`. | ||
40 | unnamed_trait_imports: FxHashMap<TraitId, Visibility>, | ||
33 | /// Macros visible in current module in legacy textual scope | 41 | /// Macros visible in current module in legacy textual scope |
34 | /// | 42 | /// |
35 | /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. | 43 | /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. |
@@ -65,14 +73,16 @@ pub(crate) enum BuiltinShadowMode { | |||
65 | /// Other methods will only resolve values, types and module scoped macros only. | 73 | /// Other methods will only resolve values, types and module scoped macros only. |
66 | impl ItemScope { | 74 | impl ItemScope { |
67 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { | 75 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { |
68 | //FIXME: shadowing | 76 | // FIXME: shadowing |
69 | self.visible.iter().map(|(n, def)| (n, *def)) | 77 | let keys: FxHashSet<_> = self |
70 | } | 78 | .types |
71 | 79 | .keys() | |
72 | pub fn entries_without_primitives<'a>( | 80 | .chain(self.values.keys()) |
73 | &'a self, | 81 | .chain(self.macros.keys()) |
74 | ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { | 82 | .chain(self.unresolved.iter()) |
75 | self.visible.iter().map(|(n, def)| (n, *def)) | 83 | .collect(); |
84 | |||
85 | keys.into_iter().map(move |name| (name, self.get(name))) | ||
76 | } | 86 | } |
77 | 87 | ||
78 | pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { | 88 | pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { |
@@ -91,7 +101,7 @@ impl ItemScope { | |||
91 | 101 | ||
92 | /// Iterate over all module scoped macros | 102 | /// Iterate over all module scoped macros |
93 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | 103 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { |
94 | self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) | 104 | self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) |
95 | } | 105 | } |
96 | 106 | ||
97 | /// Iterate over all legacy textual scoped macros visible at the end of the module | 107 | /// Iterate over all legacy textual scoped macros visible at the end of the module |
@@ -101,12 +111,16 @@ impl ItemScope { | |||
101 | 111 | ||
102 | /// Get a name from current module scope, legacy macros are not included | 112 | /// Get a name from current module scope, legacy macros are not included |
103 | pub(crate) fn get(&self, name: &Name) -> PerNs { | 113 | pub(crate) fn get(&self, name: &Name) -> PerNs { |
104 | self.visible.get(name).copied().unwrap_or_else(PerNs::none) | 114 | PerNs { |
115 | types: self.types.get(name).copied(), | ||
116 | values: self.values.get(name).copied(), | ||
117 | macros: self.macros.get(name).copied(), | ||
118 | } | ||
105 | } | 119 | } |
106 | 120 | ||
107 | pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { | 121 | pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { |
108 | for (name, per_ns) in &self.visible { | 122 | for (name, per_ns) in self.entries() { |
109 | if let Some(vis) = item.match_with(*per_ns) { | 123 | if let Some(vis) = item.match_with(per_ns) { |
110 | return Some((name, vis)); | 124 | return Some((name, vis)); |
111 | } | 125 | } |
112 | } | 126 | } |
@@ -114,10 +128,13 @@ impl ItemScope { | |||
114 | } | 128 | } |
115 | 129 | ||
116 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { | 130 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { |
117 | self.visible.values().filter_map(|def| match def.take_types() { | 131 | self.types |
118 | Some(ModuleDefId::TraitId(t)) => Some(t), | 132 | .values() |
119 | _ => None, | 133 | .filter_map(|(def, _)| match def { |
120 | }) | 134 | ModuleDefId::TraitId(t) => Some(*t), |
135 | _ => None, | ||
136 | }) | ||
137 | .chain(self.unnamed_trait_imports.keys().copied()) | ||
121 | } | 138 | } |
122 | 139 | ||
123 | pub(crate) fn define_def(&mut self, def: ModuleDefId) { | 140 | pub(crate) fn define_def(&mut self, def: ModuleDefId) { |
@@ -136,23 +153,40 @@ impl ItemScope { | |||
136 | self.legacy_macros.insert(name, mac); | 153 | self.legacy_macros.insert(name, mac); |
137 | } | 154 | } |
138 | 155 | ||
156 | pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> { | ||
157 | self.unnamed_trait_imports.get(&tr).copied() | ||
158 | } | ||
159 | |||
160 | pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) { | ||
161 | self.unnamed_trait_imports.insert(tr, vis); | ||
162 | } | ||
163 | |||
139 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { | 164 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { |
140 | let mut changed = false; | 165 | let mut changed = false; |
141 | let existing = self.visible.entry(name).or_default(); | ||
142 | 166 | ||
143 | if existing.types.is_none() && def.types.is_some() { | 167 | if let Some(types) = def.types { |
144 | existing.types = def.types; | 168 | self.types.entry(name.clone()).or_insert_with(|| { |
145 | changed = true; | 169 | changed = true; |
170 | types | ||
171 | }); | ||
146 | } | 172 | } |
147 | 173 | if let Some(values) = def.values { | |
148 | if existing.values.is_none() && def.values.is_some() { | 174 | self.values.entry(name.clone()).or_insert_with(|| { |
149 | existing.values = def.values; | 175 | changed = true; |
150 | changed = true; | 176 | values |
177 | }); | ||
178 | } | ||
179 | if let Some(macros) = def.macros { | ||
180 | self.macros.entry(name.clone()).or_insert_with(|| { | ||
181 | changed = true; | ||
182 | macros | ||
183 | }); | ||
151 | } | 184 | } |
152 | 185 | ||
153 | if existing.macros.is_none() && def.macros.is_some() { | 186 | if def.is_none() { |
154 | existing.macros = def.macros; | 187 | if self.unresolved.insert(name) { |
155 | changed = true; | 188 | changed = true; |
189 | } | ||
156 | } | 190 | } |
157 | 191 | ||
158 | changed | 192 | changed |
@@ -166,17 +200,17 @@ impl ItemScope { | |||
166 | def_import_type: ImportType, | 200 | def_import_type: ImportType, |
167 | ) -> bool { | 201 | ) -> bool { |
168 | let mut changed = false; | 202 | let mut changed = false; |
169 | let existing = self.visible.entry(lookup.1.clone()).or_default(); | ||
170 | 203 | ||
171 | macro_rules! check_changed { | 204 | macro_rules! check_changed { |
172 | ( | 205 | ( |
173 | $changed:ident, | 206 | $changed:ident, |
174 | ( $existing:ident / $def:ident ) . $field:ident, | 207 | ( $this:ident / $def:ident ) . $field:ident, |
175 | $glob_imports:ident [ $lookup:ident ], | 208 | $glob_imports:ident [ $lookup:ident ], |
176 | $def_import_type:ident | 209 | $def_import_type:ident |
177 | ) => { | 210 | ) => {{ |
178 | match ($existing.$field, $def.$field) { | 211 | let existing = $this.$field.entry($lookup.1.clone()); |
179 | (None, Some(_)) => { | 212 | match (existing, $def.$field) { |
213 | (Entry::Vacant(entry), Some(_)) => { | ||
180 | match $def_import_type { | 214 | match $def_import_type { |
181 | ImportType::Glob => { | 215 | ImportType::Glob => { |
182 | $glob_imports.$field.insert($lookup.clone()); | 216 | $glob_imports.$field.insert($lookup.clone()); |
@@ -186,32 +220,46 @@ impl ItemScope { | |||
186 | } | 220 | } |
187 | } | 221 | } |
188 | 222 | ||
189 | $existing.$field = $def.$field; | 223 | if let Some(fld) = $def.$field { |
224 | entry.insert(fld); | ||
225 | } | ||
190 | $changed = true; | 226 | $changed = true; |
191 | } | 227 | } |
192 | (Some(_), Some(_)) | 228 | (Entry::Occupied(mut entry), Some(_)) |
193 | if $glob_imports.$field.contains(&$lookup) | 229 | if $glob_imports.$field.contains(&$lookup) |
194 | && matches!($def_import_type, ImportType::Named) => | 230 | && matches!($def_import_type, ImportType::Named) => |
195 | { | 231 | { |
196 | mark::hit!(import_shadowed); | 232 | mark::hit!(import_shadowed); |
197 | $glob_imports.$field.remove(&$lookup); | 233 | $glob_imports.$field.remove(&$lookup); |
198 | $existing.$field = $def.$field; | 234 | if let Some(fld) = $def.$field { |
235 | entry.insert(fld); | ||
236 | } | ||
199 | $changed = true; | 237 | $changed = true; |
200 | } | 238 | } |
201 | _ => {} | 239 | _ => {} |
202 | } | 240 | } |
203 | }; | 241 | }}; |
204 | } | 242 | } |
205 | 243 | ||
206 | check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type); | 244 | check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type); |
207 | check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type); | 245 | check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type); |
208 | check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type); | 246 | check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type); |
247 | |||
248 | if def.is_none() { | ||
249 | if self.unresolved.insert(lookup.1) { | ||
250 | changed = true; | ||
251 | } | ||
252 | } | ||
209 | 253 | ||
210 | changed | 254 | changed |
211 | } | 255 | } |
212 | 256 | ||
213 | pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { | 257 | pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a { |
214 | self.visible.iter().map(|(name, res)| (name.clone(), *res)) | 258 | self.entries().map(|(name, res)| (Some(name.clone()), res)).chain( |
259 | self.unnamed_trait_imports | ||
260 | .iter() | ||
261 | .map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))), | ||
262 | ) | ||
215 | } | 263 | } |
216 | 264 | ||
217 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { | 265 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { |