diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_impl/module.rs | 74 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 260 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 27 |
5 files changed, 176 insertions, 196 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 6739627b4..a469ad477 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -165,11 +165,11 @@ impl Module { | |||
165 | 165 | ||
166 | /// Returns a `ModuleScope`: a set of items, visible in this module. | 166 | /// Returns a `ModuleScope`: a set of items, visible in this module. |
167 | pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope { | 167 | pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope { |
168 | self.scope_impl(db) | 168 | db.item_map(self.krate)[self.module_id].clone() |
169 | } | 169 | } |
170 | 170 | ||
171 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<ModuleDef> { | 171 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<ModuleDef> { |
172 | self.resolve_path_impl(db, path) | 172 | db.item_map(self.krate).resolve_path(db, *self, path) |
173 | } | 173 | } |
174 | 174 | ||
175 | pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { | 175 | pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { |
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index 6419d3934..480ec27bf 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs | |||
@@ -2,10 +2,10 @@ use ra_db::FileId; | |||
2 | use ra_syntax::{ast, SyntaxNode, TreeArc}; | 2 | use ra_syntax::{ast, SyntaxNode, TreeArc}; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | Module, ModuleSource, Problem, ModuleDef, | 5 | Module, ModuleSource, Problem, |
6 | Crate, Name, Path, PathKind, PerNs, | 6 | Crate, Name, |
7 | module_tree::ModuleId, | 7 | module_tree::ModuleId, |
8 | nameres::{ModuleScope, lower::ImportId}, | 8 | nameres::{lower::ImportId}, |
9 | db::HirDatabase, | 9 | db::HirDatabase, |
10 | }; | 10 | }; |
11 | 11 | ||
@@ -90,74 +90,6 @@ impl Module { | |||
90 | Some(self.with_module_id(parent_id)) | 90 | Some(self.with_module_id(parent_id)) |
91 | } | 91 | } |
92 | 92 | ||
93 | /// Returns a `ModuleScope`: a set of items, visible in this module. | ||
94 | pub(crate) fn scope_impl(&self, db: &impl HirDatabase) -> ModuleScope { | ||
95 | let item_map = db.item_map(self.krate); | ||
96 | item_map.per_module[&self.module_id].clone() | ||
97 | } | ||
98 | |||
99 | pub(crate) fn resolve_path_impl(&self, db: &impl HirDatabase, path: &Path) -> PerNs<ModuleDef> { | ||
100 | let mut curr_per_ns: PerNs<ModuleDef> = PerNs::types(match path.kind { | ||
101 | PathKind::Crate => self.crate_root(db).into(), | ||
102 | PathKind::Self_ | PathKind::Plain => self.clone().into(), | ||
103 | PathKind::Super => { | ||
104 | if let Some(p) = self.parent(db) { | ||
105 | p.into() | ||
106 | } else { | ||
107 | return PerNs::none(); | ||
108 | } | ||
109 | } | ||
110 | PathKind::Abs => { | ||
111 | // TODO: absolute use is not supported | ||
112 | return PerNs::none(); | ||
113 | } | ||
114 | }); | ||
115 | |||
116 | for segment in path.segments.iter() { | ||
117 | let curr = match curr_per_ns.as_ref().take_types() { | ||
118 | Some(r) => r, | ||
119 | None => { | ||
120 | // we still have path segments left, but the path so far | ||
121 | // didn't resolve in the types namespace => no resolution | ||
122 | // (don't break here because curr_per_ns might contain | ||
123 | // something in the value namespace, and it would be wrong | ||
124 | // to return that) | ||
125 | return PerNs::none(); | ||
126 | } | ||
127 | }; | ||
128 | // resolve segment in curr | ||
129 | |||
130 | curr_per_ns = match curr { | ||
131 | ModuleDef::Module(m) => { | ||
132 | let scope = m.scope(db); | ||
133 | match scope.get(&segment.name) { | ||
134 | Some(r) => r.def_id.clone(), | ||
135 | None => PerNs::none(), | ||
136 | } | ||
137 | } | ||
138 | ModuleDef::Enum(e) => { | ||
139 | // enum variant | ||
140 | let matching_variant = e | ||
141 | .variants(db) | ||
142 | .into_iter() | ||
143 | .find(|(n, _variant)| n == &segment.name); | ||
144 | |||
145 | match matching_variant { | ||
146 | Some((_n, variant)) => PerNs::both(variant.into(), (*e).into()), | ||
147 | None => PerNs::none(), | ||
148 | } | ||
149 | } | ||
150 | _ => { | ||
151 | // could be an inherent method call in UFCS form | ||
152 | // (`Struct::method`), or some other kind of associated | ||
153 | // item... Which we currently don't handle (TODO) | ||
154 | PerNs::none() | ||
155 | } | ||
156 | }; | ||
157 | } | ||
158 | curr_per_ns | ||
159 | } | ||
160 | |||
161 | pub(crate) fn problems_impl( | 93 | pub(crate) fn problems_impl( |
162 | &self, | 94 | &self, |
163 | db: &impl HirDatabase, | 95 | db: &impl HirDatabase, |
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index f4d0c3e59..338ed0516 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use test_utils::mark; | 1 | test_utils::marks!( |
2 | 2 | name_res_works_for_broken_modules | |
3 | mark!(name_res_works_for_broken_modules); | 3 | item_map_enum_importing |
4 | ); | ||
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index a3bc98958..639726b5e 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -19,6 +19,8 @@ pub(crate) mod lower; | |||
19 | use std::sync::Arc; | 19 | use std::sync::Arc; |
20 | 20 | ||
21 | use ra_db::CrateId; | 21 | use ra_db::CrateId; |
22 | use ra_arena::map::ArenaMap; | ||
23 | use test_utils::tested_by; | ||
22 | use rustc_hash::{FxHashMap, FxHashSet}; | 24 | use rustc_hash::{FxHashMap, FxHashSet}; |
23 | 25 | ||
24 | use crate::{ | 26 | use crate::{ |
@@ -27,16 +29,21 @@ use crate::{ | |||
27 | HirDatabase, Crate, | 29 | HirDatabase, Crate, |
28 | Name, | 30 | Name, |
29 | module_tree::{ModuleId, ModuleTree}, | 31 | module_tree::{ModuleId, ModuleTree}, |
30 | //FIXME: deglobify | 32 | nameres::lower::{ImportId, LoweredModule, ImportData}, |
31 | nameres::lower::*, | ||
32 | }; | 33 | }; |
33 | 34 | ||
34 | /// `ItemMap` is the result of name resolution. It contains, for each | 35 | /// `ItemMap` is the result of name resolution. It contains, for each |
35 | /// module, the set of visible items. | 36 | /// module, the set of visible items. |
36 | // FIXME: currenty we compute item map per source-root. We should do it per crate instead. | ||
37 | #[derive(Default, Debug, PartialEq, Eq)] | 37 | #[derive(Default, Debug, PartialEq, Eq)] |
38 | pub struct ItemMap { | 38 | pub struct ItemMap { |
39 | pub per_module: FxHashMap<ModuleId, ModuleScope>, | 39 | per_module: ArenaMap<ModuleId, ModuleScope>, |
40 | } | ||
41 | |||
42 | impl std::ops::Index<ModuleId> for ItemMap { | ||
43 | type Output = ModuleScope; | ||
44 | fn index(&self, id: ModuleId) -> &ModuleScope { | ||
45 | &self.per_module[id] | ||
46 | } | ||
40 | } | 47 | } |
41 | 48 | ||
42 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 49 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
@@ -58,7 +65,7 @@ impl ModuleScope { | |||
58 | #[derive(Debug, Clone, PartialEq, Eq)] | 65 | #[derive(Debug, Clone, PartialEq, Eq)] |
59 | pub struct Resolution { | 66 | pub struct Resolution { |
60 | /// None for unresolved | 67 | /// None for unresolved |
61 | pub def_id: PerNs<ModuleDef>, | 68 | pub def: PerNs<ModuleDef>, |
62 | /// ident by which this is imported into local scope. | 69 | /// ident by which this is imported into local scope. |
63 | pub import: Option<ImportId>, | 70 | pub import: Option<ImportId>, |
64 | } | 71 | } |
@@ -210,11 +217,11 @@ where | |||
210 | let krate = Crate::new(crate_id); | 217 | let krate = Crate::new(crate_id); |
211 | for dep in krate.dependencies(self.db) { | 218 | for dep in krate.dependencies(self.db) { |
212 | if let Some(module) = dep.krate.root_module(self.db) { | 219 | if let Some(module) = dep.krate.root_module(self.db) { |
213 | let def_id = module.into(); | 220 | let def = module.into(); |
214 | self.add_module_item( | 221 | self.add_module_item( |
215 | &mut module_items, | 222 | &mut module_items, |
216 | dep.name.clone(), | 223 | dep.name.clone(), |
217 | PerNs::types(def_id), | 224 | PerNs::types(def), |
218 | ); | 225 | ); |
219 | } | 226 | } |
220 | } | 227 | } |
@@ -226,7 +233,7 @@ where | |||
226 | module_items.items.insert( | 233 | module_items.items.insert( |
227 | segment.name.clone(), | 234 | segment.name.clone(), |
228 | Resolution { | 235 | Resolution { |
229 | def_id: PerNs::none(), | 236 | def: PerNs::none(), |
230 | import: Some(import_id), | 237 | import: Some(import_id), |
231 | }, | 238 | }, |
232 | ); | 239 | ); |
@@ -234,11 +241,8 @@ where | |||
234 | } | 241 | } |
235 | } | 242 | } |
236 | // Populate explicitly declared items, except modules | 243 | // Populate explicitly declared items, except modules |
237 | for (name, &def_id) in input.declarations.iter() { | 244 | for (name, &def) in input.declarations.iter() { |
238 | let resolution = Resolution { | 245 | let resolution = Resolution { def, import: None }; |
239 | def_id, | ||
240 | import: None, | ||
241 | }; | ||
242 | module_items.items.insert(name.clone(), resolution); | 246 | module_items.items.insert(name.clone(), resolution); |
243 | } | 247 | } |
244 | 248 | ||
@@ -254,16 +258,8 @@ where | |||
254 | self.result.per_module.insert(module_id, module_items); | 258 | self.result.per_module.insert(module_id, module_items); |
255 | } | 259 | } |
256 | 260 | ||
257 | fn add_module_item( | 261 | fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def: PerNs<ModuleDef>) { |
258 | &self, | 262 | let resolution = Resolution { def, import: None }; |
259 | module_items: &mut ModuleScope, | ||
260 | name: Name, | ||
261 | def_id: PerNs<ModuleDef>, | ||
262 | ) { | ||
263 | let resolution = Resolution { | ||
264 | def_id, | ||
265 | import: None, | ||
266 | }; | ||
267 | module_items.items.insert(name, resolution); | 263 | module_items.items.insert(name, resolution); |
268 | } | 264 | } |
269 | 265 | ||
@@ -273,7 +269,7 @@ where | |||
273 | // already done | 269 | // already done |
274 | continue; | 270 | continue; |
275 | } | 271 | } |
276 | if self.resolve_import(module_id, import_id, import_data) { | 272 | if self.resolve_import(module_id, import_id, import_data) == ReachedFixedPoint::Yes { |
277 | log::debug!("import {:?} resolved (or definite error)", import_id); | 273 | log::debug!("import {:?} resolved (or definite error)", import_id); |
278 | self.processed_imports.insert((module_id, import_id)); | 274 | self.processed_imports.insert((module_id, import_id)); |
279 | } | 275 | } |
@@ -285,116 +281,146 @@ where | |||
285 | module_id: ModuleId, | 281 | module_id: ModuleId, |
286 | import_id: ImportId, | 282 | import_id: ImportId, |
287 | import: &ImportData, | 283 | import: &ImportData, |
288 | ) -> bool { | 284 | ) -> ReachedFixedPoint { |
289 | log::debug!("resolving import: {:?}", import); | 285 | log::debug!("resolving import: {:?}", import); |
290 | if import.is_glob { | 286 | if import.is_glob { |
291 | return false; | 287 | return ReachedFixedPoint::Yes; |
292 | }; | 288 | }; |
289 | let original_module = Module { | ||
290 | krate: self.krate, | ||
291 | module_id, | ||
292 | }; | ||
293 | let (def, reached_fixedpoint) = | ||
294 | self.result | ||
295 | .resolve_path_fp(self.db, original_module, &import.path); | ||
296 | |||
297 | if reached_fixedpoint == ReachedFixedPoint::Yes { | ||
298 | let last_segment = import.path.segments.last().unwrap(); | ||
299 | self.update(module_id, |items| { | ||
300 | let res = Resolution { | ||
301 | def, | ||
302 | import: Some(import_id), | ||
303 | }; | ||
304 | items.items.insert(last_segment.name.clone(), res); | ||
305 | }); | ||
306 | log::debug!( | ||
307 | "resolved import {:?} ({:?}) cross-source root to {:?}", | ||
308 | last_segment.name, | ||
309 | import, | ||
310 | def, | ||
311 | ); | ||
312 | } | ||
313 | reached_fixedpoint | ||
314 | } | ||
315 | |||
316 | fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { | ||
317 | let module_items = self.result.per_module.get_mut(module_id).unwrap(); | ||
318 | f(module_items) | ||
319 | } | ||
320 | } | ||
321 | |||
322 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
323 | enum ReachedFixedPoint { | ||
324 | Yes, | ||
325 | No, | ||
326 | } | ||
293 | 327 | ||
294 | let mut curr: ModuleId = match import.path.kind { | 328 | impl ItemMap { |
295 | PathKind::Plain | PathKind::Self_ => module_id, | 329 | pub(crate) fn resolve_path( |
330 | &self, | ||
331 | db: &impl HirDatabase, | ||
332 | original_module: Module, | ||
333 | path: &Path, | ||
334 | ) -> PerNs<ModuleDef> { | ||
335 | self.resolve_path_fp(db, original_module, path).0 | ||
336 | } | ||
337 | |||
338 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | ||
339 | // the result. | ||
340 | fn resolve_path_fp( | ||
341 | &self, | ||
342 | db: &impl HirDatabase, | ||
343 | original_module: Module, | ||
344 | path: &Path, | ||
345 | ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { | ||
346 | let mut curr_per_ns: PerNs<ModuleDef> = PerNs::types(match path.kind { | ||
347 | PathKind::Crate => original_module.crate_root(db).into(), | ||
348 | PathKind::Self_ | PathKind::Plain => original_module.into(), | ||
296 | PathKind::Super => { | 349 | PathKind::Super => { |
297 | match module_id.parent(&self.module_tree) { | 350 | if let Some(p) = original_module.parent(db) { |
298 | Some(it) => it, | 351 | p.into() |
299 | None => { | 352 | } else { |
300 | // TODO: error | 353 | log::debug!("super path in root module"); |
301 | log::debug!("super path in root module"); | 354 | return (PerNs::none(), ReachedFixedPoint::Yes); |
302 | return true; // this can't suddenly resolve if we just resolve some other imports | ||
303 | } | ||
304 | } | 355 | } |
305 | } | 356 | } |
306 | PathKind::Crate => module_id.crate_root(&self.module_tree), | ||
307 | PathKind::Abs => { | 357 | PathKind::Abs => { |
308 | // TODO: absolute use is not supported for now | 358 | // TODO: absolute use is not supported |
309 | return false; | 359 | return (PerNs::none(), ReachedFixedPoint::Yes); |
310 | } | 360 | } |
311 | }; | 361 | }); |
312 | 362 | ||
313 | for (i, segment) in import.path.segments.iter().enumerate() { | 363 | for (i, segment) in path.segments.iter().enumerate() { |
314 | let is_last = i == import.path.segments.len() - 1; | 364 | let curr = match curr_per_ns.as_ref().take_types() { |
315 | 365 | Some(r) => r, | |
316 | let def_id = match self.result.per_module[&curr].items.get(&segment.name) { | 366 | None => { |
317 | Some(res) if !res.def_id.is_none() => res.def_id, | 367 | // we still have path segments left, but the path so far |
318 | _ => { | 368 | // didn't resolve in the types namespace => no resolution |
319 | log::debug!("path segment {:?} not found", segment.name); | 369 | // (don't break here because curr_per_ns might contain |
320 | return false; | 370 | // something in the value namespace, and it would be wrong |
371 | // to return that) | ||
372 | return (PerNs::none(), ReachedFixedPoint::No); | ||
321 | } | 373 | } |
322 | }; | 374 | }; |
375 | // resolve segment in curr | ||
376 | |||
377 | curr_per_ns = match curr { | ||
378 | ModuleDef::Module(module) => { | ||
379 | if module.krate != original_module.krate { | ||
380 | let path = Path { | ||
381 | segments: path.segments[i..].iter().cloned().collect(), | ||
382 | kind: PathKind::Crate, | ||
383 | }; | ||
384 | log::debug!("resolving {:?} in other crate", path); | ||
385 | let def = module.resolve_path(db, &path); | ||
386 | return (def, ReachedFixedPoint::Yes); | ||
387 | } | ||
323 | 388 | ||
324 | if !is_last { | 389 | match self[module.module_id].items.get(&segment.name) { |
325 | let type_def_id = if let Some(d) = def_id.take(Namespace::Types) { | 390 | Some(res) if !res.def.is_none() => res.def, |
326 | d | 391 | _ => { |
327 | } else { | 392 | log::debug!("path segment {:?} not found", segment.name); |
328 | log::debug!( | 393 | return (PerNs::none(), ReachedFixedPoint::No); |
329 | "path segment {:?} resolved to value only, but is not last", | ||
330 | segment.name | ||
331 | ); | ||
332 | return false; | ||
333 | }; | ||
334 | curr = match type_def_id { | ||
335 | ModuleDef::Module(module) => { | ||
336 | if module.krate == self.krate { | ||
337 | module.module_id | ||
338 | } else { | ||
339 | let path = Path { | ||
340 | segments: import.path.segments[i + 1..].iter().cloned().collect(), | ||
341 | kind: PathKind::Crate, | ||
342 | }; | ||
343 | log::debug!("resolving {:?} in other source root", path); | ||
344 | let def_id = module.resolve_path(self.db, &path); | ||
345 | if !def_id.is_none() { | ||
346 | let last_segment = path.segments.last().unwrap(); | ||
347 | self.update(module_id, |items| { | ||
348 | let res = Resolution { | ||
349 | def_id, | ||
350 | import: Some(import_id), | ||
351 | }; | ||
352 | items.items.insert(last_segment.name.clone(), res); | ||
353 | }); | ||
354 | log::debug!( | ||
355 | "resolved import {:?} ({:?}) cross-source root to {:?}", | ||
356 | last_segment.name, | ||
357 | import, | ||
358 | def_id, | ||
359 | ); | ||
360 | return true; | ||
361 | } else { | ||
362 | log::debug!("rest of path did not resolve in other source root"); | ||
363 | return true; | ||
364 | } | ||
365 | } | 394 | } |
366 | } | 395 | } |
367 | _ => { | 396 | } |
368 | log::debug!( | 397 | ModuleDef::Enum(e) => { |
369 | "path segment {:?} resolved to non-module {:?}, but is not last", | 398 | // enum variant |
370 | segment.name, | 399 | tested_by!(item_map_enum_importing); |
371 | type_def_id, | 400 | let matching_variant = e |
372 | ); | 401 | .variants(db) |
373 | return true; // this resolved to a non-module, so the path won't ever resolve | 402 | .into_iter() |
403 | .find(|(n, _variant)| n == &segment.name); | ||
404 | |||
405 | match matching_variant { | ||
406 | Some((_n, variant)) => PerNs::both(variant.into(), (*e).into()), | ||
407 | None => PerNs::none(), | ||
374 | } | 408 | } |
375 | } | 409 | } |
376 | } else { | 410 | _ => { |
377 | log::debug!( | 411 | // could be an inherent method call in UFCS form |
378 | "resolved import {:?} ({:?}) within source root to {:?}", | 412 | // (`Struct::method`), or some other kind of associated |
379 | segment.name, | 413 | // item... Which we currently don't handle (TODO) |
380 | import, | 414 | log::debug!( |
381 | def_id, | 415 | "path segment {:?} resolved to non-module {:?}, but is not last", |
382 | ); | 416 | segment.name, |
383 | self.update(module_id, |items| { | 417 | curr, |
384 | let res = Resolution { | 418 | ); |
385 | def_id, | 419 | return (PerNs::none(), ReachedFixedPoint::Yes); |
386 | import: Some(import_id), | 420 | } |
387 | }; | 421 | }; |
388 | items.items.insert(segment.name.clone(), res); | ||
389 | }) | ||
390 | } | ||
391 | } | 422 | } |
392 | true | 423 | (curr_per_ns, ReachedFixedPoint::Yes) |
393 | } | ||
394 | |||
395 | fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { | ||
396 | let module_items = self.result.per_module.get_mut(&module_id).unwrap(); | ||
397 | f(module_items) | ||
398 | } | 424 | } |
399 | } | 425 | } |
400 | 426 | ||
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 9322bf08c..c033bebe8 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -20,7 +20,7 @@ fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { | 22 | fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { |
23 | let mut lines = map.per_module[&module_id] | 23 | let mut lines = map[module_id] |
24 | .items | 24 | .items |
25 | .iter() | 25 | .iter() |
26 | .map(|(name, res)| format!("{}: {}", name, dump_resolution(res))) | 26 | .map(|(name, res)| format!("{}: {}", name, dump_resolution(res))) |
@@ -37,8 +37,8 @@ fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { | |||
37 | 37 | ||
38 | fn dump_resolution(resolution: &Resolution) -> &'static str { | 38 | fn dump_resolution(resolution: &Resolution) -> &'static str { |
39 | match ( | 39 | match ( |
40 | resolution.def_id.types.is_some(), | 40 | resolution.def.types.is_some(), |
41 | resolution.def_id.values.is_some(), | 41 | resolution.def.values.is_some(), |
42 | ) { | 42 | ) { |
43 | (true, true) => "t v", | 43 | (true, true) => "t v", |
44 | (true, false) => "t", | 44 | (true, false) => "t", |
@@ -216,6 +216,27 @@ fn item_map_using_self() { | |||
216 | } | 216 | } |
217 | 217 | ||
218 | #[test] | 218 | #[test] |
219 | fn item_map_enum_importing() { | ||
220 | covers!(item_map_enum_importing); | ||
221 | let (item_map, module_id) = item_map( | ||
222 | " | ||
223 | //- /lib.rs | ||
224 | enum E { V } | ||
225 | use self::E::V; | ||
226 | <|> | ||
227 | ", | ||
228 | ); | ||
229 | check_module_item_map( | ||
230 | &item_map, | ||
231 | module_id, | ||
232 | " | ||
233 | E: t | ||
234 | V: t v | ||
235 | ", | ||
236 | ); | ||
237 | } | ||
238 | |||
239 | #[test] | ||
219 | fn item_map_across_crates() { | 240 | fn item_map_across_crates() { |
220 | let (mut db, sr) = MockDatabase::with_files( | 241 | let (mut db, sr) = MockDatabase::with_files( |
221 | " | 242 | " |