diff options
author | Florian Diebold <[email protected]> | 2019-01-12 23:19:20 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-01-19 15:02:06 +0000 |
commit | 5862542dedd5aca9bbdcba19c5f8cd895591005d (patch) | |
tree | 58fb630e97583db371eed1111d2c067bde2982b4 | |
parent | 688a45e00b53412a7a16360c6d678a5d91a95789 (diff) |
Add AST/HIR for type args in path segments
-rw-r--r-- | crates/ra_hir/src/code_model_impl/module.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 24 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 68 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 128 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 10 |
5 files changed, 217 insertions, 23 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 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
1 | use ra_syntax::{ast, AstNode}; | 3 | use ra_syntax::{ast, AstNode}; |
2 | 4 | ||
3 | use crate::{Name, AsName}; | 5 | use crate::{Name, AsName, type_ref::TypeRef}; |
4 | 6 | ||
5 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 7 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
6 | pub struct Path { | 8 | pub 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)] | ||
14 | pub 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)] | ||
23 | pub 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)] | ||
30 | pub 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 | |||
129 | impl 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 => { |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 271040bf4..9fe946172 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -105,6 +105,38 @@ impl ArrayType { | |||
105 | } | 105 | } |
106 | } | 106 | } |
107 | 107 | ||
108 | // AssocTypeArg | ||
109 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
110 | #[repr(transparent)] | ||
111 | pub struct AssocTypeArg { | ||
112 | pub(crate) syntax: SyntaxNode, | ||
113 | } | ||
114 | unsafe impl TransparentNewType for AssocTypeArg { | ||
115 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
116 | } | ||
117 | |||
118 | impl AstNode for AssocTypeArg { | ||
119 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
120 | match syntax.kind() { | ||
121 | ASSOC_TYPE_ARG => Some(AssocTypeArg::from_repr(syntax.into_repr())), | ||
122 | _ => None, | ||
123 | } | ||
124 | } | ||
125 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
126 | fn to_owned(&self) -> TreeArc<AssocTypeArg> { TreeArc::cast(self.syntax.to_owned()) } | ||
127 | } | ||
128 | |||
129 | |||
130 | impl AssocTypeArg { | ||
131 | pub fn name_ref(&self) -> Option<&NameRef> { | ||
132 | super::child_opt(self) | ||
133 | } | ||
134 | |||
135 | pub fn type_ref(&self) -> Option<&TypeRef> { | ||
136 | super::child_opt(self) | ||
137 | } | ||
138 | } | ||
139 | |||
108 | // Attr | 140 | // Attr |
109 | #[derive(Debug, PartialEq, Eq, Hash)] | 141 | #[derive(Debug, PartialEq, Eq, Hash)] |
110 | #[repr(transparent)] | 142 | #[repr(transparent)] |
@@ -1397,6 +1429,34 @@ impl AstNode for Lifetime { | |||
1397 | impl ast::AstToken for Lifetime {} | 1429 | impl ast::AstToken for Lifetime {} |
1398 | impl Lifetime {} | 1430 | impl Lifetime {} |
1399 | 1431 | ||
1432 | // LifetimeArg | ||
1433 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1434 | #[repr(transparent)] | ||
1435 | pub struct LifetimeArg { | ||
1436 | pub(crate) syntax: SyntaxNode, | ||
1437 | } | ||
1438 | unsafe impl TransparentNewType for LifetimeArg { | ||
1439 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1440 | } | ||
1441 | |||
1442 | impl AstNode for LifetimeArg { | ||
1443 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1444 | match syntax.kind() { | ||
1445 | LIFETIME_ARG => Some(LifetimeArg::from_repr(syntax.into_repr())), | ||
1446 | _ => None, | ||
1447 | } | ||
1448 | } | ||
1449 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1450 | fn to_owned(&self) -> TreeArc<LifetimeArg> { TreeArc::cast(self.syntax.to_owned()) } | ||
1451 | } | ||
1452 | |||
1453 | |||
1454 | impl LifetimeArg { | ||
1455 | pub fn lifetime(&self) -> Option<&Lifetime> { | ||
1456 | super::child_opt(self) | ||
1457 | } | ||
1458 | } | ||
1459 | |||
1400 | // LifetimeParam | 1460 | // LifetimeParam |
1401 | #[derive(Debug, PartialEq, Eq, Hash)] | 1461 | #[derive(Debug, PartialEq, Eq, Hash)] |
1402 | #[repr(transparent)] | 1462 | #[repr(transparent)] |
@@ -2355,6 +2415,10 @@ impl PathSegment { | |||
2355 | pub fn name_ref(&self) -> Option<&NameRef> { | 2415 | pub fn name_ref(&self) -> Option<&NameRef> { |
2356 | super::child_opt(self) | 2416 | super::child_opt(self) |
2357 | } | 2417 | } |
2418 | |||
2419 | pub fn type_arg_list(&self) -> Option<&TypeArgList> { | ||
2420 | super::child_opt(self) | ||
2421 | } | ||
2358 | } | 2422 | } |
2359 | 2423 | ||
2360 | // PathType | 2424 | // PathType |
@@ -3335,6 +3399,70 @@ impl TupleType { | |||
3335 | } | 3399 | } |
3336 | } | 3400 | } |
3337 | 3401 | ||
3402 | // TypeArg | ||
3403 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3404 | #[repr(transparent)] | ||
3405 | pub struct TypeArg { | ||
3406 | pub(crate) syntax: SyntaxNode, | ||
3407 | } | ||
3408 | unsafe impl TransparentNewType for TypeArg { | ||
3409 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3410 | } | ||
3411 | |||
3412 | impl AstNode for TypeArg { | ||
3413 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3414 | match syntax.kind() { | ||
3415 | TYPE_ARG => Some(TypeArg::from_repr(syntax.into_repr())), | ||
3416 | _ => None, | ||
3417 | } | ||
3418 | } | ||
3419 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3420 | fn to_owned(&self) -> TreeArc<TypeArg> { TreeArc::cast(self.syntax.to_owned()) } | ||
3421 | } | ||
3422 | |||
3423 | |||
3424 | impl TypeArg { | ||
3425 | pub fn type_ref(&self) -> Option<&TypeRef> { | ||
3426 | super::child_opt(self) | ||
3427 | } | ||
3428 | } | ||
3429 | |||
3430 | // TypeArgList | ||
3431 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
3432 | #[repr(transparent)] | ||
3433 | pub struct TypeArgList { | ||
3434 | pub(crate) syntax: SyntaxNode, | ||
3435 | } | ||
3436 | unsafe impl TransparentNewType for TypeArgList { | ||
3437 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
3438 | } | ||
3439 | |||
3440 | impl AstNode for TypeArgList { | ||
3441 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
3442 | match syntax.kind() { | ||
3443 | TYPE_ARG_LIST => Some(TypeArgList::from_repr(syntax.into_repr())), | ||
3444 | _ => None, | ||
3445 | } | ||
3446 | } | ||
3447 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
3448 | fn to_owned(&self) -> TreeArc<TypeArgList> { TreeArc::cast(self.syntax.to_owned()) } | ||
3449 | } | ||
3450 | |||
3451 | |||
3452 | impl TypeArgList { | ||
3453 | pub fn type_args(&self) -> impl Iterator<Item = &TypeArg> { | ||
3454 | super::children(self) | ||
3455 | } | ||
3456 | |||
3457 | pub fn lifetime_args(&self) -> impl Iterator<Item = &LifetimeArg> { | ||
3458 | super::children(self) | ||
3459 | } | ||
3460 | |||
3461 | pub fn assoc_type_args(&self) -> impl Iterator<Item = &AssocTypeArg> { | ||
3462 | super::children(self) | ||
3463 | } | ||
3464 | } | ||
3465 | |||
3338 | // TypeDef | 3466 | // TypeDef |
3339 | #[derive(Debug, PartialEq, Eq, Hash)] | 3467 | #[derive(Debug, PartialEq, Eq, Hash)] |
3340 | #[repr(transparent)] | 3468 | #[repr(transparent)] |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index fc47c36d3..0385183fd 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -597,8 +597,16 @@ Grammar( | |||
597 | ] | 597 | ] |
598 | ), | 598 | ), |
599 | "PathSegment": ( | 599 | "PathSegment": ( |
600 | options: [ "NameRef" ] | 600 | options: [ "NameRef", "TypeArgList" ] |
601 | ), | 601 | ), |
602 | "TypeArgList": (collections: [ | ||
603 | ["type_args", "TypeArg"], | ||
604 | ["lifetime_args", "LifetimeArg"], | ||
605 | ["assoc_type_args", "AssocTypeArg"], | ||
606 | ]), | ||
607 | "TypeArg": (options: ["TypeRef"]), | ||
608 | "AssocTypeArg": (options: ["NameRef", "TypeRef"]), | ||
609 | "LifetimeArg": (options: ["Lifetime"]), | ||
602 | "Comment": ( traits: ["AstToken"] ), | 610 | "Comment": ( traits: ["AstToken"] ), |
603 | "Whitespace": ( traits: ["AstToken"] ), | 611 | "Whitespace": ( traits: ["AstToken"] ), |
604 | }, | 612 | }, |