aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres/path_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/nameres/path_resolution.rs')
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs105
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
13use std::iter::successors;
14
13use hir_expand::name::Name; 15use hir_expand::name::Name;
14use ra_db::Edition; 16use ra_db::Edition;
15use test_utils::tested_by; 17use test_utils::tested_by;
16 18
17use crate::{ 19use 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
44impl ResolvePathResult { 47impl 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 }