diff options
Diffstat (limited to 'crates/ra_hir_def/src/nameres/path_resolution.rs')
-rw-r--r-- | crates/ra_hir_def/src/nameres/path_resolution.rs | 105 |
1 files changed, 61 insertions, 44 deletions
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs index b72c55bd1..695014c7b 100644 --- a/crates/ra_hir_def/src/nameres/path_resolution.rs +++ b/crates/ra_hir_def/src/nameres/path_resolution.rs | |||
@@ -10,16 +10,18 @@ | |||
10 | //! | 10 | //! |
11 | //! `ReachedFixedPoint` signals about this. | 11 | //! `ReachedFixedPoint` signals about this. |
12 | 12 | ||
13 | use std::iter::successors; | ||
14 | |||
13 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
14 | use ra_db::Edition; | 16 | use ra_db::Edition; |
15 | use test_utils::tested_by; | 17 | use test_utils::tested_by; |
16 | 18 | ||
17 | use crate::{ | 19 | use crate::{ |
18 | db::DefDatabase, | 20 | db::DefDatabase, |
19 | nameres::CrateDefMap, | 21 | nameres::{BuiltinShadowMode, CrateDefMap}, |
20 | path::{Path, PathKind}, | 22 | path::{ModPath, PathKind}, |
21 | per_ns::PerNs, | 23 | per_ns::PerNs, |
22 | AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, | 24 | AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, |
23 | }; | 25 | }; |
24 | 26 | ||
25 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 27 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
@@ -39,19 +41,21 @@ pub(super) struct ResolvePathResult { | |||
39 | pub(super) resolved_def: PerNs, | 41 | pub(super) resolved_def: PerNs, |
40 | pub(super) segment_index: Option<usize>, | 42 | pub(super) segment_index: Option<usize>, |
41 | pub(super) reached_fixedpoint: ReachedFixedPoint, | 43 | pub(super) reached_fixedpoint: ReachedFixedPoint, |
44 | pub(super) krate: Option<CrateId>, | ||
42 | } | 45 | } |
43 | 46 | ||
44 | impl ResolvePathResult { | 47 | impl ResolvePathResult { |
45 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { | 48 | fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { |
46 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) | 49 | ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None) |
47 | } | 50 | } |
48 | 51 | ||
49 | fn with( | 52 | fn with( |
50 | resolved_def: PerNs, | 53 | resolved_def: PerNs, |
51 | reached_fixedpoint: ReachedFixedPoint, | 54 | reached_fixedpoint: ReachedFixedPoint, |
52 | segment_index: Option<usize>, | 55 | segment_index: Option<usize>, |
56 | krate: Option<CrateId>, | ||
53 | ) -> ResolvePathResult { | 57 | ) -> ResolvePathResult { |
54 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } | 58 | ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate } |
55 | } | 59 | } |
56 | } | 60 | } |
57 | 61 | ||
@@ -67,8 +71,18 @@ impl CrateDefMap { | |||
67 | db: &impl DefDatabase, | 71 | db: &impl DefDatabase, |
68 | mode: ResolveMode, | 72 | mode: ResolveMode, |
69 | original_module: LocalModuleId, | 73 | original_module: LocalModuleId, |
70 | path: &Path, | 74 | path: &ModPath, |
75 | shadow: BuiltinShadowMode, | ||
71 | ) -> ResolvePathResult { | 76 | ) -> ResolvePathResult { |
77 | // if it is not the last segment, we prefer the module to the builtin | ||
78 | let prefer_module = |index| { | ||
79 | if index == path.segments.len() - 1 { | ||
80 | shadow | ||
81 | } else { | ||
82 | BuiltinShadowMode::Module | ||
83 | } | ||
84 | }; | ||
85 | |||
72 | let mut segments = path.segments.iter().enumerate(); | 86 | let mut segments = path.segments.iter().enumerate(); |
73 | let mut curr_per_ns: PerNs = match path.kind { | 87 | let mut curr_per_ns: PerNs = match path.kind { |
74 | PathKind::DollarCrate(krate) => { | 88 | PathKind::DollarCrate(krate) => { |
@@ -85,9 +99,6 @@ impl CrateDefMap { | |||
85 | PathKind::Crate => { | 99 | PathKind::Crate => { |
86 | PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) | 100 | PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) |
87 | } | 101 | } |
88 | PathKind::Self_ => { | ||
89 | PerNs::types(ModuleId { krate: self.krate, local_id: original_module }.into()) | ||
90 | } | ||
91 | // plain import or absolute path in 2015: crate-relative with | 102 | // plain import or absolute path in 2015: crate-relative with |
92 | // fallback to extern prelude (with the simplification in | 103 | // fallback to extern prelude (with the simplification in |
93 | // rust-lang/rust#57745) | 104 | // rust-lang/rust#57745) |
@@ -96,24 +107,26 @@ impl CrateDefMap { | |||
96 | if self.edition == Edition::Edition2015 | 107 | if self.edition == Edition::Edition2015 |
97 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | 108 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => |
98 | { | 109 | { |
99 | let segment = match segments.next() { | 110 | let (idx, segment) = match segments.next() { |
100 | Some((_, segment)) => segment, | 111 | Some((idx, segment)) => (idx, segment), |
101 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 112 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
102 | }; | 113 | }; |
103 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | 114 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); |
104 | self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) | 115 | self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx)) |
105 | } | 116 | } |
106 | PathKind::Plain => { | 117 | PathKind::Plain => { |
107 | let segment = match segments.next() { | 118 | let (idx, segment) = match segments.next() { |
108 | Some((_, segment)) => segment, | 119 | Some((idx, segment)) => (idx, segment), |
109 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 120 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
110 | }; | 121 | }; |
111 | log::debug!("resolving {:?} in module", segment); | 122 | log::debug!("resolving {:?} in module", segment); |
112 | self.resolve_name_in_module(db, original_module, &segment.name) | 123 | self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx)) |
113 | } | 124 | } |
114 | PathKind::Super => { | 125 | PathKind::Super(lvl) => { |
115 | if let Some(p) = self.modules[original_module].parent { | 126 | let m = successors(Some(original_module), |m| self.modules[*m].parent) |
116 | PerNs::types(ModuleId { krate: self.krate, local_id: p }.into()) | 127 | .nth(lvl as usize); |
128 | if let Some(local_id) = m { | ||
129 | PerNs::types(ModuleId { krate: self.krate, local_id }.into()) | ||
117 | } else { | 130 | } else { |
118 | log::debug!("super path in root module"); | 131 | log::debug!("super path in root module"); |
119 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | 132 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); |
@@ -125,18 +138,13 @@ impl CrateDefMap { | |||
125 | Some((_, segment)) => segment, | 138 | Some((_, segment)) => segment, |
126 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | 139 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), |
127 | }; | 140 | }; |
128 | if let Some(def) = self.extern_prelude.get(&segment.name) { | 141 | if let Some(def) = self.extern_prelude.get(&segment) { |
129 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | 142 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); |
130 | PerNs::types(*def) | 143 | PerNs::types(*def) |
131 | } else { | 144 | } else { |
132 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | 145 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude |
133 | } | 146 | } |
134 | } | 147 | } |
135 | PathKind::Type(_) => { | ||
136 | // This is handled in `infer::infer_path_expr` | ||
137 | // The result returned here does not matter | ||
138 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
139 | } | ||
140 | }; | 148 | }; |
141 | 149 | ||
142 | for (i, segment) in segments { | 150 | for (i, segment) in segments { |
@@ -156,32 +164,29 @@ impl CrateDefMap { | |||
156 | curr_per_ns = match curr { | 164 | curr_per_ns = match curr { |
157 | ModuleDefId::ModuleId(module) => { | 165 | ModuleDefId::ModuleId(module) => { |
158 | if module.krate != self.krate { | 166 | if module.krate != self.krate { |
159 | let path = | 167 | let path = ModPath { |
160 | Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; | 168 | segments: path.segments[i..].to_vec(), |
169 | kind: PathKind::Super(0), | ||
170 | }; | ||
161 | log::debug!("resolving {:?} in other crate", path); | 171 | log::debug!("resolving {:?} in other crate", path); |
162 | let defp_map = db.crate_def_map(module.krate); | 172 | let defp_map = db.crate_def_map(module.krate); |
163 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path); | 173 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); |
164 | return ResolvePathResult::with( | 174 | return ResolvePathResult::with( |
165 | def, | 175 | def, |
166 | ReachedFixedPoint::Yes, | 176 | ReachedFixedPoint::Yes, |
167 | s.map(|s| s + i), | 177 | s.map(|s| s + i), |
178 | Some(module.krate), | ||
168 | ); | 179 | ); |
169 | } | 180 | } |
170 | 181 | ||
171 | // Since it is a qualified path here, it should not contains legacy macros | 182 | // Since it is a qualified path here, it should not contains legacy macros |
172 | match self[module.local_id].scope.get(&segment.name) { | 183 | self[module.local_id].scope.get(&segment, prefer_module(i)) |
173 | Some(res) => res.def, | ||
174 | _ => { | ||
175 | log::debug!("path segment {:?} not found", segment.name); | ||
176 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
177 | } | ||
178 | } | ||
179 | } | 184 | } |
180 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | 185 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { |
181 | // enum variant | 186 | // enum variant |
182 | tested_by!(can_import_enum_variant); | 187 | tested_by!(can_import_enum_variant); |
183 | let enum_data = db.enum_data(e); | 188 | let enum_data = db.enum_data(e); |
184 | match enum_data.variant(&segment.name) { | 189 | match enum_data.variant(&segment) { |
185 | Some(local_id) => { | 190 | Some(local_id) => { |
186 | let variant = EnumVariantId { parent: e, local_id }; | 191 | let variant = EnumVariantId { parent: e, local_id }; |
187 | PerNs::both(variant.into(), variant.into()) | 192 | PerNs::both(variant.into(), variant.into()) |
@@ -191,6 +196,7 @@ impl CrateDefMap { | |||
191 | PerNs::types(e.into()), | 196 | PerNs::types(e.into()), |
192 | ReachedFixedPoint::Yes, | 197 | ReachedFixedPoint::Yes, |
193 | Some(i), | 198 | Some(i), |
199 | Some(self.krate), | ||
194 | ); | 200 | ); |
195 | } | 201 | } |
196 | } | 202 | } |
@@ -200,7 +206,7 @@ impl CrateDefMap { | |||
200 | // (`Struct::method`), or some other kind of associated item | 206 | // (`Struct::method`), or some other kind of associated item |
201 | log::debug!( | 207 | log::debug!( |
202 | "path segment {:?} resolved to non-module {:?}, but is not last", | 208 | "path segment {:?} resolved to non-module {:?}, but is not last", |
203 | segment.name, | 209 | segment, |
204 | curr, | 210 | curr, |
205 | ); | 211 | ); |
206 | 212 | ||
@@ -208,11 +214,13 @@ impl CrateDefMap { | |||
208 | PerNs::types(s), | 214 | PerNs::types(s), |
209 | ReachedFixedPoint::Yes, | 215 | ReachedFixedPoint::Yes, |
210 | Some(i), | 216 | Some(i), |
217 | Some(self.krate), | ||
211 | ); | 218 | ); |
212 | } | 219 | } |
213 | }; | 220 | }; |
214 | } | 221 | } |
215 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | 222 | |
223 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate)) | ||
216 | } | 224 | } |
217 | 225 | ||
218 | fn resolve_name_in_module( | 226 | fn resolve_name_in_module( |
@@ -220,6 +228,7 @@ impl CrateDefMap { | |||
220 | db: &impl DefDatabase, | 228 | db: &impl DefDatabase, |
221 | module: LocalModuleId, | 229 | module: LocalModuleId, |
222 | name: &Name, | 230 | name: &Name, |
231 | shadow: BuiltinShadowMode, | ||
223 | ) -> PerNs { | 232 | ) -> PerNs { |
224 | // Resolve in: | 233 | // Resolve in: |
225 | // - legacy scope of macro | 234 | // - legacy scope of macro |
@@ -228,23 +237,31 @@ impl CrateDefMap { | |||
228 | // - std prelude | 237 | // - std prelude |
229 | let from_legacy_macro = | 238 | let from_legacy_macro = |
230 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); | 239 | self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); |
231 | let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); | 240 | let from_scope = self[module].scope.get(name, shadow); |
232 | let from_extern_prelude = | 241 | let from_extern_prelude = |
233 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | 242 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); |
234 | let from_prelude = self.resolve_in_prelude(db, name); | 243 | let from_prelude = self.resolve_in_prelude(db, name, shadow); |
235 | 244 | ||
236 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) | 245 | from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) |
237 | } | 246 | } |
238 | 247 | ||
239 | fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { | 248 | fn resolve_name_in_crate_root_or_extern_prelude( |
240 | let from_crate_root = | 249 | &self, |
241 | self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); | 250 | name: &Name, |
251 | shadow: BuiltinShadowMode, | ||
252 | ) -> PerNs { | ||
253 | let from_crate_root = self[self.root].scope.get(name, shadow); | ||
242 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | 254 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); |
243 | 255 | ||
244 | from_crate_root.or(from_extern_prelude) | 256 | from_crate_root.or(from_extern_prelude) |
245 | } | 257 | } |
246 | 258 | ||
247 | fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { | 259 | fn resolve_in_prelude( |
260 | &self, | ||
261 | db: &impl DefDatabase, | ||
262 | name: &Name, | ||
263 | shadow: BuiltinShadowMode, | ||
264 | ) -> PerNs { | ||
248 | if let Some(prelude) = self.prelude { | 265 | if let Some(prelude) = self.prelude { |
249 | let keep; | 266 | let keep; |
250 | let def_map = if prelude.krate == self.krate { | 267 | let def_map = if prelude.krate == self.krate { |
@@ -254,7 +271,7 @@ impl CrateDefMap { | |||
254 | keep = db.crate_def_map(prelude.krate); | 271 | keep = db.crate_def_map(prelude.krate); |
255 | &keep | 272 | &keep |
256 | }; | 273 | }; |
257 | def_map[prelude.local_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) | 274 | def_map[prelude.local_id].scope.get(name, shadow) |
258 | } else { | 275 | } else { |
259 | PerNs::none() | 276 | PerNs::none() |
260 | } | 277 | } |