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.rs345
1 files changed, 145 insertions, 200 deletions
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 1e9eb14ea..20d6d98ea 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -1,31 +1,78 @@
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_use; 2mod lower;
3 3
4use std::{iter, sync::Arc}; 4use std::{iter, sync::Arc};
5 5
6use either::Either;
7use hir_expand::{ 6use hir_expand::{
8 hygiene::Hygiene, 7 hygiene::Hygiene,
9 name::{name, AsName, Name}, 8 name::{AsName, Name},
10}; 9};
11use ra_db::CrateId; 10use ra_db::CrateId;
12use ra_syntax::{ 11use ra_syntax::ast;
13 ast::{self, TypeAscriptionOwner},
14 AstNode,
15};
16 12
17use crate::{type_ref::TypeRef, InFile}; 13use crate::{type_ref::TypeRef, InFile};
18 14
19#[derive(Debug, Clone, PartialEq, Eq, Hash)] 15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub struct Path { 16pub struct ModPath {
21 pub kind: PathKind, 17 pub kind: PathKind,
22 pub segments: Vec<PathSegment>, 18 pub segments: Vec<Name>,
19}
20
21impl ModPath {
22 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
23 lower::lower_path(path, hygiene).map(|it| it.mod_path)
24 }
25
26 pub fn from_simple_segments(
27 kind: PathKind,
28 segments: impl IntoIterator<Item = Name>,
29 ) -> ModPath {
30 let segments = segments.into_iter().collect::<Vec<_>>();
31 ModPath { kind, segments }
32 }
33
34 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
35 name_ref.as_name().into()
36 }
37
38 /// Converts an `tt::Ident` into a single-identifier `Path`.
39 pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
40 ident.as_name().into()
41 }
42
43 /// Calls `cb` with all paths, represented by this use item.
44 pub(crate) fn expand_use_item(
45 item_src: InFile<ast::UseItem>,
46 hygiene: &Hygiene,
47 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
48 ) {
49 if let Some(tree) = item_src.value.use_tree() {
50 lower::lower_use_tree(None, tree, hygiene, &mut cb);
51 }
52 }
53
54 pub fn is_ident(&self) -> bool {
55 self.kind == PathKind::Plain && self.segments.len() == 1
56 }
57
58 pub fn is_self(&self) -> bool {
59 self.kind == PathKind::Self_ && self.segments.is_empty()
60 }
61
62 /// If this path is a single identifier, like `foo`, return its name.
63 pub fn as_ident(&self) -> Option<&Name> {
64 if self.kind != PathKind::Plain || self.segments.len() > 1 {
65 return None;
66 }
67 self.segments.first()
68 }
23} 69}
24 70
25#[derive(Debug, Clone, PartialEq, Eq, Hash)] 71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
26pub struct PathSegment { 72pub struct Path {
27 pub name: Name, 73 mod_path: ModPath,
28 pub args_and_bindings: Option<Arc<GenericArgs>>, 74 /// Invariant: the same len as self.path.segments
75 generic_args: Vec<Option<Arc<GenericArgs>>>,
29} 76}
30 77
31/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This 78/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
@@ -65,221 +112,110 @@ pub enum PathKind {
65} 112}
66 113
67impl Path { 114impl Path {
68 /// Calls `cb` with all paths, represented by this use item.
69 pub(crate) fn expand_use_item(
70 item_src: InFile<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 lower_use::lower_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. 115 /// Converts an `ast::Path` to `Path`. Works with use trees.
90 /// DEPRECATED: It does not handle `$crate` from macro call. 116 /// DEPRECATED: It does not handle `$crate` from macro call.
91 pub fn from_ast(path: ast::Path) -> Option<Path> { 117 pub fn from_ast(path: ast::Path) -> Option<Path> {
92 Path::from_src(path, &Hygiene::new_unhygienic()) 118 lower::lower_path(path, &Hygiene::new_unhygienic())
93 } 119 }
94 120
95 /// Converts an `ast::Path` to `Path`. Works with use trees. 121 /// Converts an `ast::Path` to `Path`. Works with use trees.
96 /// It correctly handles `$crate` based path from macro call. 122 /// It correctly handles `$crate` based path from macro call.
97 pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 123 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
98 let mut kind = PathKind::Plain; 124 lower::lower_path(path, hygiene)
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::Left(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::Right(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 } 125 }
193 126
194 /// Converts an `ast::NameRef` into a single-identifier `Path`. 127 /// Converts an `ast::NameRef` into a single-identifier `Path`.
195 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { 128 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
196 name_ref.as_name().into() 129 Path { mod_path: name_ref.as_name().into(), generic_args: vec![None] }
197 } 130 }
198 131
199 /// Converts an `tt::Ident` into a single-identifier `Path`. 132 /// `true` if this path is just a standalone `self`
200 pub(crate) fn from_tt_ident(ident: &tt::Ident) -> Path { 133 pub fn is_self(&self) -> bool {
201 ident.as_name().into() 134 self.mod_path.is_self()
202 } 135 }
203 136
204 /// `true` is this path is a single identifier, like `foo` 137 pub fn kind(&self) -> &PathKind {
205 pub fn is_ident(&self) -> bool { 138 &self.mod_path.kind
206 self.kind == PathKind::Plain && self.segments.len() == 1
207 } 139 }
208 140
209 /// `true` if this path is just a standalone `self` 141 pub fn segments(&self) -> PathSegments<'_> {
210 pub fn is_self(&self) -> bool { 142 PathSegments {
211 self.kind == PathKind::Self_ && self.segments.is_empty() 143 segments: self.mod_path.segments.as_slice(),
144 generic_args: self.generic_args.as_slice(),
145 }
212 } 146 }
213 147
214 /// If this path is a single identifier, like `foo`, return its name. 148 pub fn mod_path(&self) -> &ModPath {
215 pub fn as_ident(&self) -> Option<&Name> { 149 &self.mod_path
216 if self.kind != PathKind::Plain || self.segments.len() > 1 { 150 }
151
152 pub fn qualifier(&self) -> Option<Path> {
153 if self.mod_path.is_ident() {
217 return None; 154 return None;
218 } 155 }
219 self.segments.first().map(|s| &s.name) 156 let res = Path {
157 mod_path: ModPath {
158 kind: self.mod_path.kind.clone(),
159 segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
160 },
161 generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
162 };
163 Some(res)
220 } 164 }
165}
221 166
222 pub fn expand_macro_expr(&self) -> Option<Name> { 167#[derive(Debug, Clone, PartialEq, Eq, Hash)]
223 self.as_ident().and_then(|name| Some(name.clone())) 168pub struct PathSegment<'a> {
224 } 169 pub name: &'a Name,
170 pub args_and_bindings: Option<&'a GenericArgs>,
171}
225 172
226 pub fn is_type_relative(&self) -> bool { 173pub struct PathSegments<'a> {
227 match self.kind { 174 segments: &'a [Name],
228 PathKind::Type(_) => true, 175 generic_args: &'a [Option<Arc<GenericArgs>>],
229 _ => false, 176}
230 } 177
178impl<'a> PathSegments<'a> {
179 pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
180 pub fn is_empty(&self) -> bool {
181 self.len() == 0
182 }
183 pub fn len(&self) -> usize {
184 self.segments.len()
185 }
186 pub fn first(&self) -> Option<PathSegment<'a>> {
187 self.get(0)
188 }
189 pub fn last(&self) -> Option<PathSegment<'a>> {
190 self.get(self.len().checked_sub(1)?)
191 }
192 pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
193 assert_eq!(self.segments.len(), self.generic_args.len());
194 let res = PathSegment {
195 name: self.segments.get(idx)?,
196 args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
197 };
198 Some(res)
199 }
200 pub fn skip(&self, len: usize) -> PathSegments<'a> {
201 assert_eq!(self.segments.len(), self.generic_args.len());
202 PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
203 }
204 pub fn take(&self, len: usize) -> PathSegments<'a> {
205 assert_eq!(self.segments.len(), self.generic_args.len());
206 PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
207 }
208 pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
209 self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
210 name,
211 args_and_bindings: args.as_ref().map(|it| &**it),
212 })
231 } 213 }
232} 214}
233 215
234impl GenericArgs { 216impl GenericArgs {
235 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> { 217 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
236 let mut args = Vec::new(); 218 lower::lower_generic_args(node)
237 for type_arg in node.type_args() {
238 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
239 args.push(GenericArg::Type(type_ref));
240 }
241 // lifetimes ignored for now
242 let mut bindings = Vec::new();
243 for assoc_type_arg in node.assoc_type_args() {
244 if let Some(name_ref) = assoc_type_arg.name_ref() {
245 let name = name_ref.as_name();
246 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
247 bindings.push((name, type_ref));
248 }
249 }
250 if args.is_empty() && bindings.is_empty() {
251 None
252 } else {
253 Some(GenericArgs { args, has_self_type: false, bindings })
254 }
255 }
256
257 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
258 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
259 pub(crate) fn from_fn_like_path_ast(
260 params: Option<ast::ParamList>,
261 ret_type: Option<ast::RetType>,
262 ) -> Option<GenericArgs> {
263 let mut args = Vec::new();
264 let mut bindings = Vec::new();
265 if let Some(params) = params {
266 let mut param_types = Vec::new();
267 for param in params.params() {
268 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
269 param_types.push(type_ref);
270 }
271 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
272 args.push(arg);
273 }
274 if let Some(ret_type) = ret_type {
275 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
276 bindings.push((name![Output], type_ref))
277 }
278 if args.is_empty() && bindings.is_empty() {
279 None
280 } else {
281 Some(GenericArgs { args, has_self_type: false, bindings })
282 }
283 } 219 }
284 220
285 pub(crate) fn empty() -> GenericArgs { 221 pub(crate) fn empty() -> GenericArgs {
@@ -289,7 +225,16 @@ impl GenericArgs {
289 225
290impl From<Name> for Path { 226impl From<Name> for Path {
291 fn from(name: Name) -> Path { 227 fn from(name: Name) -> Path {
292 Path::from_simple_segments(PathKind::Plain, iter::once(name)) 228 Path {
229 mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
230 generic_args: vec![None],
231 }
232 }
233}
234
235impl From<Name> for ModPath {
236 fn from(name: Name) -> ModPath {
237 ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
293 } 238 }
294} 239}
295 240
@@ -319,7 +264,7 @@ macro_rules! __known_path {
319macro_rules! __path { 264macro_rules! __path {
320 ($start:ident $(:: $seg:ident)*) => ({ 265 ($start:ident $(:: $seg:ident)*) => ({
321 $crate::__known_path!($start $(:: $seg)*); 266 $crate::__known_path!($start $(:: $seg)*);
322 $crate::path::Path::from_simple_segments($crate::path::PathKind::Abs, vec![ 267 $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
323 $crate::path::__name![$start], $($crate::path::__name![$seg],)* 268 $crate::path::__name![$start], $($crate::path::__name![$seg],)*
324 ]) 269 ])
325 }); 270 });