aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres/path_resolution.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/nameres/path_resolution.rs')
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs163
1 files changed, 126 insertions, 37 deletions
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 88e10574e..dd1db0094 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -10,20 +10,19 @@
10//! 10//!
11//! `ReachedFixedPoint` signals about this. 11//! `ReachedFixedPoint` signals about this.
12 12
13use std::iter::successors;
14
15use base_db::Edition; 13use base_db::Edition;
14use hir_expand::name;
16use hir_expand::name::Name; 15use hir_expand::name::Name;
17use test_utils::mark; 16use test_utils::mark;
18 17
19use crate::{ 18use crate::{
20 db::DefDatabase, 19 db::DefDatabase,
21 item_scope::BUILTIN_SCOPE, 20 item_scope::BUILTIN_SCOPE,
22 nameres::{BuiltinShadowMode, CrateDefMap}, 21 nameres::{BuiltinShadowMode, DefMap},
23 path::{ModPath, PathKind}, 22 path::{ModPath, PathKind},
24 per_ns::PerNs, 23 per_ns::PerNs,
25 visibility::{RawVisibility, Visibility}, 24 visibility::{RawVisibility, Visibility},
26 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, 25 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId,
27}; 26};
28 27
29#[derive(Debug, Clone, Copy, PartialEq, Eq)] 28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -61,8 +60,12 @@ impl ResolvePathResult {
61 } 60 }
62} 61}
63 62
64impl CrateDefMap { 63impl DefMap {
65 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 64 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
65 if name == &name!(self) {
66 mark::hit!(extern_crate_self_as);
67 return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
68 }
66 self.extern_prelude 69 self.extern_prelude
67 .get(name) 70 .get(name)
68 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) 71 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
@@ -74,7 +77,7 @@ impl CrateDefMap {
74 original_module: LocalModuleId, 77 original_module: LocalModuleId,
75 visibility: &RawVisibility, 78 visibility: &RawVisibility,
76 ) -> Option<Visibility> { 79 ) -> Option<Visibility> {
77 match visibility { 80 let mut vis = match visibility {
78 RawVisibility::Module(path) => { 81 RawVisibility::Module(path) => {
79 let (result, remaining) = 82 let (result, remaining) =
80 self.resolve_path(db, original_module, &path, BuiltinShadowMode::Module); 83 self.resolve_path(db, original_module, &path, BuiltinShadowMode::Module);
@@ -83,15 +86,28 @@ impl CrateDefMap {
83 } 86 }
84 let types = result.take_types()?; 87 let types = result.take_types()?;
85 match types { 88 match types {
86 ModuleDefId::ModuleId(m) => Some(Visibility::Module(m)), 89 ModuleDefId::ModuleId(m) => Visibility::Module(m),
87 _ => { 90 _ => {
88 // error: visibility needs to refer to module 91 // error: visibility needs to refer to module
89 None 92 return None;
90 } 93 }
91 } 94 }
92 } 95 }
93 RawVisibility::Public => Some(Visibility::Public), 96 RawVisibility::Public => Visibility::Public,
97 };
98
99 // In block expressions, `self` normally refers to the containing non-block module, and
100 // `super` to its parent (etc.). However, visibilities must only refer to a module in the
101 // DefMap they're written in, so we restrict them when that happens.
102 if let Visibility::Module(m) = vis {
103 if self.block_id() != m.block {
104 mark::hit!(adjust_vis_in_block_def_map);
105 vis = Visibility::Module(self.module_id(self.root()));
106 log::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
107 }
94 } 108 }
109
110 Some(vis)
95 } 111 }
96 112
97 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 113 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -100,30 +116,69 @@ impl CrateDefMap {
100 &self, 116 &self,
101 db: &dyn DefDatabase, 117 db: &dyn DefDatabase,
102 mode: ResolveMode, 118 mode: ResolveMode,
119 mut original_module: LocalModuleId,
120 path: &ModPath,
121 shadow: BuiltinShadowMode,
122 ) -> ResolvePathResult {
123 let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
124
125 let mut arc;
126 let mut current_map = self;
127 loop {
128 let new = current_map.resolve_path_fp_with_macro_single(
129 db,
130 mode,
131 original_module,
132 path,
133 shadow,
134 );
135
136 // Merge `new` into `result`.
137 result.resolved_def = result.resolved_def.or(new.resolved_def);
138 if result.reached_fixedpoint == ReachedFixedPoint::No {
139 result.reached_fixedpoint = new.reached_fixedpoint;
140 }
141 // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates?
142 result.krate = result.krate.or(new.krate);
143 result.segment_index = match (result.segment_index, new.segment_index) {
144 (Some(idx), None) => Some(idx),
145 (Some(old), Some(new)) => Some(old.max(new)),
146 (None, new) => new,
147 };
148
149 match &current_map.block {
150 Some(block) => {
151 original_module = block.parent.local_id;
152 arc = block.parent.def_map(db);
153 current_map = &*arc;
154 }
155 None => return result,
156 }
157 }
158 }
159
160 pub(super) fn resolve_path_fp_with_macro_single(
161 &self,
162 db: &dyn DefDatabase,
163 mode: ResolveMode,
103 original_module: LocalModuleId, 164 original_module: LocalModuleId,
104 path: &ModPath, 165 path: &ModPath,
105 shadow: BuiltinShadowMode, 166 shadow: BuiltinShadowMode,
106 ) -> ResolvePathResult { 167 ) -> ResolvePathResult {
107 let mut segments = path.segments.iter().enumerate(); 168 let mut segments = path.segments().iter().enumerate();
108 let mut curr_per_ns: PerNs = match path.kind { 169 let mut curr_per_ns: PerNs = match path.kind {
109 PathKind::DollarCrate(krate) => { 170 PathKind::DollarCrate(krate) => {
110 if krate == self.krate { 171 if krate == self.krate {
111 mark::hit!(macro_dollar_crate_self); 172 mark::hit!(macro_dollar_crate_self);
112 PerNs::types( 173 PerNs::types(self.crate_root(db).into(), Visibility::Public)
113 ModuleId { krate: self.krate, local_id: self.root }.into(),
114 Visibility::Public,
115 )
116 } else { 174 } else {
117 let def_map = db.crate_def_map(krate); 175 let def_map = db.crate_def_map(krate);
118 let module = ModuleId { krate, local_id: def_map.root }; 176 let module = def_map.module_id(def_map.root);
119 mark::hit!(macro_dollar_crate_other); 177 mark::hit!(macro_dollar_crate_other);
120 PerNs::types(module.into(), Visibility::Public) 178 PerNs::types(module.into(), Visibility::Public)
121 } 179 }
122 } 180 }
123 PathKind::Crate => PerNs::types( 181 PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public),
124 ModuleId { krate: self.krate, local_id: self.root }.into(),
125 Visibility::Public,
126 ),
127 // plain import or absolute path in 2015: crate-relative with 182 // plain import or absolute path in 2015: crate-relative with
128 // fallback to extern prelude (with the simplification in 183 // fallback to extern prelude (with the simplification in
129 // rust-lang/rust#57745) 184 // rust-lang/rust#57745)
@@ -151,23 +206,49 @@ impl CrateDefMap {
151 // BuiltinShadowMode wasn't Module, then we need to try 206 // BuiltinShadowMode wasn't Module, then we need to try
152 // resolving it as a builtin. 207 // resolving it as a builtin.
153 let prefer_module = 208 let prefer_module =
154 if path.segments.len() == 1 { shadow } else { BuiltinShadowMode::Module }; 209 if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
155 210
156 log::debug!("resolving {:?} in module", segment); 211 log::debug!("resolving {:?} in module", segment);
157 self.resolve_name_in_module(db, original_module, &segment, prefer_module) 212 self.resolve_name_in_module(db, original_module, &segment, prefer_module)
158 } 213 }
159 PathKind::Super(lvl) => { 214 PathKind::Super(lvl) => {
160 let m = successors(Some(original_module), |m| self.modules[*m].parent) 215 let mut module = original_module;
161 .nth(lvl as usize); 216 for i in 0..lvl {
162 if let Some(local_id) = m { 217 match self.modules[module].parent {
163 PerNs::types( 218 Some(it) => module = it,
164 ModuleId { krate: self.krate, local_id }.into(), 219 None => match &self.block {
165 Visibility::Public, 220 Some(block) => {
166 ) 221 // Look up remaining path in parent `DefMap`
167 } else { 222 let new_path = ModPath::from_segments(
168 log::debug!("super path in root module"); 223 PathKind::Super(lvl - i),
169 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 224 path.segments().to_vec(),
225 );
226 log::debug!("`super` path: {} -> {} in parent map", path, new_path);
227 return block.parent.def_map(db).resolve_path_fp_with_macro(
228 db,
229 mode,
230 block.parent.local_id,
231 &new_path,
232 shadow,
233 );
234 }
235 None => {
236 log::debug!("super path in root module");
237 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
238 }
239 },
240 }
170 } 241 }
242
243 // Resolve `self` to the containing crate-rooted module if we're a block
244 self.with_ancestor_maps(db, module, &mut |def_map, module| {
245 if def_map.block.is_some() {
246 None // keep ascending
247 } else {
248 Some(PerNs::types(def_map.module_id(module).into(), Visibility::Public))
249 }
250 })
251 .expect("block DefMap not rooted in crate DefMap")
171 } 252 }
172 PathKind::Abs => { 253 PathKind::Abs => {
173 // 2018-style absolute path -- only extern prelude 254 // 2018-style absolute path -- only extern prelude
@@ -201,12 +282,12 @@ impl CrateDefMap {
201 curr_per_ns = match curr { 282 curr_per_ns = match curr {
202 ModuleDefId::ModuleId(module) => { 283 ModuleDefId::ModuleId(module) => {
203 if module.krate != self.krate { 284 if module.krate != self.krate {
204 let path = ModPath { 285 let path = ModPath::from_segments(
205 segments: path.segments[i..].to_vec(), 286 PathKind::Super(0),
206 kind: PathKind::Super(0), 287 path.segments()[i..].iter().cloned(),
207 }; 288 );
208 log::debug!("resolving {:?} in other crate", path); 289 log::debug!("resolving {:?} in other crate", path);
209 let defp_map = db.crate_def_map(module.krate); 290 let defp_map = module.def_map(db);
210 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); 291 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
211 return ResolvePathResult::with( 292 return ResolvePathResult::with(
212 def, 293 def,
@@ -216,8 +297,16 @@ impl CrateDefMap {
216 ); 297 );
217 } 298 }
218 299
300 let def_map;
301 let module_data = if module.block == self.block_id() {
302 &self[module.local_id]
303 } else {
304 def_map = module.def_map(db);
305 &def_map[module.local_id]
306 };
307
219 // Since it is a qualified path here, it should not contains legacy macros 308 // Since it is a qualified path here, it should not contains legacy macros
220 self[module.local_id].scope.get(&segment) 309 module_data.scope.get(&segment)
221 } 310 }
222 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 311 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
223 // enum variant 312 // enum variant
@@ -319,7 +408,7 @@ impl CrateDefMap {
319 self 408 self
320 } else { 409 } else {
321 // Extend lifetime 410 // Extend lifetime
322 keep = db.crate_def_map(prelude.krate); 411 keep = prelude.def_map(db);
323 &keep 412 &keep
324 }; 413 };
325 def_map[prelude.local_id].scope.get(name) 414 def_map[prelude.local_id].scope.get(name)