diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/auto_import.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/validation.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 100 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 127 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 58 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 2 |
12 files changed, 235 insertions, 148 deletions
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index 1158adbbc..5aae98546 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs | |||
@@ -504,7 +504,7 @@ fn apply_auto_import( | |||
504 | } | 504 | } |
505 | } | 505 | } |
506 | 506 | ||
507 | pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> { | 507 | pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { |
508 | let mut ps = Vec::<SmolStr>::with_capacity(10); | 508 | let mut ps = Vec::<SmolStr>::with_capacity(10); |
509 | match path.kind { | 509 | match path.kind { |
510 | hir::PathKind::Abs => ps.push("".into()), | 510 | hir::PathKind::Abs => ps.push("".into()), |
@@ -512,11 +512,12 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> { | |||
512 | hir::PathKind::Plain => {} | 512 | hir::PathKind::Plain => {} |
513 | hir::PathKind::Self_ => ps.push("self".into()), | 513 | hir::PathKind::Self_ => ps.push("self".into()), |
514 | hir::PathKind::Super => ps.push("super".into()), | 514 | hir::PathKind::Super => ps.push("super".into()), |
515 | hir::PathKind::Type(_) => return None, | ||
515 | } | 516 | } |
516 | for s in path.segments.iter() { | 517 | for s in path.segments.iter() { |
517 | ps.push(s.name.to_string().into()); | 518 | ps.push(s.name.to_string().into()); |
518 | } | 519 | } |
519 | ps | 520 | Some(ps) |
520 | } | 521 | } |
521 | 522 | ||
522 | // This function produces sequence of text edits into edit | 523 | // This function produces sequence of text edits into edit |
@@ -552,7 +553,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist | |||
552 | } | 553 | } |
553 | 554 | ||
554 | let hir_path = hir::Path::from_ast(path.clone())?; | 555 | let hir_path = hir::Path::from_ast(path.clone())?; |
555 | let segments = collect_hir_path_segments(&hir_path); | 556 | let segments = collect_hir_path_segments(&hir_path)?; |
556 | if segments.len() < 2 { | 557 | if segments.len() < 2 { |
557 | return None; | 558 | return None; |
558 | } | 559 | } |
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index 030ec53a2..f06e5ec07 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs | |||
@@ -7,8 +7,7 @@ use crate::{ | |||
7 | db::HirDatabase, | 7 | db::HirDatabase, |
8 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, | 8 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, |
9 | expr::AstPtr, | 9 | expr::AstPtr, |
10 | name, | 10 | path::known, |
11 | path::{PathKind, PathSegment}, | ||
12 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, | 11 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, |
13 | Adt, Function, Name, Path, | 12 | Adt, Function, Name, Path, |
14 | }; | 13 | }; |
@@ -108,14 +107,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
108 | None => return, | 107 | None => return, |
109 | }; | 108 | }; |
110 | 109 | ||
111 | let std_result_path = Path { | 110 | let std_result_path = known::std_result_result(); |
112 | kind: PathKind::Abs, | ||
113 | segments: vec![ | ||
114 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
115 | PathSegment { name: name::RESULT_MOD, args_and_bindings: None }, | ||
116 | PathSegment { name: name::RESULT_TYPE, args_and_bindings: None }, | ||
117 | ], | ||
118 | }; | ||
119 | 111 | ||
120 | let resolver = self.func.resolver(db); | 112 | let resolver = self.func.resolver(db); |
121 | let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { | 113 | let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { |
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index abdfec296..1bf993ffb 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -85,6 +85,7 @@ impl AsName for ra_db::Dependency { | |||
85 | } | 85 | } |
86 | } | 86 | } |
87 | 87 | ||
88 | // Primitives | ||
88 | pub(crate) const ISIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"isize")); | 89 | pub(crate) const ISIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"isize")); |
89 | pub(crate) const I8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"i8")); | 90 | pub(crate) const I8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"i8")); |
90 | pub(crate) const I16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i16")); | 91 | pub(crate) const I16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i16")); |
@@ -102,24 +103,30 @@ pub(crate) const F64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f64") | |||
102 | pub(crate) const BOOL: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"bool")); | 103 | pub(crate) const BOOL: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"bool")); |
103 | pub(crate) const CHAR: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"char")); | 104 | pub(crate) const CHAR: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"char")); |
104 | pub(crate) const STR: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"str")); | 105 | pub(crate) const STR: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"str")); |
106 | |||
107 | // Special names | ||
105 | pub(crate) const SELF_PARAM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"self")); | 108 | pub(crate) const SELF_PARAM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"self")); |
106 | pub(crate) const SELF_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Self")); | 109 | pub(crate) const SELF_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Self")); |
107 | pub(crate) const MACRO_RULES: Name = Name::new(SmolStr::new_inline_from_ascii(11, b"macro_rules")); | 110 | pub(crate) const MACRO_RULES: Name = Name::new(SmolStr::new_inline_from_ascii(11, b"macro_rules")); |
111 | |||
112 | // Components of known path (value or mod name) | ||
108 | pub(crate) const STD: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"std")); | 113 | pub(crate) const STD: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"std")); |
109 | pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter")); | 114 | pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter")); |
110 | pub(crate) const INTO_ITERATOR: Name = | ||
111 | Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); | ||
112 | pub(crate) const ITEM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); | ||
113 | pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops")); | 115 | pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops")); |
114 | pub(crate) const TRY: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")); | 116 | pub(crate) const FUTURE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); |
115 | pub(crate) const OK: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); | 117 | pub(crate) const RESULT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); |
116 | pub(crate) const FUTURE_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); | 118 | pub(crate) const BOXED: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed")); |
119 | |||
120 | // Components of known path (type name) | ||
121 | pub(crate) const INTO_ITERATOR_TYPE: Name = | ||
122 | Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); | ||
123 | pub(crate) const ITEM_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); | ||
124 | pub(crate) const TRY_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")); | ||
125 | pub(crate) const OK_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); | ||
117 | pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); | 126 | pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); |
118 | pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); | ||
119 | pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); | 127 | pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); |
120 | pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); | 128 | pub(crate) const OUTPUT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); |
121 | pub(crate) const TARGET: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); | 129 | pub(crate) const TARGET_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); |
122 | pub(crate) const BOXED_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed")); | ||
123 | pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box")); | 130 | pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box")); |
124 | 131 | ||
125 | fn resolve_name(text: &SmolStr) -> SmolStr { | 132 | fn resolve_name(text: &SmolStr) -> SmolStr { |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 7922e3f7e..b808a0c36 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -382,6 +382,11 @@ impl CrateDefMap { | |||
382 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | 382 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude |
383 | } | 383 | } |
384 | } | 384 | } |
385 | PathKind::Type(_) => { | ||
386 | // This is handled in `infer::infer_path_expr` | ||
387 | // The result returned here does not matter | ||
388 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
389 | } | ||
385 | }; | 390 | }; |
386 | 391 | ||
387 | for (i, segment) in segments { | 392 | for (i, segment) in segments { |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index d6c78593b..a61161b63 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use std::sync::Arc; | 1 | use std::{iter, sync::Arc}; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, NameOwner, TypeAscriptionOwner}, | 4 | ast::{self, NameOwner, TypeAscriptionOwner}, |
@@ -42,7 +42,7 @@ pub enum GenericArg { | |||
42 | // or lifetime... | 42 | // or lifetime... |
43 | } | 43 | } |
44 | 44 | ||
45 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 45 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
46 | pub enum PathKind { | 46 | pub enum PathKind { |
47 | Plain, | 47 | Plain, |
48 | Self_, | 48 | Self_, |
@@ -50,6 +50,8 @@ pub enum PathKind { | |||
50 | Crate, | 50 | Crate, |
51 | // Absolute path | 51 | // Absolute path |
52 | Abs, | 52 | Abs, |
53 | // Type based path like `<T>::foo` | ||
54 | Type(Box<TypeRef>), | ||
53 | } | 55 | } |
54 | 56 | ||
55 | impl Path { | 57 | impl Path { |
@@ -63,6 +65,16 @@ impl Path { | |||
63 | } | 65 | } |
64 | } | 66 | } |
65 | 67 | ||
68 | pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path { | ||
69 | Path { | ||
70 | kind, | ||
71 | segments: segments | ||
72 | .into_iter() | ||
73 | .map(|name| PathSegment { name, args_and_bindings: None }) | ||
74 | .collect(), | ||
75 | } | ||
76 | } | ||
77 | |||
66 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 78 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
67 | pub fn from_ast(mut path: ast::Path) -> Option<Path> { | 79 | pub fn from_ast(mut path: ast::Path) -> Option<Path> { |
68 | let mut kind = PathKind::Plain; | 80 | let mut kind = PathKind::Plain; |
@@ -92,24 +104,32 @@ impl Path { | |||
92 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | 104 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { |
93 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | 105 | assert!(path.qualifier().is_none()); // this can only occur at the first segment |
94 | 106 | ||
95 | // FIXME: handle <T> syntax (type segments without trait) | ||
96 | |||
97 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | ||
98 | let path = Path::from_ast(trait_ref?.path()?)?; | ||
99 | kind = path.kind; | ||
100 | let mut prefix_segments = path.segments; | ||
101 | prefix_segments.reverse(); | ||
102 | segments.extend(prefix_segments); | ||
103 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
104 | let self_type = TypeRef::from_ast(type_ref?); | 107 | let self_type = TypeRef::from_ast(type_ref?); |
105 | let mut last_segment = segments.last_mut()?; | 108 | |
106 | if last_segment.args_and_bindings.is_none() { | 109 | match trait_ref { |
107 | last_segment.args_and_bindings = Some(Arc::new(GenericArgs::empty())); | 110 | // <T>::foo |
108 | }; | 111 | None => { |
109 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | 112 | kind = PathKind::Type(Box::new(self_type)); |
110 | let mut args_inner = Arc::make_mut(args); | 113 | } |
111 | args_inner.has_self_type = true; | 114 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo |
112 | args_inner.args.insert(0, GenericArg::Type(self_type)); | 115 | Some(trait_ref) => { |
116 | let path = Path::from_ast(trait_ref.path()?)?; | ||
117 | kind = path.kind; | ||
118 | let mut prefix_segments = path.segments; | ||
119 | prefix_segments.reverse(); | ||
120 | segments.extend(prefix_segments); | ||
121 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
122 | let mut last_segment = segments.last_mut()?; | ||
123 | if last_segment.args_and_bindings.is_none() { | ||
124 | last_segment.args_and_bindings = | ||
125 | Some(Arc::new(GenericArgs::empty())); | ||
126 | }; | ||
127 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | ||
128 | let mut args_inner = Arc::make_mut(args); | ||
129 | args_inner.has_self_type = true; | ||
130 | args_inner.args.insert(0, GenericArg::Type(self_type)); | ||
131 | } | ||
132 | } | ||
113 | } | 133 | } |
114 | ast::PathSegmentKind::CrateKw => { | 134 | ast::PathSegmentKind::CrateKw => { |
115 | kind = PathKind::Crate; | 135 | kind = PathKind::Crate; |
@@ -214,7 +234,7 @@ impl GenericArgs { | |||
214 | } | 234 | } |
215 | if let Some(ret_type) = ret_type { | 235 | if let Some(ret_type) = ret_type { |
216 | let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); | 236 | let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); |
217 | bindings.push((name::OUTPUT, type_ref)) | 237 | bindings.push((name::OUTPUT_TYPE, type_ref)) |
218 | } | 238 | } |
219 | if args.is_empty() && bindings.is_empty() { | 239 | if args.is_empty() && bindings.is_empty() { |
220 | None | 240 | None |
@@ -230,10 +250,7 @@ impl GenericArgs { | |||
230 | 250 | ||
231 | impl From<Name> for Path { | 251 | impl From<Name> for Path { |
232 | fn from(name: Name) -> Path { | 252 | fn from(name: Name) -> Path { |
233 | Path { | 253 | Path::from_simple_segments(PathKind::Plain, iter::once(name)) |
234 | kind: PathKind::Plain, | ||
235 | segments: vec![PathSegment { name, args_and_bindings: None }], | ||
236 | } | ||
237 | } | 254 | } |
238 | } | 255 | } |
239 | 256 | ||
@@ -287,6 +304,7 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
287 | let segment = path.segment()?; | 304 | let segment = path.segment()?; |
288 | let res = match segment.kind()? { | 305 | let res = match segment.kind()? { |
289 | ast::PathSegmentKind::Name(name) => { | 306 | ast::PathSegmentKind::Name(name) => { |
307 | // no type args in use | ||
290 | let mut res = prefix | 308 | let mut res = prefix |
291 | .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); | 309 | .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); |
292 | res.segments.push(PathSegment { | 310 | res.segments.push(PathSegment { |
@@ -299,19 +317,19 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
299 | if prefix.is_some() { | 317 | if prefix.is_some() { |
300 | return None; | 318 | return None; |
301 | } | 319 | } |
302 | Path { kind: PathKind::Crate, segments: Vec::new() } | 320 | Path::from_simple_segments(PathKind::Crate, iter::empty()) |
303 | } | 321 | } |
304 | ast::PathSegmentKind::SelfKw => { | 322 | ast::PathSegmentKind::SelfKw => { |
305 | if prefix.is_some() { | 323 | if prefix.is_some() { |
306 | return None; | 324 | return None; |
307 | } | 325 | } |
308 | Path { kind: PathKind::Self_, segments: Vec::new() } | 326 | Path::from_simple_segments(PathKind::Self_, iter::empty()) |
309 | } | 327 | } |
310 | ast::PathSegmentKind::SuperKw => { | 328 | ast::PathSegmentKind::SuperKw => { |
311 | if prefix.is_some() { | 329 | if prefix.is_some() { |
312 | return None; | 330 | return None; |
313 | } | 331 | } |
314 | Path { kind: PathKind::Super, segments: Vec::new() } | 332 | Path::from_simple_segments(PathKind::Super, iter::empty()) |
315 | } | 333 | } |
316 | ast::PathSegmentKind::Type { .. } => { | 334 | ast::PathSegmentKind::Type { .. } => { |
317 | // not allowed in imports | 335 | // not allowed in imports |
@@ -320,3 +338,31 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
320 | }; | 338 | }; |
321 | Some(res) | 339 | Some(res) |
322 | } | 340 | } |
341 | |||
342 | pub mod known { | ||
343 | use super::{Path, PathKind}; | ||
344 | use crate::name; | ||
345 | |||
346 | pub fn std_iter_into_iterator() -> Path { | ||
347 | Path::from_simple_segments( | ||
348 | PathKind::Abs, | ||
349 | vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE], | ||
350 | ) | ||
351 | } | ||
352 | |||
353 | pub fn std_ops_try() -> Path { | ||
354 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE]) | ||
355 | } | ||
356 | |||
357 | pub fn std_result_result() -> Path { | ||
358 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE]) | ||
359 | } | ||
360 | |||
361 | pub fn std_future_future() -> Path { | ||
362 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE]) | ||
363 | } | ||
364 | |||
365 | pub fn std_boxed_box() -> Path { | ||
366 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE]) | ||
367 | } | ||
368 | } | ||
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 3207b6626..bb6915901 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -15,6 +15,7 @@ use crate::{ | |||
15 | name::{Name, SELF_PARAM, SELF_TYPE}, | 15 | name::{Name, SELF_PARAM, SELF_TYPE}, |
16 | nameres::{CrateDefMap, CrateModuleId, PerNs}, | 16 | nameres::{CrateDefMap, CrateModuleId, PerNs}, |
17 | path::{Path, PathKind}, | 17 | path::{Path, PathKind}, |
18 | type_ref::TypeRef, | ||
18 | Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, | 19 | Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, |
19 | Trait, TypeAlias, | 20 | Trait, TypeAlias, |
20 | }; | 21 | }; |
@@ -64,9 +65,10 @@ pub enum TypeNs { | |||
64 | } | 65 | } |
65 | 66 | ||
66 | #[derive(Debug)] | 67 | #[derive(Debug)] |
67 | pub enum ValueOrPartial { | 68 | pub enum ResolveValueResult<'a> { |
68 | ValueNs(ValueNs), | 69 | ValueNs(ValueNs), |
69 | Partial(TypeNs, usize), | 70 | Partial(TypeNs, usize), |
71 | TypeRef(&'a TypeRef), | ||
70 | } | 72 | } |
71 | 73 | ||
72 | #[derive(Debug)] | 74 | #[derive(Debug)] |
@@ -183,11 +185,15 @@ impl Resolver { | |||
183 | Some(res) | 185 | Some(res) |
184 | } | 186 | } |
185 | 187 | ||
186 | pub(crate) fn resolve_path_in_value_ns( | 188 | pub(crate) fn resolve_path_in_value_ns<'p>( |
187 | &self, | 189 | &self, |
188 | db: &impl HirDatabase, | 190 | db: &impl HirDatabase, |
189 | path: &Path, | 191 | path: &'p Path, |
190 | ) -> Option<ValueOrPartial> { | 192 | ) -> Option<ResolveValueResult<'p>> { |
193 | if let PathKind::Type(type_ref) = &path.kind { | ||
194 | return Some(ResolveValueResult::TypeRef(type_ref)); | ||
195 | } | ||
196 | |||
191 | let n_segments = path.segments.len(); | 197 | let n_segments = path.segments.len(); |
192 | let tmp = SELF_PARAM; | 198 | let tmp = SELF_PARAM; |
193 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; | 199 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; |
@@ -208,7 +214,7 @@ impl Resolver { | |||
208 | .find(|entry| entry.name() == first_name); | 214 | .find(|entry| entry.name() == first_name); |
209 | 215 | ||
210 | if let Some(e) = entry { | 216 | if let Some(e) = entry { |
211 | return Some(ValueOrPartial::ValueNs(ValueNs::LocalBinding(e.pat()))); | 217 | return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); |
212 | } | 218 | } |
213 | } | 219 | } |
214 | Scope::ExprScope(_) => continue, | 220 | Scope::ExprScope(_) => continue, |
@@ -216,7 +222,7 @@ impl Resolver { | |||
216 | Scope::GenericParams(params) if n_segments > 1 => { | 222 | Scope::GenericParams(params) if n_segments > 1 => { |
217 | if let Some(param) = params.find_by_name(first_name) { | 223 | if let Some(param) = params.find_by_name(first_name) { |
218 | let ty = TypeNs::GenericParam(param.idx); | 224 | let ty = TypeNs::GenericParam(param.idx); |
219 | return Some(ValueOrPartial::Partial(ty, 1)); | 225 | return Some(ResolveValueResult::Partial(ty, 1)); |
220 | } | 226 | } |
221 | } | 227 | } |
222 | Scope::GenericParams(_) => continue, | 228 | Scope::GenericParams(_) => continue, |
@@ -224,7 +230,7 @@ impl Resolver { | |||
224 | Scope::ImplBlockScope(impl_) if n_segments > 1 => { | 230 | Scope::ImplBlockScope(impl_) if n_segments > 1 => { |
225 | if first_name == &SELF_TYPE { | 231 | if first_name == &SELF_TYPE { |
226 | let ty = TypeNs::SelfType(*impl_); | 232 | let ty = TypeNs::SelfType(*impl_); |
227 | return Some(ValueOrPartial::Partial(ty, 1)); | 233 | return Some(ResolveValueResult::Partial(ty, 1)); |
228 | } | 234 | } |
229 | } | 235 | } |
230 | Scope::ImplBlockScope(_) => continue, | 236 | Scope::ImplBlockScope(_) => continue, |
@@ -247,7 +253,7 @@ impl Resolver { | |||
247 | | ModuleDef::BuiltinType(_) | 253 | | ModuleDef::BuiltinType(_) |
248 | | ModuleDef::Module(_) => return None, | 254 | | ModuleDef::Module(_) => return None, |
249 | }; | 255 | }; |
250 | Some(ValueOrPartial::ValueNs(value)) | 256 | Some(ResolveValueResult::ValueNs(value)) |
251 | } | 257 | } |
252 | Some(idx) => { | 258 | Some(idx) => { |
253 | let ty = match module_def.take_types()? { | 259 | let ty = match module_def.take_types()? { |
@@ -262,7 +268,7 @@ impl Resolver { | |||
262 | | ModuleDef::Const(_) | 268 | | ModuleDef::Const(_) |
263 | | ModuleDef::Static(_) => return None, | 269 | | ModuleDef::Static(_) => return None, |
264 | }; | 270 | }; |
265 | Some(ValueOrPartial::Partial(ty, idx)) | 271 | Some(ResolveValueResult::Partial(ty, idx)) |
266 | } | 272 | } |
267 | }; | 273 | }; |
268 | } | 274 | } |
@@ -277,8 +283,8 @@ impl Resolver { | |||
277 | path: &Path, | 283 | path: &Path, |
278 | ) -> Option<ValueNs> { | 284 | ) -> Option<ValueNs> { |
279 | match self.resolve_path_in_value_ns(db, path)? { | 285 | match self.resolve_path_in_value_ns(db, path)? { |
280 | ValueOrPartial::ValueNs(it) => Some(it), | 286 | ResolveValueResult::ValueNs(it) => Some(it), |
281 | ValueOrPartial::Partial(..) => None, | 287 | ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None, |
282 | } | 288 | } |
283 | } | 289 | } |
284 | 290 | ||
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index cff55b640..2a907c9f1 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -25,8 +25,7 @@ use crate::{ | |||
25 | BodySourceMap, | 25 | BodySourceMap, |
26 | }, | 26 | }, |
27 | ids::LocationCtx, | 27 | ids::LocationCtx, |
28 | name, | 28 | path::known, |
29 | path::{PathKind, PathSegment}, | ||
30 | resolve::{ScopeDef, TypeNs, ValueNs}, | 29 | resolve::{ScopeDef, TypeNs, ValueNs}, |
31 | ty::method_resolution::implements_trait, | 30 | ty::method_resolution::implements_trait, |
32 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, | 31 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, |
@@ -433,14 +432,7 @@ impl SourceAnalyzer { | |||
433 | /// Checks that particular type `ty` implements `std::future::Future`. | 432 | /// Checks that particular type `ty` implements `std::future::Future`. |
434 | /// This function is used in `.await` syntax completion. | 433 | /// This function is used in `.await` syntax completion. |
435 | pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { | 434 | pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { |
436 | let std_future_path = Path { | 435 | let std_future_path = known::std_future_future(); |
437 | kind: PathKind::Abs, | ||
438 | segments: vec![ | ||
439 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
440 | PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, | ||
441 | PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, | ||
442 | ], | ||
443 | }; | ||
444 | 436 | ||
445 | let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { | 437 | let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { |
446 | Some(it) => it, | 438 | Some(it) => it, |
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 5ba7cf2e0..94f8ecdc9 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -42,7 +42,7 @@ fn deref_by_trait( | |||
42 | crate::lang_item::LangItemTarget::Trait(t) => t, | 42 | crate::lang_item::LangItemTarget::Trait(t) => t, |
43 | _ => return None, | 43 | _ => return None, |
44 | }; | 44 | }; |
45 | let target = deref_trait.associated_type_by_name(db, &name::TARGET)?; | 45 | let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; |
46 | 46 | ||
47 | if target.generic_params(db).count_params_including_parent() != 1 { | 47 | if target.generic_params(db).count_params_including_parent() != 1 { |
48 | // the Target type + Deref trait should only have one generic parameter, | 48 | // the Target type + Deref trait should only have one generic parameter, |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 7d9b86752..bf9609d8c 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -44,11 +44,12 @@ use crate::{ | |||
44 | generics::{GenericParams, HasGenericParams}, | 44 | generics::{GenericParams, HasGenericParams}, |
45 | name, | 45 | name, |
46 | nameres::Namespace, | 46 | nameres::Namespace, |
47 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, | 47 | path::{known, GenericArg, GenericArgs}, |
48 | resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial}, | 48 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
49 | ty::infer::diagnostics::InferenceDiagnostic, | 49 | ty::infer::diagnostics::InferenceDiagnostic, |
50 | type_ref::{Mutability, TypeRef}, | 50 | type_ref::{Mutability, TypeRef}, |
51 | Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, Name, Path, StructField, | 51 | Adt, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, |
52 | StructField, | ||
52 | }; | 53 | }; |
53 | 54 | ||
54 | mod unify; | 55 | mod unify; |
@@ -470,9 +471,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
470 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; | 471 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; |
471 | 472 | ||
472 | let (value, self_subst) = match value_or_partial { | 473 | let (value, self_subst) = match value_or_partial { |
473 | ValueOrPartial::ValueNs(it) => (it, None), | 474 | ResolveValueResult::ValueNs(it) => (it, None), |
474 | ValueOrPartial::Partial(def, remaining_index) => { | 475 | ResolveValueResult::Partial(def, remaining_index) => { |
475 | self.resolve_assoc_item(def, path, remaining_index, id)? | 476 | self.resolve_assoc_item(Either::A(def), path, remaining_index, id)? |
477 | } | ||
478 | ResolveValueResult::TypeRef(type_ref) => { | ||
479 | let ty = self.make_ty(type_ref); | ||
480 | self.resolve_assoc_item(Either::B(ty), path, 0, id)? | ||
476 | } | 481 | } |
477 | }; | 482 | }; |
478 | 483 | ||
@@ -503,7 +508,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
503 | 508 | ||
504 | fn resolve_assoc_item( | 509 | fn resolve_assoc_item( |
505 | &mut self, | 510 | &mut self, |
506 | mut def: TypeNs, | 511 | mut def_or_ty: Either<TypeNs, Ty>, |
507 | path: &Path, | 512 | path: &Path, |
508 | remaining_index: usize, | 513 | remaining_index: usize, |
509 | id: ExprOrPatId, | 514 | id: ExprOrPatId, |
@@ -516,30 +521,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
516 | // resolve intermediate segments | 521 | // resolve intermediate segments |
517 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { | 522 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { |
518 | let is_last_segment = i == path.segments[remaining_index..].len() - 1; | 523 | let is_last_segment = i == path.segments[remaining_index..].len() - 1; |
519 | ty = { | 524 | ty = match def_or_ty { |
520 | let typable: TypableDef = match def { | 525 | Either::A(def) => { |
521 | TypeNs::Adt(it) => it.into(), | 526 | let typable: TypableDef = match def { |
522 | TypeNs::TypeAlias(it) => it.into(), | 527 | TypeNs::Adt(it) => it.into(), |
523 | TypeNs::BuiltinType(it) => it.into(), | 528 | TypeNs::TypeAlias(it) => it.into(), |
524 | // FIXME associated item of traits, generics, and Self | 529 | TypeNs::BuiltinType(it) => it.into(), |
525 | TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { | 530 | // FIXME associated item of traits, generics, and Self |
526 | return None; | 531 | TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { |
527 | } | 532 | return None; |
528 | // FIXME: report error here | 533 | } |
529 | TypeNs::EnumVariant(_) => return None, | 534 | // FIXME: report error here |
530 | }; | 535 | TypeNs::EnumVariant(_) => return None, |
531 | 536 | }; | |
532 | let ty = self.db.type_for_def(typable, Namespace::Types); | ||
533 | 537 | ||
534 | // For example, this substs will take `Gen::*<u32>*::make` | 538 | let ty = self.db.type_for_def(typable, Namespace::Types); |
535 | assert!(remaining_index > 0); | 539 | |
536 | let substs = Ty::substs_from_path_segment( | 540 | // For example, this substs will take `Gen::*<u32>*::make` |
537 | self.db, | 541 | assert!(remaining_index > 0); |
538 | &self.resolver, | 542 | let substs = Ty::substs_from_path_segment( |
539 | &path.segments[remaining_index + i - 1], | 543 | self.db, |
540 | typable, | 544 | &self.resolver, |
541 | ); | 545 | &path.segments[remaining_index + i - 1], |
542 | ty.subst(&substs) | 546 | typable, |
547 | ); | ||
548 | ty.subst(&substs) | ||
549 | } | ||
550 | Either::B(ty) => ty, | ||
543 | }; | 551 | }; |
544 | if is_last_segment { | 552 | if is_last_segment { |
545 | break; | 553 | break; |
@@ -550,15 +558,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
550 | log::debug!("looking for path segment: {:?}", segment); | 558 | log::debug!("looking for path segment: {:?}", segment); |
551 | 559 | ||
552 | let ty = mem::replace(&mut ty, Ty::Unknown); | 560 | let ty = mem::replace(&mut ty, Ty::Unknown); |
553 | def = ty.iterate_impl_items(self.db, krate, |item| { | 561 | def_or_ty = ty.iterate_impl_items(self.db, krate, |item| { |
554 | match item { | 562 | match item { |
555 | crate::ImplItem::Method(_) => None, | 563 | crate::ImplItem::Method(_) => None, |
556 | crate::ImplItem::Const(_) => None, | 564 | crate::ImplItem::Const(_) => None, |
557 | 565 | ||
558 | // FIXME: Resolve associated types | 566 | // FIXME: Resolve associated types |
559 | crate::ImplItem::TypeAlias(_) => { | 567 | crate::ImplItem::TypeAlias(_) => { |
560 | // Some(TypeNs::TypeAlias(..)) | 568 | // Some(Either::A(TypeNs::TypeAlias(..))) |
561 | None::<TypeNs> | 569 | None |
562 | } | 570 | } |
563 | } | 571 | } |
564 | })?; | 572 | })?; |
@@ -1434,57 +1442,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1434 | } | 1442 | } |
1435 | 1443 | ||
1436 | fn resolve_into_iter_item(&self) -> Option<TypeAlias> { | 1444 | fn resolve_into_iter_item(&self) -> Option<TypeAlias> { |
1437 | let into_iter_path = Path { | 1445 | let path = known::std_iter_into_iterator(); |
1438 | kind: PathKind::Abs, | 1446 | let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; |
1439 | segments: vec![ | 1447 | trait_.associated_type_by_name(self.db, &name::ITEM_TYPE) |
1440 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
1441 | PathSegment { name: name::ITER, args_and_bindings: None }, | ||
1442 | PathSegment { name: name::INTO_ITERATOR, args_and_bindings: None }, | ||
1443 | ], | ||
1444 | }; | ||
1445 | |||
1446 | let trait_ = self.resolver.resolve_known_trait(self.db, &into_iter_path)?; | ||
1447 | trait_.associated_type_by_name(self.db, &name::ITEM) | ||
1448 | } | 1448 | } |
1449 | 1449 | ||
1450 | fn resolve_ops_try_ok(&self) -> Option<TypeAlias> { | 1450 | fn resolve_ops_try_ok(&self) -> Option<TypeAlias> { |
1451 | let ops_try_path = Path { | 1451 | let path = known::std_ops_try(); |
1452 | kind: PathKind::Abs, | 1452 | let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; |
1453 | segments: vec![ | 1453 | trait_.associated_type_by_name(self.db, &name::OK_TYPE) |
1454 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
1455 | PathSegment { name: name::OPS, args_and_bindings: None }, | ||
1456 | PathSegment { name: name::TRY, args_and_bindings: None }, | ||
1457 | ], | ||
1458 | }; | ||
1459 | |||
1460 | let trait_ = self.resolver.resolve_known_trait(self.db, &ops_try_path)?; | ||
1461 | trait_.associated_type_by_name(self.db, &name::OK) | ||
1462 | } | 1454 | } |
1463 | 1455 | ||
1464 | fn resolve_future_future_output(&self) -> Option<TypeAlias> { | 1456 | fn resolve_future_future_output(&self) -> Option<TypeAlias> { |
1465 | let future_future_path = Path { | 1457 | let path = known::std_future_future(); |
1466 | kind: PathKind::Abs, | 1458 | let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; |
1467 | segments: vec![ | 1459 | trait_.associated_type_by_name(self.db, &name::OUTPUT_TYPE) |
1468 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
1469 | PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, | ||
1470 | PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, | ||
1471 | ], | ||
1472 | }; | ||
1473 | |||
1474 | let trait_ = self.resolver.resolve_known_trait(self.db, &future_future_path)?; | ||
1475 | trait_.associated_type_by_name(self.db, &name::OUTPUT) | ||
1476 | } | 1460 | } |
1477 | 1461 | ||
1478 | fn resolve_boxed_box(&self) -> Option<Adt> { | 1462 | fn resolve_boxed_box(&self) -> Option<Adt> { |
1479 | let boxed_box_path = Path { | 1463 | let path = known::std_boxed_box(); |
1480 | kind: PathKind::Abs, | 1464 | let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; |
1481 | segments: vec![ | ||
1482 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
1483 | PathSegment { name: name::BOXED_MOD, args_and_bindings: None }, | ||
1484 | PathSegment { name: name::BOX_TYPE, args_and_bindings: None }, | ||
1485 | ], | ||
1486 | }; | ||
1487 | let struct_ = self.resolver.resolve_known_struct(self.db, &boxed_box_path)?; | ||
1488 | Some(Adt::Struct(struct_)) | 1465 | Some(Adt::Struct(struct_)) |
1489 | } | 1466 | } |
1490 | } | 1467 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f6a2a658f..1bd677cab 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -282,6 +282,64 @@ fn test() { | |||
282 | } | 282 | } |
283 | 283 | ||
284 | #[test] | 284 | #[test] |
285 | fn infer_path_type() { | ||
286 | assert_snapshot!( | ||
287 | infer(r#" | ||
288 | struct S; | ||
289 | |||
290 | impl S { | ||
291 | fn foo() -> i32 { 1 } | ||
292 | } | ||
293 | |||
294 | fn test() { | ||
295 | S::foo(); | ||
296 | <S>::foo(); | ||
297 | } | ||
298 | "#), | ||
299 | @r###" | ||
300 | [41; 46) '{ 1 }': i32 | ||
301 | [43; 44) '1': i32 | ||
302 | [60; 93) '{ ...o(); }': () | ||
303 | [66; 72) 'S::foo': fn foo() -> i32 | ||
304 | [66; 74) 'S::foo()': i32 | ||
305 | [80; 88) '<S>::foo': fn foo() -> i32 | ||
306 | [80; 90) '<S>::foo()': i32 | ||
307 | "### | ||
308 | ); | ||
309 | } | ||
310 | |||
311 | #[test] | ||
312 | fn infer_slice_method() { | ||
313 | assert_snapshot!( | ||
314 | infer(r#" | ||
315 | #[lang = "slice"] | ||
316 | impl<T> [T] { | ||
317 | fn foo(&self) -> T { | ||
318 | loop {} | ||
319 | } | ||
320 | } | ||
321 | |||
322 | #[lang = "slice_alloc"] | ||
323 | impl<T> [T] {} | ||
324 | |||
325 | fn test() { | ||
326 | <[_]>::foo(b"foo"); | ||
327 | } | ||
328 | "#), | ||
329 | @r###" | ||
330 | [45; 49) 'self': &[T] | ||
331 | [56; 79) '{ ... }': ! | ||
332 | [66; 73) 'loop {}': ! | ||
333 | [71; 73) '{}': () | ||
334 | [133; 160) '{ ...o"); }': () | ||
335 | [139; 149) '<[_]>::foo': fn foo<u8>(&[T]) -> T | ||
336 | [139; 157) '<[_]>:..."foo")': u8 | ||
337 | [150; 156) 'b"foo"': &[u8] | ||
338 | "### | ||
339 | ); | ||
340 | } | ||
341 | |||
342 | #[test] | ||
285 | fn infer_struct() { | 343 | fn infer_struct() { |
286 | assert_snapshot!( | 344 | assert_snapshot!( |
287 | infer(r#" | 345 | infer(r#" |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 591ac8ca3..dc1f8c82c 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -2385,6 +2385,9 @@ impl PathSegment { | |||
2385 | pub fn ret_type(&self) -> Option<RetType> { | 2385 | pub fn ret_type(&self) -> Option<RetType> { |
2386 | AstChildren::new(&self.syntax).next() | 2386 | AstChildren::new(&self.syntax).next() |
2387 | } | 2387 | } |
2388 | pub fn path_type(&self) -> Option<PathType> { | ||
2389 | AstChildren::new(&self.syntax).next() | ||
2390 | } | ||
2388 | } | 2391 | } |
2389 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 2392 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
2390 | pub struct PathType { | 2393 | pub struct PathType { |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 08cc6eeea..da9de2214 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -689,7 +689,7 @@ Grammar( | |||
689 | ] | 689 | ] |
690 | ), | 690 | ), |
691 | "PathSegment": ( | 691 | "PathSegment": ( |
692 | options: [ "NameRef", "TypeArgList", "ParamList", "RetType" ] | 692 | options: [ "NameRef", "TypeArgList", "ParamList", "RetType", "PathType" ] |
693 | ), | 693 | ), |
694 | "TypeArgList": (collections: [ | 694 | "TypeArgList": (collections: [ |
695 | ("type_args", "TypeArg"), | 695 | ("type_args", "TypeArg"), |