hir_def/expr_store/lower/
path.rs1#[cfg(test)]
4mod tests;
5
6use std::iter;
7
8use crate::expr_store::{
9 lower::{ExprCollector, generics::ImplTraitLowerFn},
10 path::NormalPath,
11};
12
13use hir_expand::{
14 mod_path::{ModPath, PathKind, resolve_crate_root},
15 name::{AsName, Name},
16};
17use intern::{Interned, sym};
18use syntax::{
19 AstPtr,
20 ast::{self, AstNode, HasGenericArgs},
21};
22
23use crate::{
24 expr_store::path::{GenericArg, GenericArgs, Path},
25 type_ref::TypeRef,
26};
27
28#[cfg(test)]
29thread_local! {
30 pub(super) static SEGMENT_LOWERING_MAP: std::cell::RefCell<rustc_hash::FxHashMap<ast::PathSegment, usize>> = std::cell::RefCell::default();
32}
33
34pub(super) fn lower_path(
39 collector: &mut ExprCollector<'_>,
40 mut path: ast::Path,
41 impl_trait_lower_fn: ImplTraitLowerFn<'_>,
42) -> Option<Path> {
43 let mut kind = PathKind::Plain;
44 let mut type_anchor = None;
45 let mut segments = Vec::new();
46 let mut generic_args = Vec::new();
47 #[cfg(test)]
48 let mut ast_segments = Vec::new();
49 #[cfg(test)]
50 let mut ast_segments_offset = 0;
51 #[allow(unused_mut)]
52 let mut push_segment = |_segment: &ast::PathSegment, segments: &mut Vec<Name>, name| {
53 #[cfg(test)]
54 ast_segments.push(_segment.clone());
55 segments.push(name);
56 };
57 loop {
58 let Some(segment) = path.segment() else {
59 segments.push(Name::missing());
60 match qualifier(&path) {
62 Some(it) => {
63 path = it;
64 continue;
65 }
66 None => break,
67 }
68 };
69
70 if segment.coloncolon_token().is_some() {
71 debug_assert!(path.qualifier().is_none()); kind = PathKind::Abs;
73 }
74
75 match segment.kind()? {
76 ast::PathSegmentKind::Name(name_ref) => {
77 if name_ref.text() == "$crate" {
78 if path.qualifier().is_some() {
79 return None;
81 }
82 break kind = resolve_crate_root(
83 collector.db,
84 collector.expander.ctx_for_range(name_ref.syntax().text_range()),
85 )
86 .map(PathKind::DollarCrate)
87 .unwrap_or(PathKind::Crate);
88 }
89 let name = name_ref.as_name();
90 let args = segment
91 .generic_arg_list()
92 .and_then(|it| collector.lower_generic_args(it, impl_trait_lower_fn))
93 .or_else(|| {
94 collector.lower_generic_args_from_fn_path(
95 segment.parenthesized_arg_list(),
96 segment.ret_type(),
97 impl_trait_lower_fn,
98 )
99 })
100 .or_else(|| {
101 segment.return_type_syntax().map(|_| GenericArgs::return_type_notation())
102 });
103 if args.is_some() {
104 generic_args.resize(segments.len(), None);
105 generic_args.push(args);
106 }
107 push_segment(&segment, &mut segments, name);
108 }
109 ast::PathSegmentKind::SelfTypeKw => {
110 push_segment(&segment, &mut segments, Name::new_symbol_root(sym::Self_));
111 }
112 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
113 debug_assert!(path.qualifier().is_none()); let self_type = collector.lower_type_ref(type_ref?, impl_trait_lower_fn);
116
117 match trait_ref {
118 None => {
120 type_anchor = Some(self_type);
121 kind = PathKind::Plain;
122 }
123 Some(trait_ref) => {
125 let path = collector.lower_path(trait_ref.path()?, impl_trait_lower_fn)?;
126 collector.alloc_type_ref(
128 TypeRef::Path(path.clone()),
129 AstPtr::new(&trait_ref).upcast(),
130 );
131 let mod_path = path.mod_path()?;
132 let path_generic_args = path.generic_args();
133 let num_segments = mod_path.segments().len();
134 kind = mod_path.kind;
135
136 segments.extend(mod_path.segments().iter().cloned().rev());
137 #[cfg(test)]
138 {
139 ast_segments_offset = mod_path.segments().len();
140 }
141 if let Some(path_generic_args) = path_generic_args {
142 generic_args.resize(segments.len() - num_segments, None);
143 generic_args.extend(Vec::from(path_generic_args).into_iter().rev());
144 } else {
145 generic_args.resize(segments.len(), None);
146 }
147
148 let self_type = GenericArg::Type(self_type);
149
150 let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
152 *last_segment = Some(match last_segment.take() {
153 Some(it) => GenericArgs {
154 args: iter::once(self_type)
155 .chain(it.args.iter().cloned())
156 .collect(),
157 has_self_type: true,
158 ..it
159 },
160 None => GenericArgs {
161 args: Box::new([self_type]),
162 has_self_type: true,
163 ..GenericArgs::empty()
164 },
165 });
166 }
167 }
168 }
169 ast::PathSegmentKind::CrateKw => {
170 if path.qualifier().is_some() {
171 return None;
173 }
174 kind = PathKind::Crate;
175 break;
176 }
177 ast::PathSegmentKind::SelfKw => {
178 if path.qualifier().is_some() {
179 return None;
181 }
182 if !segments.is_empty() {
185 kind = PathKind::SELF;
186 break;
187 }
188 }
189 ast::PathSegmentKind::SuperKw => {
190 let nested_super_count = if let PathKind::Super(n) = kind { n } else { 0 };
191 kind = PathKind::Super(nested_super_count + 1);
192 }
193 }
194 path = match qualifier(&path) {
195 Some(it) => it,
196 None => break,
197 };
198 }
199 segments.reverse();
200 if !generic_args.is_empty() || type_anchor.is_some() {
201 generic_args.resize(segments.len(), None);
202 generic_args.reverse();
203 }
204
205 if segments.is_empty() && kind == PathKind::Plain && type_anchor.is_none() {
206 kind = PathKind::SELF;
208 }
209
210 if segments.len() == 1
215 && kind == PathKind::Plain
216 && let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast)
217 {
218 let syn_ctxt = collector.expander.ctx_for_range(path.segment()?.syntax().text_range());
219 if let Some(macro_call_id) = syn_ctxt.outer_expn(collector.db)
220 && collector.db.lookup_intern_macro_call(macro_call_id.into()).def.local_inner
221 {
222 kind = match resolve_crate_root(collector.db, syn_ctxt) {
223 Some(crate_root) => PathKind::DollarCrate(crate_root),
224 None => PathKind::Crate,
225 }
226 }
227 }
228
229 #[cfg(test)]
230 {
231 ast_segments.reverse();
232 SEGMENT_LOWERING_MAP
233 .with_borrow_mut(|map| map.extend(ast_segments.into_iter().zip(ast_segments_offset..)));
234 }
235
236 if let Some(last_segment_args @ Some(GenericArgs { has_self_type: true, .. })) =
237 generic_args.last_mut()
238 {
239 *last_segment_args = None;
242 }
243
244 let mod_path = Interned::new(ModPath::from_segments(kind, segments));
245 if type_anchor.is_none() && generic_args.is_empty() {
246 return Some(Path::BarePath(mod_path));
247 } else {
248 return Some(Path::Normal(Box::new(NormalPath {
249 type_anchor,
250 mod_path,
251 generic_args: generic_args.into_boxed_slice(),
252 })));
253 }
254
255 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
256 if let Some(q) = path.qualifier() {
257 return Some(q);
258 }
259 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
262 let use_tree = use_tree_list.parent_use_tree();
263 use_tree.path()
264 }
265}
266
267pub fn hir_segment_to_ast_segment(path: &ast::Path, segment_idx: u32) -> Option<ast::PathSegment> {
270 let mut segments = path.segments();
274 if let Some(ast::PathSegmentKind::Type { trait_ref: Some(trait_ref), .. }) =
275 segments.clone().next().and_then(|it| it.kind())
276 {
277 segments.next();
278 return find_segment(trait_ref.path()?.segments().chain(segments), segment_idx);
279 }
280 return find_segment(segments, segment_idx);
281
282 fn find_segment(
283 segments: impl Iterator<Item = ast::PathSegment>,
284 segment_idx: u32,
285 ) -> Option<ast::PathSegment> {
286 segments
287 .filter(|segment| match segment.kind() {
288 Some(
289 ast::PathSegmentKind::CrateKw
290 | ast::PathSegmentKind::SelfKw
291 | ast::PathSegmentKind::SuperKw
292 | ast::PathSegmentKind::Type { .. },
293 )
294 | None => false,
295 Some(ast::PathSegmentKind::Name(name)) => name.text() != "$crate",
296 Some(ast::PathSegmentKind::SelfTypeKw) => true,
297 })
298 .nth(segment_idx as usize)
299 }
300}