diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-01 22:37:59 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-01 22:37:59 +0000 |
commit | 4447019f4b5f24728bb7b91b161755ddb373c74c (patch) | |
tree | c53ff3531cbbad182e821eb92fa9ad201d2bff0c /crates/ra_hir/src/resolve.rs | |
parent | 2b5c226e86892113bcab478cdf4c9adaf1e7b2f6 (diff) | |
parent | c5852f422ff45adaa21815c1a15e03b067a56a82 (diff) |
Merge #693
693: Name resolution refactoring r=matklad a=flodiebold
This is still very WIP, but it's becoming quite big and I want to make sure this isn't going in a completely bad direction :sweat_smile:. I'm not really happy with how the path resolution looks, and I'm not sure `PerNs<Resolution>` is the best return type -- there are 'this cannot happen in the (types/values) namespace' cases everywhere. I also want to unify the `resolver` and `nameres` namespaces once I'm done switching everything to `Resolver`. Also, `Resolver` only has a lifetime because it needs to have a reference to the `ItemMap` during import resolution :confused:
The differences in the completion snapshots are almost completely just ordering (except it completes `Self` as well now), so I changed it to sort the completions before snapshotting.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/resolve.rs')
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs new file mode 100644 index 000000000..6c87d0df7 --- /dev/null +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -0,0 +1,226 @@ | |||
1 | //! Name resolution. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use rustc_hash::FxHashMap; | ||
5 | |||
6 | use crate::{ | ||
7 | ModuleDef, Module, | ||
8 | db::HirDatabase, | ||
9 | name::{Name, KnownName}, | ||
10 | nameres::{PerNs, ItemMap}, | ||
11 | generics::GenericParams, | ||
12 | expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, | ||
13 | impl_block::ImplBlock, | ||
14 | path::Path, | ||
15 | }; | ||
16 | |||
17 | #[derive(Debug, Clone, Default)] | ||
18 | pub struct Resolver { | ||
19 | scopes: Vec<Scope>, | ||
20 | } | ||
21 | |||
22 | // TODO how to store these best | ||
23 | #[derive(Debug, Clone)] | ||
24 | pub(crate) struct ModuleItemMap { | ||
25 | item_map: Arc<ItemMap>, | ||
26 | module: Module, | ||
27 | } | ||
28 | |||
29 | #[derive(Debug, Clone)] | ||
30 | pub(crate) struct ExprScope { | ||
31 | expr_scopes: Arc<ExprScopes>, | ||
32 | scope_id: ScopeId, | ||
33 | } | ||
34 | |||
35 | #[derive(Debug, Clone)] | ||
36 | pub(crate) enum Scope { | ||
37 | /// All the items and imported names of a module | ||
38 | ModuleScope(ModuleItemMap), | ||
39 | /// Brings the generic parameters of an item into scope | ||
40 | GenericParams(Arc<GenericParams>), | ||
41 | /// Brings `Self` into scope | ||
42 | ImplBlockScope(ImplBlock), | ||
43 | /// Local bindings | ||
44 | ExprScope(ExprScope), | ||
45 | } | ||
46 | |||
47 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
48 | pub enum Resolution { | ||
49 | /// An item | ||
50 | Def(ModuleDef), | ||
51 | /// A local binding (only value namespace) | ||
52 | LocalBinding(PatId), | ||
53 | /// A generic parameter | ||
54 | GenericParam(u32), | ||
55 | SelfType(ImplBlock), | ||
56 | } | ||
57 | |||
58 | impl Resolver { | ||
59 | pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { | ||
60 | let mut resolution = PerNs::none(); | ||
61 | for scope in self.scopes.iter().rev() { | ||
62 | resolution = resolution.combine(scope.resolve_name(name)); | ||
63 | if resolution.is_both() { | ||
64 | return resolution; | ||
65 | } | ||
66 | } | ||
67 | resolution | ||
68 | } | ||
69 | |||
70 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { | ||
71 | if let Some(name) = path.as_ident() { | ||
72 | self.resolve_name(name) | ||
73 | } else if path.is_self() { | ||
74 | self.resolve_name(&Name::self_param()) | ||
75 | } else { | ||
76 | let (item_map, module) = match self.module() { | ||
77 | Some(m) => m, | ||
78 | _ => return PerNs::none(), | ||
79 | }; | ||
80 | let module_res = item_map.resolve_path(db, module, path); | ||
81 | module_res.map(|def| Resolution::Def(def)) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | pub fn all_names(&self) -> FxHashMap<Name, PerNs<Resolution>> { | ||
86 | let mut names = FxHashMap::default(); | ||
87 | for scope in self.scopes.iter().rev() { | ||
88 | scope.collect_names(&mut |name, res| { | ||
89 | let current: &mut PerNs<Resolution> = names.entry(name).or_default(); | ||
90 | if current.types.is_none() { | ||
91 | current.types = res.types; | ||
92 | } | ||
93 | if current.values.is_none() { | ||
94 | current.values = res.values; | ||
95 | } | ||
96 | }); | ||
97 | } | ||
98 | names | ||
99 | } | ||
100 | |||
101 | fn module(&self) -> Option<(&ItemMap, Module)> { | ||
102 | self.scopes.iter().rev().find_map(|scope| match scope { | ||
103 | Scope::ModuleScope(m) => Some((&*m.item_map, m.module.clone())), | ||
104 | |||
105 | _ => None, | ||
106 | }) | ||
107 | } | ||
108 | |||
109 | /// The body from which any `LocalBinding` resolutions in this resolver come. | ||
110 | pub fn body(&self) -> Option<Arc<Body>> { | ||
111 | self.scopes.iter().rev().find_map(|scope| match scope { | ||
112 | Scope::ExprScope(expr_scope) => Some(expr_scope.expr_scopes.body()), | ||
113 | _ => None, | ||
114 | }) | ||
115 | } | ||
116 | } | ||
117 | |||
118 | impl Resolver { | ||
119 | pub(crate) fn push_scope(mut self, scope: Scope) -> Resolver { | ||
120 | self.scopes.push(scope); | ||
121 | self | ||
122 | } | ||
123 | |||
124 | pub(crate) fn push_generic_params_scope(self, params: Arc<GenericParams>) -> Resolver { | ||
125 | self.push_scope(Scope::GenericParams(params)) | ||
126 | } | ||
127 | |||
128 | pub(crate) fn push_impl_block_scope(self, impl_block: ImplBlock) -> Resolver { | ||
129 | self.push_scope(Scope::ImplBlockScope(impl_block)) | ||
130 | } | ||
131 | |||
132 | pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module: Module) -> Resolver { | ||
133 | self.push_scope(Scope::ModuleScope(ModuleItemMap { item_map, module })) | ||
134 | } | ||
135 | |||
136 | pub(crate) fn push_expr_scope( | ||
137 | self, | ||
138 | expr_scopes: Arc<ExprScopes>, | ||
139 | scope_id: ScopeId, | ||
140 | ) -> Resolver { | ||
141 | self.push_scope(Scope::ExprScope(ExprScope { | ||
142 | expr_scopes, | ||
143 | scope_id, | ||
144 | })) | ||
145 | } | ||
146 | } | ||
147 | |||
148 | impl Scope { | ||
149 | fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { | ||
150 | match self { | ||
151 | Scope::ModuleScope(m) => { | ||
152 | if let Some(KnownName::SelfParam) = name.as_known_name() { | ||
153 | PerNs::types(Resolution::Def(m.module.into())) | ||
154 | } else { | ||
155 | match m.item_map[m.module.module_id].get(name) { | ||
156 | Some(res) => res.def.map(Resolution::Def), | ||
157 | None => PerNs::none(), | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | Scope::GenericParams(gp) => match gp.find_by_name(name) { | ||
162 | Some(gp) => PerNs::types(Resolution::GenericParam(gp.idx)), | ||
163 | None => PerNs::none(), | ||
164 | }, | ||
165 | Scope::ImplBlockScope(i) => { | ||
166 | if name.as_known_name() == Some(KnownName::SelfType) { | ||
167 | PerNs::types(Resolution::SelfType(i.clone())) | ||
168 | } else { | ||
169 | PerNs::none() | ||
170 | } | ||
171 | } | ||
172 | Scope::ExprScope(e) => { | ||
173 | let entry = e | ||
174 | .expr_scopes | ||
175 | .entries(e.scope_id) | ||
176 | .iter() | ||
177 | .find(|entry| entry.name() == name); | ||
178 | match entry { | ||
179 | Some(e) => PerNs::values(Resolution::LocalBinding(e.pat())), | ||
180 | None => PerNs::none(), | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | fn collect_names(&self, f: &mut FnMut(Name, PerNs<Resolution>)) { | ||
187 | match self { | ||
188 | Scope::ModuleScope(m) => { | ||
189 | // TODO: should we provide `self` here? | ||
190 | // f( | ||
191 | // Name::self_param(), | ||
192 | // PerNs::types(Resolution::Def { | ||
193 | // def: m.module.into(), | ||
194 | // }), | ||
195 | // ); | ||
196 | m.item_map[m.module.module_id] | ||
197 | .entries() | ||
198 | .for_each(|(name, res)| { | ||
199 | f(name.clone(), res.def.map(Resolution::Def)); | ||
200 | }) | ||
201 | } | ||
202 | Scope::GenericParams(gp) => { | ||
203 | for param in &gp.params { | ||
204 | f( | ||
205 | param.name.clone(), | ||
206 | PerNs::types(Resolution::GenericParam(param.idx)), | ||
207 | ) | ||
208 | } | ||
209 | } | ||
210 | Scope::ImplBlockScope(i) => { | ||
211 | f( | ||
212 | Name::self_type(), | ||
213 | PerNs::types(Resolution::SelfType(i.clone())), | ||
214 | ); | ||
215 | } | ||
216 | Scope::ExprScope(e) => { | ||
217 | e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { | ||
218 | f( | ||
219 | e.name().clone(), | ||
220 | PerNs::values(Resolution::LocalBinding(e.pat())), | ||
221 | ); | ||
222 | }); | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | } | ||