aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-01-12 23:19:20 +0000
committerFlorian Diebold <[email protected]>2019-01-19 15:02:06 +0000
commit5862542dedd5aca9bbdcba19c5f8cd895591005d (patch)
tree58fb630e97583db371eed1111d2c067bde2982b4 /crates/ra_hir/src
parent688a45e00b53412a7a16360c6d678a5d91a95789 (diff)
Add AST/HIR for type args in path segments
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs10
-rw-r--r--crates/ra_hir/src/nameres.rs24
-rw-r--r--crates/ra_hir/src/path.rs68
3 files changed, 80 insertions, 22 deletions
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 7215236f9..2014f1090 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -147,7 +147,7 @@ impl Module {
147 .def_id, 147 .def_id,
148 ); 148 );
149 149
150 for name in path.segments.iter() { 150 for segment in path.segments.iter() {
151 let curr = match curr_per_ns.as_ref().take_types() { 151 let curr = match curr_per_ns.as_ref().take_types() {
152 Some(r) => r, 152 Some(r) => r,
153 None => { 153 None => {
@@ -163,15 +163,17 @@ impl Module {
163 curr_per_ns = match curr.resolve(db) { 163 curr_per_ns = match curr.resolve(db) {
164 Def::Module(m) => { 164 Def::Module(m) => {
165 let scope = m.scope(db); 165 let scope = m.scope(db);
166 match scope.get(&name) { 166 match scope.get(&segment.name) {
167 Some(r) => r.def_id, 167 Some(r) => r.def_id,
168 None => PerNs::none(), 168 None => PerNs::none(),
169 } 169 }
170 } 170 }
171 Def::Enum(e) => { 171 Def::Enum(e) => {
172 // enum variant 172 // enum variant
173 let matching_variant = 173 let matching_variant = e
174 e.variants(db).into_iter().find(|(n, _variant)| n == name); 174 .variants(db)
175 .into_iter()
176 .find(|(n, _variant)| n == &segment.name);
175 177
176 match matching_variant { 178 match matching_variant {
177 Some((_n, variant)) => PerNs::both(variant.def_id(), e.def_id()), 179 Some((_n, variant)) => PerNs::both(variant.def_id(), e.def_id()),
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 4efafd409..4874e82f3 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -221,10 +221,10 @@ where
221 }; 221 };
222 } 222 }
223 for (import_id, import_data) in input.imports.iter() { 223 for (import_id, import_data) in input.imports.iter() {
224 if let Some(name) = import_data.path.segments.iter().last() { 224 if let Some(segment) = import_data.path.segments.iter().last() {
225 if !import_data.is_glob { 225 if !import_data.is_glob {
226 module_items.items.insert( 226 module_items.items.insert(
227 name.clone(), 227 segment.name.clone(),
228 Resolution { 228 Resolution {
229 def_id: PerNs::none(), 229 def_id: PerNs::none(),
230 import: Some(import_id), 230 import: Some(import_id),
@@ -319,13 +319,13 @@ where
319 PathKind::Crate => module_id.crate_root(&self.module_tree), 319 PathKind::Crate => module_id.crate_root(&self.module_tree),
320 }; 320 };
321 321
322 for (i, name) in import.path.segments.iter().enumerate() { 322 for (i, segment) in import.path.segments.iter().enumerate() {
323 let is_last = i == import.path.segments.len() - 1; 323 let is_last = i == import.path.segments.len() - 1;
324 324
325 let def_id = match self.result.per_module[&curr].items.get(name) { 325 let def_id = match self.result.per_module[&curr].items.get(&segment.name) {
326 Some(res) if !res.def_id.is_none() => res.def_id, 326 Some(res) if !res.def_id.is_none() => res.def_id,
327 _ => { 327 _ => {
328 log::debug!("path segment {:?} not found", name); 328 log::debug!("path segment {:?} not found", segment.name);
329 return false; 329 return false;
330 } 330 }
331 }; 331 };
@@ -336,7 +336,7 @@ where
336 } else { 336 } else {
337 log::debug!( 337 log::debug!(
338 "path segment {:?} resolved to value only, but is not last", 338 "path segment {:?} resolved to value only, but is not last",
339 name 339 segment.name
340 ); 340 );
341 return false; 341 return false;
342 }; 342 };
@@ -358,17 +358,17 @@ where
358 log::debug!("resolving {:?} in other source root", path); 358 log::debug!("resolving {:?} in other source root", path);
359 let def_id = module.resolve_path(self.db, &path); 359 let def_id = module.resolve_path(self.db, &path);
360 if !def_id.is_none() { 360 if !def_id.is_none() {
361 let name = path.segments.last().unwrap(); 361 let last_segment = path.segments.last().unwrap();
362 self.update(module_id, |items| { 362 self.update(module_id, |items| {
363 let res = Resolution { 363 let res = Resolution {
364 def_id, 364 def_id,
365 import: Some(import_id), 365 import: Some(import_id),
366 }; 366 };
367 items.items.insert(name.clone(), res); 367 items.items.insert(last_segment.name.clone(), res);
368 }); 368 });
369 log::debug!( 369 log::debug!(
370 "resolved import {:?} ({:?}) cross-source root to {:?}", 370 "resolved import {:?} ({:?}) cross-source root to {:?}",
371 name, 371 last_segment.name,
372 import, 372 import,
373 def_id.map(|did| did.loc(self.db)) 373 def_id.map(|did| did.loc(self.db))
374 ); 374 );
@@ -382,7 +382,7 @@ where
382 _ => { 382 _ => {
383 log::debug!( 383 log::debug!(
384 "path segment {:?} resolved to non-module {:?}, but is not last", 384 "path segment {:?} resolved to non-module {:?}, but is not last",
385 name, 385 segment.name,
386 type_def_id.loc(self.db) 386 type_def_id.loc(self.db)
387 ); 387 );
388 return true; // this resolved to a non-module, so the path won't ever resolve 388 return true; // this resolved to a non-module, so the path won't ever resolve
@@ -391,7 +391,7 @@ where
391 } else { 391 } else {
392 log::debug!( 392 log::debug!(
393 "resolved import {:?} ({:?}) within source root to {:?}", 393 "resolved import {:?} ({:?}) within source root to {:?}",
394 name, 394 segment.name,
395 import, 395 import,
396 def_id.map(|did| did.loc(self.db)) 396 def_id.map(|did| did.loc(self.db))
397 ); 397 );
@@ -400,7 +400,7 @@ where
400 def_id, 400 def_id,
401 import: Some(import_id), 401 import: Some(import_id),
402 }; 402 };
403 items.items.insert(name.clone(), res); 403 items.items.insert(segment.name.clone(), res);
404 }) 404 })
405 } 405 }
406 } 406 }
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 7b0ce3b61..c3d14c689 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -1,11 +1,35 @@
1use std::sync::Arc;
2
1use ra_syntax::{ast, AstNode}; 3use ra_syntax::{ast, AstNode};
2 4
3use crate::{Name, AsName}; 5use crate::{Name, AsName, type_ref::TypeRef};
4 6
5#[derive(Debug, Clone, PartialEq, Eq, Hash)] 7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
6pub struct Path { 8pub struct Path {
7 pub kind: PathKind, 9 pub kind: PathKind,
8 pub segments: Vec<Name>, 10 pub segments: Vec<PathSegment>,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct PathSegment {
15 pub name: Name,
16 pub args_and_bindings: Option<Arc<GenericArgs>>,
17}
18
19/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
20/// can (in the future) also include bindings of associated types, like in
21/// `Iterator<Item = Foo>`.
22#[derive(Debug, Clone, PartialEq, Eq, Hash)]
23pub struct GenericArgs {
24 pub args: Vec<GenericArg>,
25 // someday also bindings
26}
27
28/// A single generic argument.
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
30pub enum GenericArg {
31 Type(TypeRef),
32 // or lifetime...
9} 33}
10 34
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -34,7 +58,17 @@ impl Path {
34 loop { 58 loop {
35 let segment = path.segment()?; 59 let segment = path.segment()?;
36 match segment.kind()? { 60 match segment.kind()? {
37 ast::PathSegmentKind::Name(name) => segments.push(name.as_name()), 61 ast::PathSegmentKind::Name(name) => {
62 let args = segment
63 .type_arg_list()
64 .and_then(GenericArgs::from_ast)
65 .map(Arc::new);
66 let segment = PathSegment {
67 name: name.as_name(),
68 args_and_bindings: args,
69 };
70 segments.push(segment);
71 }
38 ast::PathSegmentKind::CrateKw => { 72 ast::PathSegmentKind::CrateKw => {
39 kind = PathKind::Crate; 73 kind = PathKind::Crate;
40 break; 74 break;
@@ -88,7 +122,23 @@ impl Path {
88 if self.kind != PathKind::Plain || self.segments.len() > 1 { 122 if self.kind != PathKind::Plain || self.segments.len() > 1 {
89 return None; 123 return None;
90 } 124 }
91 self.segments.first() 125 self.segments.first().map(|s| &s.name)
126 }
127}
128
129impl GenericArgs {
130 fn from_ast(node: &ast::TypeArgList) -> Option<GenericArgs> {
131 let mut args = Vec::new();
132 for type_arg in node.type_args() {
133 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
134 args.push(GenericArg::Type(type_ref));
135 }
136 // lifetimes and assoc type args ignored for now
137 if args.len() > 0 {
138 Some(GenericArgs { args })
139 } else {
140 None
141 }
92 } 142 }
93} 143}
94 144
@@ -96,7 +146,10 @@ impl From<Name> for Path {
96 fn from(name: Name) -> Path { 146 fn from(name: Name) -> Path {
97 Path { 147 Path {
98 kind: PathKind::Plain, 148 kind: PathKind::Plain,
99 segments: vec![name], 149 segments: vec![PathSegment {
150 name,
151 args_and_bindings: None,
152 }],
100 } 153 }
101 } 154 }
102} 155}
@@ -160,7 +213,10 @@ fn convert_path(prefix: Option<Path>, path: &ast::Path) -> Option<Path> {
160 kind: PathKind::Plain, 213 kind: PathKind::Plain,
161 segments: Vec::with_capacity(1), 214 segments: Vec::with_capacity(1),
162 }); 215 });
163 res.segments.push(name.as_name()); 216 res.segments.push(PathSegment {
217 name: name.as_name(),
218 args_and_bindings: None, // no type args in use
219 });
164 res 220 res
165 } 221 }
166 ast::PathSegmentKind::CrateKw => { 222 ast::PathSegmentKind::CrateKw => {