aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/path.rs')
-rw-r--r--crates/ra_hir_def/src/path.rs420
1 files changed, 420 insertions, 0 deletions
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
new file mode 100644
index 000000000..04039376f
--- /dev/null
+++ b/crates/ra_hir_def/src/path.rs
@@ -0,0 +1,420 @@
1//! FIXME: write short doc here
2
3use std::{iter, sync::Arc};
4
5use hir_expand::{
6 either::Either,
7 hygiene::Hygiene,
8 name::{self, AsName, Name},
9};
10use ra_db::CrateId;
11use ra_syntax::{
12 ast::{self, NameOwner, TypeAscriptionOwner},
13 AstNode,
14};
15
16use crate::{type_ref::TypeRef, Source};
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct Path {
20 pub kind: PathKind,
21 pub segments: Vec<PathSegment>,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct PathSegment {
26 pub name: Name,
27 pub args_and_bindings: Option<Arc<GenericArgs>>,
28}
29
30/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
31/// can (in the future) also include bindings of associated types, like in
32/// `Iterator<Item = Foo>`.
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct GenericArgs {
35 pub args: Vec<GenericArg>,
36 /// This specifies whether the args contain a Self type as the first
37 /// element. This is the case for path segments like `<T as Trait>`, where
38 /// `T` is actually a type parameter for the path `Trait` specifying the
39 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
40 /// is left out.
41 pub has_self_type: bool,
42 /// Associated type bindings like in `Iterator<Item = T>`.
43 pub bindings: Vec<(Name, TypeRef)>,
44}
45
46/// A single generic argument.
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48pub enum GenericArg {
49 Type(TypeRef),
50 // or lifetime...
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub enum PathKind {
55 Plain,
56 Self_,
57 Super,
58 Crate,
59 // Absolute path
60 Abs,
61 // Type based path like `<T>::foo`
62 Type(Box<TypeRef>),
63 // `$crate` from macro expansion
64 DollarCrate(CrateId),
65}
66
67impl Path {
68 /// Calls `cb` with all paths, represented by this use item.
69 pub fn expand_use_item(
70 item_src: Source<ast::UseItem>,
71 hygiene: &Hygiene,
72 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
73 ) {
74 if let Some(tree) = item_src.ast.use_tree() {
75 expand_use_tree(None, tree, hygiene, &mut cb);
76 }
77 }
78
79 pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path {
80 Path {
81 kind,
82 segments: segments
83 .into_iter()
84 .map(|name| PathSegment { name, args_and_bindings: None })
85 .collect(),
86 }
87 }
88
89 /// Converts an `ast::Path` to `Path`. Works with use trees.
90 /// DEPRECATED: It does not handle `$crate` from macro call.
91 pub fn from_ast(path: ast::Path) -> Option<Path> {
92 Path::from_src(path, &Hygiene::new_unhygienic())
93 }
94
95 /// Converts an `ast::Path` to `Path`. Works with use trees.
96 /// It correctly handles `$crate` based path from macro call.
97 pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
98 let mut kind = PathKind::Plain;
99 let mut segments = Vec::new();
100 loop {
101 let segment = path.segment()?;
102
103 if segment.has_colon_colon() {
104 kind = PathKind::Abs;
105 }
106
107 match segment.kind()? {
108 ast::PathSegmentKind::Name(name_ref) => {
109 // FIXME: this should just return name
110 match hygiene.name_ref_to_name(name_ref) {
111 Either::A(name) => {
112 let args = segment
113 .type_arg_list()
114 .and_then(GenericArgs::from_ast)
115 .or_else(|| {
116 GenericArgs::from_fn_like_path_ast(
117 segment.param_list(),
118 segment.ret_type(),
119 )
120 })
121 .map(Arc::new);
122 let segment = PathSegment { name, args_and_bindings: args };
123 segments.push(segment);
124 }
125 Either::B(crate_id) => {
126 kind = PathKind::DollarCrate(crate_id);
127 break;
128 }
129 }
130 }
131 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
132 assert!(path.qualifier().is_none()); // this can only occur at the first segment
133
134 let self_type = TypeRef::from_ast(type_ref?);
135
136 match trait_ref {
137 // <T>::foo
138 None => {
139 kind = PathKind::Type(Box::new(self_type));
140 }
141 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
142 Some(trait_ref) => {
143 let path = Path::from_src(trait_ref.path()?, hygiene)?;
144 kind = path.kind;
145 let mut prefix_segments = path.segments;
146 prefix_segments.reverse();
147 segments.extend(prefix_segments);
148 // Insert the type reference (T in the above example) as Self parameter for the trait
149 let mut last_segment = segments.last_mut()?;
150 if last_segment.args_and_bindings.is_none() {
151 last_segment.args_and_bindings =
152 Some(Arc::new(GenericArgs::empty()));
153 };
154 let args = last_segment.args_and_bindings.as_mut().unwrap();
155 let mut args_inner = Arc::make_mut(args);
156 args_inner.has_self_type = true;
157 args_inner.args.insert(0, GenericArg::Type(self_type));
158 }
159 }
160 }
161 ast::PathSegmentKind::CrateKw => {
162 kind = PathKind::Crate;
163 break;
164 }
165 ast::PathSegmentKind::SelfKw => {
166 kind = PathKind::Self_;
167 break;
168 }
169 ast::PathSegmentKind::SuperKw => {
170 kind = PathKind::Super;
171 break;
172 }
173 }
174 path = match qualifier(&path) {
175 Some(it) => it,
176 None => break,
177 };
178 }
179 segments.reverse();
180 return Some(Path { kind, segments });
181
182 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
183 if let Some(q) = path.qualifier() {
184 return Some(q);
185 }
186 // FIXME: this bottom up traversal is not too precise.
187 // Should we handle do a top-down analysis, recording results?
188 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
189 let use_tree = use_tree_list.parent_use_tree();
190 use_tree.path()
191 }
192 }
193
194 /// Converts an `ast::NameRef` into a single-identifier `Path`.
195 pub fn from_name_ref(name_ref: &ast::NameRef) -> Path {
196 name_ref.as_name().into()
197 }
198
199 /// `true` is this path is a single identifier, like `foo`
200 pub fn is_ident(&self) -> bool {
201 self.kind == PathKind::Plain && self.segments.len() == 1
202 }
203
204 /// `true` if this path is just a standalone `self`
205 pub fn is_self(&self) -> bool {
206 self.kind == PathKind::Self_ && self.segments.is_empty()
207 }
208
209 /// If this path is a single identifier, like `foo`, return its name.
210 pub fn as_ident(&self) -> Option<&Name> {
211 if self.kind != PathKind::Plain || self.segments.len() > 1 {
212 return None;
213 }
214 self.segments.first().map(|s| &s.name)
215 }
216
217 pub fn expand_macro_expr(&self) -> Option<Name> {
218 self.as_ident().and_then(|name| Some(name.clone()))
219 }
220
221 pub fn is_type_relative(&self) -> bool {
222 match self.kind {
223 PathKind::Type(_) => true,
224 _ => false,
225 }
226 }
227}
228
229impl GenericArgs {
230 pub fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
231 let mut args = Vec::new();
232 for type_arg in node.type_args() {
233 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
234 args.push(GenericArg::Type(type_ref));
235 }
236 // lifetimes ignored for now
237 let mut bindings = Vec::new();
238 for assoc_type_arg in node.assoc_type_args() {
239 if let Some(name_ref) = assoc_type_arg.name_ref() {
240 let name = name_ref.as_name();
241 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
242 bindings.push((name, type_ref));
243 }
244 }
245 if args.is_empty() && bindings.is_empty() {
246 None
247 } else {
248 Some(GenericArgs { args, has_self_type: false, bindings })
249 }
250 }
251
252 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
253 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
254 pub(crate) fn from_fn_like_path_ast(
255 params: Option<ast::ParamList>,
256 ret_type: Option<ast::RetType>,
257 ) -> Option<GenericArgs> {
258 let mut args = Vec::new();
259 let mut bindings = Vec::new();
260 if let Some(params) = params {
261 let mut param_types = Vec::new();
262 for param in params.params() {
263 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
264 param_types.push(type_ref);
265 }
266 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
267 args.push(arg);
268 }
269 if let Some(ret_type) = ret_type {
270 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
271 bindings.push((name::OUTPUT_TYPE, type_ref))
272 }
273 if args.is_empty() && bindings.is_empty() {
274 None
275 } else {
276 Some(GenericArgs { args, has_self_type: false, bindings })
277 }
278 }
279
280 pub(crate) fn empty() -> GenericArgs {
281 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
282 }
283}
284
285impl From<Name> for Path {
286 fn from(name: Name) -> Path {
287 Path::from_simple_segments(PathKind::Plain, iter::once(name))
288 }
289}
290
291fn expand_use_tree(
292 prefix: Option<Path>,
293 tree: ast::UseTree,
294 hygiene: &Hygiene,
295 cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>),
296) {
297 if let Some(use_tree_list) = tree.use_tree_list() {
298 let prefix = match tree.path() {
299 // E.g. use something::{{{inner}}};
300 None => prefix,
301 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
302 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
303 Some(path) => match convert_path(prefix, path, hygiene) {
304 Some(it) => Some(it),
305 None => return, // FIXME: report errors somewhere
306 },
307 };
308 for child_tree in use_tree_list.use_trees() {
309 expand_use_tree(prefix.clone(), child_tree, hygiene, cb);
310 }
311 } else {
312 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
313 if let Some(ast_path) = tree.path() {
314 // Handle self in a path.
315 // E.g. `use something::{self, <...>}`
316 if ast_path.qualifier().is_none() {
317 if let Some(segment) = ast_path.segment() {
318 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
319 if let Some(prefix) = prefix {
320 cb(prefix, &tree, false, alias);
321 return;
322 }
323 }
324 }
325 }
326 if let Some(path) = convert_path(prefix, ast_path, hygiene) {
327 let is_glob = tree.has_star();
328 cb(path, &tree, is_glob, alias)
329 }
330 // FIXME: report errors somewhere
331 // We get here if we do
332 }
333 }
334}
335
336fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
337 let prefix = if let Some(qual) = path.qualifier() {
338 Some(convert_path(prefix, qual, hygiene)?)
339 } else {
340 prefix
341 };
342
343 let segment = path.segment()?;
344 let res = match segment.kind()? {
345 ast::PathSegmentKind::Name(name_ref) => {
346 match hygiene.name_ref_to_name(name_ref) {
347 Either::A(name) => {
348 // no type args in use
349 let mut res = prefix.unwrap_or_else(|| Path {
350 kind: PathKind::Plain,
351 segments: Vec::with_capacity(1),
352 });
353 res.segments.push(PathSegment {
354 name,
355 args_and_bindings: None, // no type args in use
356 });
357 res
358 }
359 Either::B(crate_id) => {
360 return Some(Path::from_simple_segments(
361 PathKind::DollarCrate(crate_id),
362 iter::empty(),
363 ))
364 }
365 }
366 }
367 ast::PathSegmentKind::CrateKw => {
368 if prefix.is_some() {
369 return None;
370 }
371 Path::from_simple_segments(PathKind::Crate, iter::empty())
372 }
373 ast::PathSegmentKind::SelfKw => {
374 if prefix.is_some() {
375 return None;
376 }
377 Path::from_simple_segments(PathKind::Self_, iter::empty())
378 }
379 ast::PathSegmentKind::SuperKw => {
380 if prefix.is_some() {
381 return None;
382 }
383 Path::from_simple_segments(PathKind::Super, iter::empty())
384 }
385 ast::PathSegmentKind::Type { .. } => {
386 // not allowed in imports
387 return None;
388 }
389 };
390 Some(res)
391}
392
393pub mod known {
394 use hir_expand::name;
395
396 use super::{Path, PathKind};
397
398 pub fn std_iter_into_iterator() -> Path {
399 Path::from_simple_segments(
400 PathKind::Abs,
401 vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE],
402 )
403 }
404
405 pub fn std_ops_try() -> Path {
406 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE])
407 }
408
409 pub fn std_result_result() -> Path {
410 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE])
411 }
412
413 pub fn std_future_future() -> Path {
414 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE])
415 }
416
417 pub fn std_boxed_box() -> Path {
418 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE])
419 }
420}