aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/resolve.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-01 22:37:59 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-01 22:37:59 +0000
commit4447019f4b5f24728bb7b91b161755ddb373c74c (patch)
treec53ff3531cbbad182e821eb92fa9ad201d2bff0c /crates/ra_hir/src/resolve.rs
parent2b5c226e86892113bcab478cdf4c9adaf1e7b2f6 (diff)
parentc5852f422ff45adaa21815c1a15e03b067a56a82 (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.rs226
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.
2use std::sync::Arc;
3
4use rustc_hash::FxHashMap;
5
6use 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)]
18pub struct Resolver {
19 scopes: Vec<Scope>,
20}
21
22// TODO how to store these best
23#[derive(Debug, Clone)]
24pub(crate) struct ModuleItemMap {
25 item_map: Arc<ItemMap>,
26 module: Module,
27}
28
29#[derive(Debug, Clone)]
30pub(crate) struct ExprScope {
31 expr_scopes: Arc<ExprScopes>,
32 scope_id: ScopeId,
33}
34
35#[derive(Debug, Clone)]
36pub(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)]
48pub 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
58impl 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
118impl 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
148impl 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}