diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-08-12 20:43:57 +0100 |
---|---|---|
committer | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-08-12 20:43:57 +0100 |
commit | 2c65a059840dd2092a00e90337a8221cd832c456 (patch) | |
tree | fa1f8c46158271eb859928ed9da3eb389f861c09 /crates/ra_hir/src/path.rs | |
parent | 0cf48e48d75d267bfa38ff1319e7f7c0468fb53f (diff) | |
parent | 5af9691dc9132db61b50c4e90cdeda6fea0c5dd9 (diff) |
Merge #1677
1677: Associated types r=flodiebold a=flodiebold
This implements basic support for (fully qualified) associated type projections:
- handle fully qualified paths like `<T as Trait>::AssocType` (basically desugaring to something like `Trait<Self=T>::AssocType`)
- lower these to a new `Ty::Projection` enum variant
- also introduce `Ty::UnselectedProjection` for cases like `T::AssocType` where the trait from which the type comes isn't specified, but these aren't handled further so far
- in inference, normalize these projections using Chalk: basically, when encountering a type e.g. from a type annotation or signature, we replace these `Ty::Projection`s by type variables and add obligations to normalize the associated type
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/path.rs')
-rw-r--r-- | crates/ra_hir/src/path.rs | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 882db7681..5ee71e421 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -25,6 +25,12 @@ pub struct PathSegment { | |||
25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
26 | pub struct GenericArgs { | 26 | pub struct GenericArgs { |
27 | pub args: Vec<GenericArg>, | 27 | pub args: Vec<GenericArg>, |
28 | /// This specifies whether the args contain a Self type as the first | ||
29 | /// element. This is the case for path segments like `<T as Trait>`, where | ||
30 | /// `T` is actually a type parameter for the path `Trait` specifying the | ||
31 | /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type | ||
32 | /// is left out. | ||
33 | pub has_self_type: bool, | ||
28 | // someday also bindings | 34 | // someday also bindings |
29 | } | 35 | } |
30 | 36 | ||
@@ -74,6 +80,28 @@ impl Path { | |||
74 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; | 80 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; |
75 | segments.push(segment); | 81 | segments.push(segment); |
76 | } | 82 | } |
83 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | ||
84 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | ||
85 | |||
86 | // FIXME: handle <T> syntax (type segments without trait) | ||
87 | |||
88 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | ||
89 | let path = Path::from_ast(trait_ref?.path()?)?; | ||
90 | kind = path.kind; | ||
91 | let mut prefix_segments = path.segments; | ||
92 | prefix_segments.reverse(); | ||
93 | segments.extend(prefix_segments); | ||
94 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
95 | let self_type = TypeRef::from_ast(type_ref?); | ||
96 | let mut last_segment = segments.last_mut()?; | ||
97 | if last_segment.args_and_bindings.is_none() { | ||
98 | last_segment.args_and_bindings = Some(Arc::new(GenericArgs::empty())); | ||
99 | }; | ||
100 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | ||
101 | let mut args_inner = Arc::make_mut(args); | ||
102 | args_inner.has_self_type = true; | ||
103 | args_inner.args.insert(0, GenericArg::Type(self_type)); | ||
104 | } | ||
77 | ast::PathSegmentKind::CrateKw => { | 105 | ast::PathSegmentKind::CrateKw => { |
78 | kind = PathKind::Crate; | 106 | kind = PathKind::Crate; |
79 | break; | 107 | break; |
@@ -144,11 +172,15 @@ impl GenericArgs { | |||
144 | } | 172 | } |
145 | // lifetimes and assoc type args ignored for now | 173 | // lifetimes and assoc type args ignored for now |
146 | if !args.is_empty() { | 174 | if !args.is_empty() { |
147 | Some(GenericArgs { args }) | 175 | Some(GenericArgs { args, has_self_type: false }) |
148 | } else { | 176 | } else { |
149 | None | 177 | None |
150 | } | 178 | } |
151 | } | 179 | } |
180 | |||
181 | pub(crate) fn empty() -> GenericArgs { | ||
182 | GenericArgs { args: Vec::new(), has_self_type: false } | ||
183 | } | ||
152 | } | 184 | } |
153 | 185 | ||
154 | impl From<Name> for Path { | 186 | impl From<Name> for Path { |
@@ -236,6 +268,10 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
236 | } | 268 | } |
237 | Path { kind: PathKind::Super, segments: Vec::new() } | 269 | Path { kind: PathKind::Super, segments: Vec::new() } |
238 | } | 270 | } |
271 | ast::PathSegmentKind::Type { .. } => { | ||
272 | // not allowed in imports | ||
273 | return None; | ||
274 | } | ||
239 | }; | 275 | }; |
240 | Some(res) | 276 | Some(res) |
241 | } | 277 | } |