diff options
author | Aleksey Kladov <[email protected]> | 2019-03-16 14:17:50 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-03-17 09:53:22 +0000 |
commit | 967a4b64af2f09e11108d28f11565fa0f3e583a5 (patch) | |
tree | 985072c007ce020de3c5205f0f976d872e44c41a /crates/ra_hir | |
parent | d4449945a069d26035afe9d8627414f6dfc8bf0a (diff) |
Reorganize name resolution
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_impl/module.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 462 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs (renamed from crates/ra_hir/src/nameres/crate_def_map/collector.rs) | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/crate_def_map.rs | 368 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/lower.rs | 40 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/per_ns.rs | 78 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs (renamed from crates/ra_hir/src/nameres/crate_def_map/raw.rs) | 41 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs (renamed from crates/ra_hir/src/nameres/crate_def_map/tests.rs) | 0 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/globs.rs (renamed from crates/ra_hir/src/nameres/crate_def_map/tests/globs.rs) | 0 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/incremental.rs (renamed from crates/ra_hir/src/nameres/crate_def_map/tests/incremental.rs) | 0 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs (renamed from crates/ra_hir/src/nameres/crate_def_map/tests/macros.rs) | 0 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 2 |
14 files changed, 481 insertions, 522 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index c918ec9f6..c3124480b 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -8,8 +8,7 @@ use crate::{ | |||
8 | Name, ScopesWithSourceMap, Ty, HirFileId, | 8 | Name, ScopesWithSourceMap, Ty, HirFileId, |
9 | HirDatabase, PersistentHirDatabase, | 9 | HirDatabase, PersistentHirDatabase, |
10 | type_ref::TypeRef, | 10 | type_ref::TypeRef, |
11 | nameres::{ModuleScope, Namespace, lower::ImportId}, | 11 | nameres::{ModuleScope, Namespace, ImportId, ModuleId}, |
12 | nameres::crate_def_map::ModuleId, | ||
13 | expr::{Body, BodySourceMap}, | 12 | expr::{Body, BodySourceMap}, |
14 | ty::InferenceResult, | 13 | ty::InferenceResult, |
15 | adt::{EnumVariantId, StructFieldId, VariantDef}, | 14 | adt::{EnumVariantId, StructFieldId, VariantDef}, |
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index aa4e62518..9f4448475 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs | |||
@@ -3,8 +3,7 @@ use ra_syntax::{ast, SyntaxNode, TreeArc, AstNode}; | |||
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | Module, ModuleSource, Problem, Name, | 5 | Module, ModuleSource, Problem, Name, |
6 | nameres::crate_def_map::ModuleId, | 6 | nameres::{ModuleId, ImportId}, |
7 | nameres::lower::ImportId, | ||
8 | HirDatabase, PersistentHirDatabase, | 7 | HirDatabase, PersistentHirDatabase, |
9 | HirFileId, SourceItemId, | 8 | HirFileId, SourceItemId, |
10 | }; | 9 | }; |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index b8c0a68a6..d2cc19b0f 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -10,7 +10,7 @@ use crate::{ | |||
10 | Struct, Enum, StructField, | 10 | Struct, Enum, StructField, |
11 | Const, ConstSignature, Static, | 11 | Const, ConstSignature, Static, |
12 | macros::MacroExpansion, | 12 | macros::MacroExpansion, |
13 | nameres::{Namespace, lower::{ImportSourceMap}, crate_def_map::{RawItems, CrateDefMap}}, | 13 | nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, |
14 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, | 14 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, |
15 | adt::{StructData, EnumData}, | 15 | adt::{StructData, EnumData}, |
16 | impl_block::{ModuleImplBlocks, ImplSourceMap}, | 16 | impl_block::{ModuleImplBlocks, ImplSourceMap}, |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 2248842de..30e959c04 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -1,35 +1,128 @@ | |||
1 | //! Name resolution algorithm. The end result of the algorithm is an `ItemMap`: | 1 | /// This module implements import-resolution/macro expansion algorithm. |
2 | //! a map which maps each module to its scope: the set of items visible in the | 2 | /// |
3 | //! module. That is, we only resolve imports here, name resolution of item | 3 | /// The result of this module is `CrateDefMap`: a datastructure which contains: |
4 | //! bodies will be done in a separate step. | 4 | /// |
5 | //! | 5 | /// * a tree of modules for the crate |
6 | //! Like Rustc, we use an interactive per-crate algorithm: we start with scopes | 6 | /// * for each module, a set of items visible in the module (directly declared |
7 | //! containing only directly defined items, and then iteratively resolve | 7 | /// or imported) |
8 | //! imports. | 8 | /// |
9 | //! | 9 | /// Note that `CrateDefMap` contains fully macro expanded code. |
10 | //! To make this work nicely in the IDE scenario, we place `InputModuleItems` | 10 | /// |
11 | //! in between raw syntax and name resolution. `InputModuleItems` are computed | 11 | /// Computing `CrateDefMap` can be partitioned into several logically |
12 | //! using only the module's syntax, and it is all directly defined items plus | 12 | /// independent "phases". The phases are mutually recursive though, there's no |
13 | //! imports. The plan is to make `InputModuleItems` independent of local | 13 | /// stric ordering. |
14 | //! modifications (that is, typing inside a function should not change IMIs), | 14 | /// |
15 | //! so that the results of name resolution can be preserved unless the module | 15 | /// ## Collecting RawItems |
16 | //! structure itself is modified. | 16 | /// |
17 | pub(crate) mod lower; | 17 | /// This happens in the `raw` module, which parses a single source file into a |
18 | pub(crate) mod crate_def_map; | 18 | /// set of top-level items. Nested importa are desugared to flat imports in |
19 | /// this phase. Macro calls are represented as a triple of (Path, Option<Name>, | ||
20 | /// TokenTree). | ||
21 | /// | ||
22 | /// ## Collecting Modules | ||
23 | /// | ||
24 | /// This happens in the `collector` module. In this phase, we recursively walk | ||
25 | /// tree of modules, collect raw items from submodules, populate module scopes | ||
26 | /// with defined items (so, we assign item ids in this phase) and record the set | ||
27 | /// of unresovled imports and macros. | ||
28 | /// | ||
29 | /// While we walk tree of modules, we also record macro_rules defenitions and | ||
30 | /// expand calls to macro_rules defined macros. | ||
31 | /// | ||
32 | /// ## Resolving Imports | ||
33 | /// | ||
34 | /// TBD | ||
35 | /// | ||
36 | /// ## Resolving Macros | ||
37 | /// | ||
38 | /// While macro_rules from the same crate use a global mutable namespace, macros | ||
39 | /// from other crates (including proc-macros) can be used with `foo::bar!` | ||
40 | /// syntax. | ||
41 | /// | ||
42 | /// TBD; | ||
43 | |||
44 | mod per_ns; | ||
45 | mod raw; | ||
46 | mod collector; | ||
47 | #[cfg(test)] | ||
48 | mod tests; | ||
49 | |||
50 | use std::sync::Arc; | ||
19 | 51 | ||
20 | use rustc_hash::FxHashMap; | 52 | use rustc_hash::FxHashMap; |
21 | use ra_db::Edition; | 53 | use ra_arena::{Arena, RawId, impl_arena_id}; |
54 | use ra_db::{FileId, Edition}; | ||
55 | use test_utils::tested_by; | ||
22 | 56 | ||
23 | use crate::{ | 57 | use crate::{ |
24 | ModuleDef, Name, | 58 | ModuleDef, Name, Crate, Module, Problem, |
25 | nameres::lower::ImportId, | 59 | PersistentHirDatabase, Path, PathKind, HirFileId, |
60 | ids::{SourceItemId, SourceFileItemId}, | ||
26 | }; | 61 | }; |
27 | 62 | ||
28 | pub(crate) use self::crate_def_map::{CrateDefMap, ModuleId}; | 63 | pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; |
64 | |||
65 | pub use self::per_ns::{PerNs, Namespace}; | ||
66 | |||
67 | /// Contans all top-level defs from a macro-expanded crate | ||
68 | #[derive(Debug, PartialEq, Eq)] | ||
69 | pub struct CrateDefMap { | ||
70 | krate: Crate, | ||
71 | edition: Edition, | ||
72 | /// The prelude module for this crate. This either comes from an import | ||
73 | /// marked with the `prelude_import` attribute, or (in the normal case) from | ||
74 | /// a dependency (`std` or `core`). | ||
75 | prelude: Option<Module>, | ||
76 | extern_prelude: FxHashMap<Name, ModuleDef>, | ||
77 | root: ModuleId, | ||
78 | modules: Arena<ModuleId, ModuleData>, | ||
79 | public_macros: FxHashMap<Name, mbe::MacroRules>, | ||
80 | problems: CrateDefMapProblems, | ||
81 | } | ||
82 | |||
83 | impl std::ops::Index<ModuleId> for CrateDefMap { | ||
84 | type Output = ModuleData; | ||
85 | fn index(&self, id: ModuleId) -> &ModuleData { | ||
86 | &self.modules[id] | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /// An ID of a module, **local** to a specific crate | ||
91 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
92 | pub(crate) struct ModuleId(RawId); | ||
93 | impl_arena_id!(ModuleId); | ||
94 | |||
95 | #[derive(Default, Debug, PartialEq, Eq)] | ||
96 | pub(crate) struct ModuleData { | ||
97 | pub(crate) parent: Option<ModuleId>, | ||
98 | pub(crate) children: FxHashMap<Name, ModuleId>, | ||
99 | pub(crate) scope: ModuleScope, | ||
100 | /// None for root | ||
101 | pub(crate) declaration: Option<SourceItemId>, | ||
102 | /// None for inline modules. | ||
103 | /// | ||
104 | /// Note that non-inline modules, by definition, live inside non-macro file. | ||
105 | pub(crate) definition: Option<FileId>, | ||
106 | } | ||
107 | |||
108 | #[derive(Default, Debug, PartialEq, Eq)] | ||
109 | pub(crate) struct CrateDefMapProblems { | ||
110 | problems: Vec<(SourceItemId, Problem)>, | ||
111 | } | ||
112 | |||
113 | impl CrateDefMapProblems { | ||
114 | fn add(&mut self, source_item_id: SourceItemId, problem: Problem) { | ||
115 | self.problems.push((source_item_id, problem)) | ||
116 | } | ||
117 | |||
118 | pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a { | ||
119 | self.problems.iter().map(|(s, p)| (s, p)) | ||
120 | } | ||
121 | } | ||
29 | 122 | ||
30 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 123 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
31 | pub struct ModuleScope { | 124 | pub struct ModuleScope { |
32 | pub(crate) items: FxHashMap<Name, Resolution>, | 125 | items: FxHashMap<Name, Resolution>, |
33 | } | 126 | } |
34 | 127 | ||
35 | impl ModuleScope { | 128 | impl ModuleScope { |
@@ -41,8 +134,6 @@ impl ModuleScope { | |||
41 | } | 134 | } |
42 | } | 135 | } |
43 | 136 | ||
44 | /// `Resolution` is basically `DefId` atm, but it should account for stuff like | ||
45 | /// multiple namespaces, ambiguity and errors. | ||
46 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | 137 | #[derive(Debug, Clone, PartialEq, Eq, Default)] |
47 | pub struct Resolution { | 138 | pub struct Resolution { |
48 | /// None for unresolved | 139 | /// None for unresolved |
@@ -51,114 +142,285 @@ pub struct Resolution { | |||
51 | pub import: Option<ImportId>, | 142 | pub import: Option<ImportId>, |
52 | } | 143 | } |
53 | 144 | ||
54 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | 145 | #[derive(Debug, Clone)] |
55 | pub enum Namespace { | 146 | struct ResolvePathResult { |
56 | Types, | 147 | resolved_def: PerNs<ModuleDef>, |
57 | Values, | 148 | segment_index: Option<usize>, |
149 | reached_fixedpoint: ReachedFixedPoint, | ||
58 | } | 150 | } |
59 | 151 | ||
60 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 152 | impl ResolvePathResult { |
61 | pub struct PerNs<T> { | 153 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { |
62 | pub types: Option<T>, | 154 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) |
63 | pub values: Option<T>, | 155 | } |
64 | } | ||
65 | 156 | ||
66 | impl<T> Default for PerNs<T> { | 157 | fn with( |
67 | fn default() -> Self { | 158 | resolved_def: PerNs<ModuleDef>, |
68 | PerNs { types: None, values: None } | 159 | reached_fixedpoint: ReachedFixedPoint, |
160 | segment_index: Option<usize>, | ||
161 | ) -> ResolvePathResult { | ||
162 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } | ||
69 | } | 163 | } |
70 | } | 164 | } |
71 | 165 | ||
72 | impl<T> PerNs<T> { | 166 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
73 | pub fn none() -> PerNs<T> { | 167 | enum ResolveMode { |
74 | PerNs { types: None, values: None } | 168 | Import, |
75 | } | 169 | Other, |
170 | } | ||
76 | 171 | ||
77 | pub fn values(t: T) -> PerNs<T> { | 172 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
78 | PerNs { types: None, values: Some(t) } | 173 | enum ReachedFixedPoint { |
79 | } | 174 | Yes, |
175 | No, | ||
176 | } | ||
80 | 177 | ||
81 | pub fn types(t: T) -> PerNs<T> { | 178 | impl CrateDefMap { |
82 | PerNs { types: Some(t), values: None } | 179 | pub(crate) fn crate_def_map_query( |
180 | db: &impl PersistentHirDatabase, | ||
181 | krate: Crate, | ||
182 | ) -> Arc<CrateDefMap> { | ||
183 | let def_map = { | ||
184 | let edition = krate.edition(db); | ||
185 | let mut modules: Arena<ModuleId, ModuleData> = Arena::default(); | ||
186 | let root = modules.alloc(ModuleData::default()); | ||
187 | CrateDefMap { | ||
188 | krate, | ||
189 | edition, | ||
190 | extern_prelude: FxHashMap::default(), | ||
191 | prelude: None, | ||
192 | root, | ||
193 | modules, | ||
194 | public_macros: FxHashMap::default(), | ||
195 | problems: CrateDefMapProblems::default(), | ||
196 | } | ||
197 | }; | ||
198 | let def_map = collector::collect_defs(db, def_map); | ||
199 | Arc::new(def_map) | ||
83 | } | 200 | } |
84 | 201 | ||
85 | pub fn both(types: T, values: T) -> PerNs<T> { | 202 | pub(crate) fn root(&self) -> ModuleId { |
86 | PerNs { types: Some(types), values: Some(values) } | 203 | self.root |
87 | } | 204 | } |
88 | 205 | ||
89 | pub fn is_none(&self) -> bool { | 206 | pub(crate) fn problems(&self) -> &CrateDefMapProblems { |
90 | self.types.is_none() && self.values.is_none() | 207 | &self.problems |
91 | } | 208 | } |
92 | 209 | ||
93 | pub fn is_both(&self) -> bool { | 210 | pub(crate) fn mk_module(&self, module_id: ModuleId) -> Module { |
94 | self.types.is_some() && self.values.is_some() | 211 | Module { krate: self.krate, module_id } |
95 | } | 212 | } |
96 | 213 | ||
97 | pub fn take(self, namespace: Namespace) -> Option<T> { | 214 | pub(crate) fn prelude(&self) -> Option<Module> { |
98 | match namespace { | 215 | self.prelude |
99 | Namespace::Types => self.types, | ||
100 | Namespace::Values => self.values, | ||
101 | } | ||
102 | } | 216 | } |
103 | 217 | ||
104 | pub fn take_types(self) -> Option<T> { | 218 | pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> { |
105 | self.take(Namespace::Types) | 219 | &self.extern_prelude |
106 | } | 220 | } |
107 | 221 | ||
108 | pub fn take_values(self) -> Option<T> { | 222 | pub(crate) fn find_module_by_source( |
109 | self.take(Namespace::Values) | 223 | &self, |
224 | file_id: HirFileId, | ||
225 | decl_id: Option<SourceFileItemId>, | ||
226 | ) -> Option<ModuleId> { | ||
227 | let decl_id = decl_id.map(|it| it.with_file_id(file_id)); | ||
228 | let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { | ||
229 | if decl_id.is_some() { | ||
230 | module_data.declaration == decl_id | ||
231 | } else { | ||
232 | module_data.definition.map(|it| it.into()) == Some(file_id) | ||
233 | } | ||
234 | })?; | ||
235 | Some(module_id) | ||
110 | } | 236 | } |
111 | 237 | ||
112 | pub fn get(&self, namespace: Namespace) -> Option<&T> { | 238 | pub(crate) fn resolve_path( |
113 | self.as_ref().take(namespace) | 239 | &self, |
240 | db: &impl PersistentHirDatabase, | ||
241 | original_module: ModuleId, | ||
242 | path: &Path, | ||
243 | ) -> (PerNs<ModuleDef>, Option<usize>) { | ||
244 | let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path); | ||
245 | (res.resolved_def, res.segment_index) | ||
114 | } | 246 | } |
115 | 247 | ||
116 | pub fn as_ref(&self) -> PerNs<&T> { | 248 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change |
117 | PerNs { types: self.types.as_ref(), values: self.values.as_ref() } | 249 | // the result. |
118 | } | 250 | fn resolve_path_fp( |
251 | &self, | ||
252 | db: &impl PersistentHirDatabase, | ||
253 | mode: ResolveMode, | ||
254 | original_module: ModuleId, | ||
255 | path: &Path, | ||
256 | ) -> ResolvePathResult { | ||
257 | let mut segments = path.segments.iter().enumerate(); | ||
258 | let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { | ||
259 | PathKind::Crate => { | ||
260 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) | ||
261 | } | ||
262 | PathKind::Self_ => { | ||
263 | PerNs::types(Module { krate: self.krate, module_id: original_module }.into()) | ||
264 | } | ||
265 | // plain import or absolute path in 2015: crate-relative with | ||
266 | // fallback to extern prelude (with the simplification in | ||
267 | // rust-lang/rust#57745) | ||
268 | // TODO there must be a nicer way to write this condition | ||
269 | PathKind::Plain | PathKind::Abs | ||
270 | if self.edition == Edition::Edition2015 | ||
271 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | ||
272 | { | ||
273 | let segment = match segments.next() { | ||
274 | Some((_, segment)) => segment, | ||
275 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
276 | }; | ||
277 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | ||
278 | self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) | ||
279 | } | ||
280 | PathKind::Plain => { | ||
281 | let segment = match segments.next() { | ||
282 | Some((_, segment)) => segment, | ||
283 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
284 | }; | ||
285 | log::debug!("resolving {:?} in module", segment); | ||
286 | self.resolve_name_in_module(db, original_module, &segment.name) | ||
287 | } | ||
288 | PathKind::Super => { | ||
289 | if let Some(p) = self.modules[original_module].parent { | ||
290 | PerNs::types(Module { krate: self.krate, module_id: p }.into()) | ||
291 | } else { | ||
292 | log::debug!("super path in root module"); | ||
293 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
294 | } | ||
295 | } | ||
296 | PathKind::Abs => { | ||
297 | // 2018-style absolute path -- only extern prelude | ||
298 | let segment = match segments.next() { | ||
299 | Some((_, segment)) => segment, | ||
300 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
301 | }; | ||
302 | if let Some(def) = self.extern_prelude.get(&segment.name) { | ||
303 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | ||
304 | PerNs::types(*def) | ||
305 | } else { | ||
306 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | ||
307 | } | ||
308 | } | ||
309 | }; | ||
119 | 310 | ||
120 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { | 311 | for (i, segment) in segments { |
121 | PerNs { types: self.types.or(other.types), values: self.values.or(other.values) } | 312 | let curr = match curr_per_ns.as_ref().take_types() { |
122 | } | 313 | Some(r) => r, |
314 | None => { | ||
315 | // we still have path segments left, but the path so far | ||
316 | // didn't resolve in the types namespace => no resolution | ||
317 | // (don't break here because `curr_per_ns` might contain | ||
318 | // something in the value namespace, and it would be wrong | ||
319 | // to return that) | ||
320 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
321 | } | ||
322 | }; | ||
323 | // resolve segment in curr | ||
123 | 324 | ||
124 | pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { | 325 | curr_per_ns = match curr { |
125 | PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) } | 326 | ModuleDef::Module(module) => { |
126 | } | 327 | if module.krate != self.krate { |
328 | let path = Path { | ||
329 | segments: path.segments[i..].iter().cloned().collect(), | ||
330 | kind: PathKind::Self_, | ||
331 | }; | ||
332 | log::debug!("resolving {:?} in other crate", path); | ||
333 | let defp_map = db.crate_def_map(module.krate); | ||
334 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); | ||
335 | return ResolvePathResult::with( | ||
336 | def, | ||
337 | ReachedFixedPoint::Yes, | ||
338 | s.map(|s| s + i), | ||
339 | ); | ||
340 | } | ||
127 | 341 | ||
128 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { | 342 | match self[module.module_id].scope.items.get(&segment.name) { |
129 | PerNs { types: self.types.map(&f), values: self.values.map(&f) } | 343 | Some(res) if !res.def.is_none() => res.def, |
344 | _ => { | ||
345 | log::debug!("path segment {:?} not found", segment.name); | ||
346 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | ModuleDef::Enum(e) => { | ||
351 | // enum variant | ||
352 | tested_by!(can_import_enum_variant); | ||
353 | match e.variant(db, &segment.name) { | ||
354 | Some(variant) => PerNs::both(variant.into(), variant.into()), | ||
355 | None => { | ||
356 | return ResolvePathResult::with( | ||
357 | PerNs::types((*e).into()), | ||
358 | ReachedFixedPoint::Yes, | ||
359 | Some(i), | ||
360 | ); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | s => { | ||
365 | // could be an inherent method call in UFCS form | ||
366 | // (`Struct::method`), or some other kind of associated item | ||
367 | log::debug!( | ||
368 | "path segment {:?} resolved to non-module {:?}, but is not last", | ||
369 | segment.name, | ||
370 | curr, | ||
371 | ); | ||
372 | |||
373 | return ResolvePathResult::with( | ||
374 | PerNs::types((*s).into()), | ||
375 | ReachedFixedPoint::Yes, | ||
376 | Some(i), | ||
377 | ); | ||
378 | } | ||
379 | }; | ||
380 | } | ||
381 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | ||
130 | } | 382 | } |
131 | } | ||
132 | 383 | ||
133 | #[derive(Debug, Clone)] | 384 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { |
134 | struct ResolvePathResult { | 385 | let from_crate_root = |
135 | resolved_def: PerNs<ModuleDef>, | 386 | self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def); |
136 | segment_index: Option<usize>, | 387 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); |
137 | reached_fixedpoint: ReachedFixedPoint, | ||
138 | } | ||
139 | 388 | ||
140 | impl ResolvePathResult { | 389 | from_crate_root.or(from_extern_prelude) |
141 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | ||
142 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) | ||
143 | } | 390 | } |
144 | 391 | ||
145 | fn with( | 392 | pub(crate) fn resolve_name_in_module( |
146 | resolved_def: PerNs<ModuleDef>, | 393 | &self, |
147 | reached_fixedpoint: ReachedFixedPoint, | 394 | db: &impl PersistentHirDatabase, |
148 | segment_index: Option<usize>, | 395 | module: ModuleId, |
149 | ) -> ResolvePathResult { | 396 | name: &Name, |
150 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } | 397 | ) -> PerNs<ModuleDef> { |
398 | // Resolve in: | ||
399 | // - current module / scope | ||
400 | // - extern prelude | ||
401 | // - std prelude | ||
402 | let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def); | ||
403 | let from_extern_prelude = | ||
404 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | ||
405 | let from_prelude = self.resolve_in_prelude(db, name); | ||
406 | |||
407 | from_scope.or(from_extern_prelude).or(from_prelude) | ||
151 | } | 408 | } |
152 | } | ||
153 | 409 | ||
154 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 410 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { |
155 | enum ResolveMode { | 411 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) |
156 | Import, | 412 | } |
157 | Other, | ||
158 | } | ||
159 | 413 | ||
160 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 414 | fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> { |
161 | enum ReachedFixedPoint { | 415 | if let Some(prelude) = self.prelude { |
162 | Yes, | 416 | let resolution = if prelude.krate == self.krate { |
163 | No, | 417 | self[prelude.module_id].scope.items.get(name).cloned() |
418 | } else { | ||
419 | db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned() | ||
420 | }; | ||
421 | resolution.map(|r| r.def).unwrap_or_else(PerNs::none) | ||
422 | } else { | ||
423 | PerNs::none() | ||
424 | } | ||
425 | } | ||
164 | } | 426 | } |
diff --git a/crates/ra_hir/src/nameres/crate_def_map/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 0f500ce42..cbe850ba4 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -8,11 +8,11 @@ use crate::{ | |||
8 | Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, | 8 | Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, |
9 | PersistentHirDatabase, HirFileId, Name, Path, Problem, | 9 | PersistentHirDatabase, HirFileId, Name, Path, Problem, |
10 | KnownName, | 10 | KnownName, |
11 | nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode}, | 11 | nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw}, |
12 | ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, | 12 | ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | use super::{CrateDefMap, ModuleId, ModuleData, raw}; | 15 | use super::{CrateDefMap, ModuleId, ModuleData}; |
16 | 16 | ||
17 | pub(super) fn collect_defs( | 17 | pub(super) fn collect_defs( |
18 | db: &impl PersistentHirDatabase, | 18 | db: &impl PersistentHirDatabase, |
diff --git a/crates/ra_hir/src/nameres/crate_def_map.rs b/crates/ra_hir/src/nameres/crate_def_map.rs deleted file mode 100644 index cc4955053..000000000 --- a/crates/ra_hir/src/nameres/crate_def_map.rs +++ /dev/null | |||
@@ -1,368 +0,0 @@ | |||
1 | /// This module implements new import-resolution/macro expansion algorithm. | ||
2 | /// | ||
3 | /// The result of this module is `CrateDefMap`: a datastructure which contains: | ||
4 | /// | ||
5 | /// * a tree of modules for the crate | ||
6 | /// * for each module, a set of items visible in the module (directly declared | ||
7 | /// or imported) | ||
8 | /// | ||
9 | /// Note that `CrateDefMap` contains fully macro expanded code. | ||
10 | /// | ||
11 | /// Computing `CrateDefMap` can be partitioned into several logically | ||
12 | /// independent "phases". The phases are mutually recursive though, there's no | ||
13 | /// stric ordering. | ||
14 | /// | ||
15 | /// ## Collecting RawItems | ||
16 | /// | ||
17 | /// This happens in the `raw` module, which parses a single source file into a | ||
18 | /// set of top-level items. Nested importa are desugared to flat imports in | ||
19 | /// this phase. Macro calls are represented as a triple of (Path, Option<Name>, | ||
20 | /// TokenTree). | ||
21 | /// | ||
22 | /// ## Collecting Modules | ||
23 | /// | ||
24 | /// This happens in the `collector` module. In this phase, we recursively walk | ||
25 | /// tree of modules, collect raw items from submodules, populate module scopes | ||
26 | /// with defined items (so, we assign item ids in this phase) and record the set | ||
27 | /// of unresovled imports and macros. | ||
28 | /// | ||
29 | /// While we walk tree of modules, we also record macro_rules defenitions and | ||
30 | /// expand calls to macro_rules defined macros. | ||
31 | /// | ||
32 | /// ## Resolving Imports | ||
33 | /// | ||
34 | /// TBD | ||
35 | /// | ||
36 | /// ## Resolving Macros | ||
37 | /// | ||
38 | /// While macro_rules from the same crate use a global mutable namespace, macros | ||
39 | /// from other crates (including proc-macros) can be used with `foo::bar!` | ||
40 | /// syntax. | ||
41 | /// | ||
42 | /// TBD; | ||
43 | |||
44 | mod raw; | ||
45 | mod collector; | ||
46 | #[cfg(test)] | ||
47 | mod tests; | ||
48 | |||
49 | use rustc_hash::FxHashMap; | ||
50 | use test_utils::tested_by; | ||
51 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
52 | use ra_db::FileId; | ||
53 | |||
54 | use std::sync::Arc; | ||
55 | |||
56 | use crate::{ | ||
57 | Name, Module, Path, PathKind, ModuleDef, Crate, Problem, HirFileId, | ||
58 | PersistentHirDatabase, | ||
59 | nameres::{ModuleScope, ResolveMode, ResolvePathResult, PerNs, Edition, ReachedFixedPoint}, | ||
60 | ids::{SourceItemId, SourceFileItemId}, | ||
61 | }; | ||
62 | |||
63 | pub(crate) use self::raw::RawItems; | ||
64 | |||
65 | #[derive(Default, Debug, PartialEq, Eq)] | ||
66 | pub(crate) struct ModuleData { | ||
67 | pub(crate) parent: Option<ModuleId>, | ||
68 | pub(crate) children: FxHashMap<Name, ModuleId>, | ||
69 | pub(crate) scope: ModuleScope, | ||
70 | /// None for root | ||
71 | pub(crate) declaration: Option<SourceItemId>, | ||
72 | /// None for inline modules. | ||
73 | /// | ||
74 | /// Note that non-inline modules, by definition, live inside non-macro file. | ||
75 | pub(crate) definition: Option<FileId>, | ||
76 | } | ||
77 | |||
78 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
79 | pub(crate) struct ModuleId(RawId); | ||
80 | impl_arena_id!(ModuleId); | ||
81 | |||
82 | /// Contans all top-level defs from a macro-expanded crate | ||
83 | #[derive(Debug, PartialEq, Eq)] | ||
84 | pub struct CrateDefMap { | ||
85 | krate: Crate, | ||
86 | edition: Edition, | ||
87 | /// The prelude module for this crate. This either comes from an import | ||
88 | /// marked with the `prelude_import` attribute, or (in the normal case) from | ||
89 | /// a dependency (`std` or `core`). | ||
90 | prelude: Option<Module>, | ||
91 | extern_prelude: FxHashMap<Name, ModuleDef>, | ||
92 | root: ModuleId, | ||
93 | modules: Arena<ModuleId, ModuleData>, | ||
94 | public_macros: FxHashMap<Name, mbe::MacroRules>, | ||
95 | problems: CrateDefMapProblems, | ||
96 | } | ||
97 | |||
98 | #[derive(Default, Debug, PartialEq, Eq)] | ||
99 | pub(crate) struct CrateDefMapProblems { | ||
100 | problems: Vec<(SourceItemId, Problem)>, | ||
101 | } | ||
102 | |||
103 | impl CrateDefMapProblems { | ||
104 | fn add(&mut self, source_item_id: SourceItemId, problem: Problem) { | ||
105 | self.problems.push((source_item_id, problem)) | ||
106 | } | ||
107 | |||
108 | pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a { | ||
109 | self.problems.iter().map(|(s, p)| (s, p)) | ||
110 | } | ||
111 | } | ||
112 | |||
113 | impl std::ops::Index<ModuleId> for CrateDefMap { | ||
114 | type Output = ModuleData; | ||
115 | fn index(&self, id: ModuleId) -> &ModuleData { | ||
116 | &self.modules[id] | ||
117 | } | ||
118 | } | ||
119 | |||
120 | impl CrateDefMap { | ||
121 | pub(crate) fn crate_def_map_query( | ||
122 | db: &impl PersistentHirDatabase, | ||
123 | krate: Crate, | ||
124 | ) -> Arc<CrateDefMap> { | ||
125 | let def_map = { | ||
126 | let edition = krate.edition(db); | ||
127 | let mut modules: Arena<ModuleId, ModuleData> = Arena::default(); | ||
128 | let root = modules.alloc(ModuleData::default()); | ||
129 | CrateDefMap { | ||
130 | krate, | ||
131 | edition, | ||
132 | extern_prelude: FxHashMap::default(), | ||
133 | prelude: None, | ||
134 | root, | ||
135 | modules, | ||
136 | public_macros: FxHashMap::default(), | ||
137 | problems: CrateDefMapProblems::default(), | ||
138 | } | ||
139 | }; | ||
140 | let def_map = collector::collect_defs(db, def_map); | ||
141 | Arc::new(def_map) | ||
142 | } | ||
143 | |||
144 | pub(crate) fn root(&self) -> ModuleId { | ||
145 | self.root | ||
146 | } | ||
147 | |||
148 | pub(crate) fn problems(&self) -> &CrateDefMapProblems { | ||
149 | &self.problems | ||
150 | } | ||
151 | |||
152 | pub(crate) fn mk_module(&self, module_id: ModuleId) -> Module { | ||
153 | Module { krate: self.krate, module_id } | ||
154 | } | ||
155 | |||
156 | pub(crate) fn prelude(&self) -> Option<Module> { | ||
157 | self.prelude | ||
158 | } | ||
159 | |||
160 | pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> { | ||
161 | &self.extern_prelude | ||
162 | } | ||
163 | |||
164 | pub(crate) fn find_module_by_source( | ||
165 | &self, | ||
166 | file_id: HirFileId, | ||
167 | decl_id: Option<SourceFileItemId>, | ||
168 | ) -> Option<ModuleId> { | ||
169 | let decl_id = decl_id.map(|it| it.with_file_id(file_id)); | ||
170 | let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { | ||
171 | if decl_id.is_some() { | ||
172 | module_data.declaration == decl_id | ||
173 | } else { | ||
174 | module_data.definition.map(|it| it.into()) == Some(file_id) | ||
175 | } | ||
176 | })?; | ||
177 | Some(module_id) | ||
178 | } | ||
179 | |||
180 | pub(crate) fn resolve_path( | ||
181 | &self, | ||
182 | db: &impl PersistentHirDatabase, | ||
183 | original_module: ModuleId, | ||
184 | path: &Path, | ||
185 | ) -> (PerNs<ModuleDef>, Option<usize>) { | ||
186 | let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path); | ||
187 | (res.resolved_def, res.segment_index) | ||
188 | } | ||
189 | |||
190 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | ||
191 | // the result. | ||
192 | fn resolve_path_fp( | ||
193 | &self, | ||
194 | db: &impl PersistentHirDatabase, | ||
195 | mode: ResolveMode, | ||
196 | original_module: ModuleId, | ||
197 | path: &Path, | ||
198 | ) -> ResolvePathResult { | ||
199 | let mut segments = path.segments.iter().enumerate(); | ||
200 | let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { | ||
201 | PathKind::Crate => { | ||
202 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) | ||
203 | } | ||
204 | PathKind::Self_ => { | ||
205 | PerNs::types(Module { krate: self.krate, module_id: original_module }.into()) | ||
206 | } | ||
207 | // plain import or absolute path in 2015: crate-relative with | ||
208 | // fallback to extern prelude (with the simplification in | ||
209 | // rust-lang/rust#57745) | ||
210 | // TODO there must be a nicer way to write this condition | ||
211 | PathKind::Plain | PathKind::Abs | ||
212 | if self.edition == Edition::Edition2015 | ||
213 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | ||
214 | { | ||
215 | let segment = match segments.next() { | ||
216 | Some((_, segment)) => segment, | ||
217 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
218 | }; | ||
219 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | ||
220 | self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) | ||
221 | } | ||
222 | PathKind::Plain => { | ||
223 | let segment = match segments.next() { | ||
224 | Some((_, segment)) => segment, | ||
225 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
226 | }; | ||
227 | log::debug!("resolving {:?} in module", segment); | ||
228 | self.resolve_name_in_module(db, original_module, &segment.name) | ||
229 | } | ||
230 | PathKind::Super => { | ||
231 | if let Some(p) = self.modules[original_module].parent { | ||
232 | PerNs::types(Module { krate: self.krate, module_id: p }.into()) | ||
233 | } else { | ||
234 | log::debug!("super path in root module"); | ||
235 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
236 | } | ||
237 | } | ||
238 | PathKind::Abs => { | ||
239 | // 2018-style absolute path -- only extern prelude | ||
240 | let segment = match segments.next() { | ||
241 | Some((_, segment)) => segment, | ||
242 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
243 | }; | ||
244 | if let Some(def) = self.extern_prelude.get(&segment.name) { | ||
245 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | ||
246 | PerNs::types(*def) | ||
247 | } else { | ||
248 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | ||
249 | } | ||
250 | } | ||
251 | }; | ||
252 | |||
253 | for (i, segment) in segments { | ||
254 | let curr = match curr_per_ns.as_ref().take_types() { | ||
255 | Some(r) => r, | ||
256 | None => { | ||
257 | // we still have path segments left, but the path so far | ||
258 | // didn't resolve in the types namespace => no resolution | ||
259 | // (don't break here because `curr_per_ns` might contain | ||
260 | // something in the value namespace, and it would be wrong | ||
261 | // to return that) | ||
262 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
263 | } | ||
264 | }; | ||
265 | // resolve segment in curr | ||
266 | |||
267 | curr_per_ns = match curr { | ||
268 | ModuleDef::Module(module) => { | ||
269 | if module.krate != self.krate { | ||
270 | let path = Path { | ||
271 | segments: path.segments[i..].iter().cloned().collect(), | ||
272 | kind: PathKind::Self_, | ||
273 | }; | ||
274 | log::debug!("resolving {:?} in other crate", path); | ||
275 | let defp_map = db.crate_def_map(module.krate); | ||
276 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); | ||
277 | return ResolvePathResult::with( | ||
278 | def, | ||
279 | ReachedFixedPoint::Yes, | ||
280 | s.map(|s| s + i), | ||
281 | ); | ||
282 | } | ||
283 | |||
284 | match self[module.module_id].scope.items.get(&segment.name) { | ||
285 | Some(res) if !res.def.is_none() => res.def, | ||
286 | _ => { | ||
287 | log::debug!("path segment {:?} not found", segment.name); | ||
288 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | ModuleDef::Enum(e) => { | ||
293 | // enum variant | ||
294 | tested_by!(can_import_enum_variant); | ||
295 | match e.variant(db, &segment.name) { | ||
296 | Some(variant) => PerNs::both(variant.into(), variant.into()), | ||
297 | None => { | ||
298 | return ResolvePathResult::with( | ||
299 | PerNs::types((*e).into()), | ||
300 | ReachedFixedPoint::Yes, | ||
301 | Some(i), | ||
302 | ); | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | s => { | ||
307 | // could be an inherent method call in UFCS form | ||
308 | // (`Struct::method`), or some other kind of associated item | ||
309 | log::debug!( | ||
310 | "path segment {:?} resolved to non-module {:?}, but is not last", | ||
311 | segment.name, | ||
312 | curr, | ||
313 | ); | ||
314 | |||
315 | return ResolvePathResult::with( | ||
316 | PerNs::types((*s).into()), | ||
317 | ReachedFixedPoint::Yes, | ||
318 | Some(i), | ||
319 | ); | ||
320 | } | ||
321 | }; | ||
322 | } | ||
323 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | ||
324 | } | ||
325 | |||
326 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { | ||
327 | let from_crate_root = | ||
328 | self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def); | ||
329 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | ||
330 | |||
331 | from_crate_root.or(from_extern_prelude) | ||
332 | } | ||
333 | |||
334 | pub(crate) fn resolve_name_in_module( | ||
335 | &self, | ||
336 | db: &impl PersistentHirDatabase, | ||
337 | module: ModuleId, | ||
338 | name: &Name, | ||
339 | ) -> PerNs<ModuleDef> { | ||
340 | // Resolve in: | ||
341 | // - current module / scope | ||
342 | // - extern prelude | ||
343 | // - std prelude | ||
344 | let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def); | ||
345 | let from_extern_prelude = | ||
346 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | ||
347 | let from_prelude = self.resolve_in_prelude(db, name); | ||
348 | |||
349 | from_scope.or(from_extern_prelude).or(from_prelude) | ||
350 | } | ||
351 | |||
352 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { | ||
353 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) | ||
354 | } | ||
355 | |||
356 | fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> { | ||
357 | if let Some(prelude) = self.prelude { | ||
358 | let resolution = if prelude.krate == self.krate { | ||
359 | self[prelude.module_id].scope.items.get(name).cloned() | ||
360 | } else { | ||
361 | db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned() | ||
362 | }; | ||
363 | resolution.map(|r| r.def).unwrap_or_else(PerNs::none) | ||
364 | } else { | ||
365 | PerNs::none() | ||
366 | } | ||
367 | } | ||
368 | } | ||
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs deleted file mode 100644 index d4c7f2481..000000000 --- a/crates/ra_hir/src/nameres/lower.rs +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | use ra_syntax::{ | ||
2 | AstNode, SourceFile, TreeArc, AstPtr, | ||
3 | ast, | ||
4 | }; | ||
5 | use ra_arena::{RawId, impl_arena_id, map::ArenaMap}; | ||
6 | |||
7 | use crate::{Path, ModuleSource, Name}; | ||
8 | |||
9 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
10 | pub struct ImportId(RawId); | ||
11 | impl_arena_id!(ImportId); | ||
12 | |||
13 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
14 | pub struct ImportData { | ||
15 | pub(super) path: Path, | ||
16 | pub(super) alias: Option<Name>, | ||
17 | pub(super) is_glob: bool, | ||
18 | pub(super) is_prelude: bool, | ||
19 | pub(super) is_extern_crate: bool, | ||
20 | } | ||
21 | |||
22 | #[derive(Debug, Default, PartialEq, Eq)] | ||
23 | pub struct ImportSourceMap { | ||
24 | map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>, | ||
25 | } | ||
26 | |||
27 | impl ImportSourceMap { | ||
28 | pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { | ||
29 | self.map.insert(import, AstPtr::new(segment)) | ||
30 | } | ||
31 | |||
32 | pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { | ||
33 | let file = match source { | ||
34 | ModuleSource::SourceFile(file) => &*file, | ||
35 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), | ||
36 | }; | ||
37 | |||
38 | self.map[import].to_node(file).to_owned() | ||
39 | } | ||
40 | } | ||
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs new file mode 100644 index 000000000..c40a3ff9d --- /dev/null +++ b/crates/ra_hir/src/nameres/per_ns.rs | |||
@@ -0,0 +1,78 @@ | |||
1 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
2 | pub enum Namespace { | ||
3 | Types, | ||
4 | Values, | ||
5 | } | ||
6 | |||
7 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
8 | pub struct PerNs<T> { | ||
9 | pub types: Option<T>, | ||
10 | pub values: Option<T>, | ||
11 | } | ||
12 | |||
13 | impl<T> Default for PerNs<T> { | ||
14 | fn default() -> Self { | ||
15 | PerNs { types: None, values: None } | ||
16 | } | ||
17 | } | ||
18 | |||
19 | impl<T> PerNs<T> { | ||
20 | pub fn none() -> PerNs<T> { | ||
21 | PerNs { types: None, values: None } | ||
22 | } | ||
23 | |||
24 | pub fn values(t: T) -> PerNs<T> { | ||
25 | PerNs { types: None, values: Some(t) } | ||
26 | } | ||
27 | |||
28 | pub fn types(t: T) -> PerNs<T> { | ||
29 | PerNs { types: Some(t), values: None } | ||
30 | } | ||
31 | |||
32 | pub fn both(types: T, values: T) -> PerNs<T> { | ||
33 | PerNs { types: Some(types), values: Some(values) } | ||
34 | } | ||
35 | |||
36 | pub fn is_none(&self) -> bool { | ||
37 | self.types.is_none() && self.values.is_none() | ||
38 | } | ||
39 | |||
40 | pub fn is_both(&self) -> bool { | ||
41 | self.types.is_some() && self.values.is_some() | ||
42 | } | ||
43 | |||
44 | pub fn take(self, namespace: Namespace) -> Option<T> { | ||
45 | match namespace { | ||
46 | Namespace::Types => self.types, | ||
47 | Namespace::Values => self.values, | ||
48 | } | ||
49 | } | ||
50 | |||
51 | pub fn take_types(self) -> Option<T> { | ||
52 | self.take(Namespace::Types) | ||
53 | } | ||
54 | |||
55 | pub fn take_values(self) -> Option<T> { | ||
56 | self.take(Namespace::Values) | ||
57 | } | ||
58 | |||
59 | pub fn get(&self, namespace: Namespace) -> Option<&T> { | ||
60 | self.as_ref().take(namespace) | ||
61 | } | ||
62 | |||
63 | pub fn as_ref(&self) -> PerNs<&T> { | ||
64 | PerNs { types: self.types.as_ref(), values: self.values.as_ref() } | ||
65 | } | ||
66 | |||
67 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { | ||
68 | PerNs { types: self.types.or(other.types), values: self.values.or(other.values) } | ||
69 | } | ||
70 | |||
71 | pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { | ||
72 | PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) } | ||
73 | } | ||
74 | |||
75 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { | ||
76 | PerNs { types: self.types.map(&f), values: self.values.map(&f) } | ||
77 | } | ||
78 | } | ||
diff --git a/crates/ra_hir/src/nameres/crate_def_map/raw.rs b/crates/ra_hir/src/nameres/raw.rs index dca86e394..3226bbf0d 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -5,16 +5,15 @@ use std::{ | |||
5 | 5 | ||
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | use ra_db::FileId; | 7 | use ra_db::FileId; |
8 | use ra_arena::{Arena, impl_arena_id, RawId}; | 8 | use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap}; |
9 | use ra_syntax::{ | 9 | use ra_syntax::{ |
10 | AstNode, SourceFile, | 10 | AstNode, SourceFile, AstPtr, TreeArc, |
11 | ast::{self, NameOwner, AttrsOwner}, | 11 | ast::{self, NameOwner, AttrsOwner}, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | PersistentHirDatabase, Name, AsName, Path, HirFileId, | 15 | PersistentHirDatabase, Name, AsName, Path, HirFileId, ModuleSource, |
16 | ids::{SourceFileItemId, SourceFileItems}, | 16 | ids::{SourceFileItemId, SourceFileItems}, |
17 | nameres::lower::ImportSourceMap, | ||
18 | }; | 17 | }; |
19 | 18 | ||
20 | #[derive(Debug, Default, PartialEq, Eq)] | 19 | #[derive(Debug, Default, PartialEq, Eq)] |
@@ -27,6 +26,26 @@ pub struct RawItems { | |||
27 | items: Vec<RawItem>, | 26 | items: Vec<RawItem>, |
28 | } | 27 | } |
29 | 28 | ||
29 | #[derive(Debug, Default, PartialEq, Eq)] | ||
30 | pub struct ImportSourceMap { | ||
31 | map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>, | ||
32 | } | ||
33 | |||
34 | impl ImportSourceMap { | ||
35 | pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { | ||
36 | self.map.insert(import, AstPtr::new(segment)) | ||
37 | } | ||
38 | |||
39 | pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { | ||
40 | let file = match source { | ||
41 | ModuleSource::SourceFile(file) => &*file, | ||
42 | ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), | ||
43 | }; | ||
44 | |||
45 | self.map[import].to_node(file).to_owned() | ||
46 | } | ||
47 | } | ||
48 | |||
30 | impl RawItems { | 49 | impl RawItems { |
31 | pub(crate) fn raw_items_query( | 50 | pub(crate) fn raw_items_query( |
32 | db: &impl PersistentHirDatabase, | 51 | db: &impl PersistentHirDatabase, |
@@ -113,8 +132,18 @@ pub(crate) enum ModuleData { | |||
113 | Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> }, | 132 | Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> }, |
114 | } | 133 | } |
115 | 134 | ||
116 | pub(crate) use crate::nameres::lower::ImportId; | 135 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
117 | pub(super) use crate::nameres::lower::ImportData; | 136 | pub struct ImportId(RawId); |
137 | impl_arena_id!(ImportId); | ||
138 | |||
139 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
140 | pub struct ImportData { | ||
141 | pub(crate) path: Path, | ||
142 | pub(crate) alias: Option<Name>, | ||
143 | pub(crate) is_glob: bool, | ||
144 | pub(crate) is_prelude: bool, | ||
145 | pub(crate) is_extern_crate: bool, | ||
146 | } | ||
118 | 147 | ||
119 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 148 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
120 | pub(crate) struct Def(RawId); | 149 | pub(crate) struct Def(RawId); |
diff --git a/crates/ra_hir/src/nameres/crate_def_map/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 36c1d74ce..36c1d74ce 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
diff --git a/crates/ra_hir/src/nameres/crate_def_map/tests/globs.rs b/crates/ra_hir/src/nameres/tests/globs.rs index 6e50c7ff6..6e50c7ff6 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/tests/globs.rs +++ b/crates/ra_hir/src/nameres/tests/globs.rs | |||
diff --git a/crates/ra_hir/src/nameres/crate_def_map/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs index 698781923..698781923 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/tests/incremental.rs +++ b/crates/ra_hir/src/nameres/tests/incremental.rs | |||
diff --git a/crates/ra_hir/src/nameres/crate_def_map/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index 8781b026b..8781b026b 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 7c77474b0..1adf9eef9 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -11,7 +11,7 @@ use crate::{ | |||
11 | ids::TraitId, | 11 | ids::TraitId, |
12 | impl_block::{ImplId, ImplBlock, ImplItem}, | 12 | impl_block::{ImplId, ImplBlock, ImplItem}, |
13 | ty::{AdtDef, Ty}, | 13 | ty::{AdtDef, Ty}, |
14 | nameres::crate_def_map::ModuleId, | 14 | nameres::ModuleId, |
15 | 15 | ||
16 | }; | 16 | }; |
17 | 17 | ||