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