aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-08-05 21:42:38 +0100
committerFlorian Diebold <[email protected]>2019-08-12 20:43:00 +0100
commit22724f37f3ae73983bf700d10d80a8dbd4fa4073 (patch)
treef5970c453f15d2b60e7c7b026de34316a5c8f4e0 /crates
parent6cfdfdecbaed38534397f16e1ea1cda38b0b9395 (diff)
Lower fully qualified associated type paths
I.e. `<T as Trait>::Foo`.
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/auto_import.rs1
-rw-r--r--crates/ra_hir/src/path.rs38
-rw-r--r--crates/ra_hir/src/ty/lower.rs88
-rw-r--r--crates/ra_hir/src/ty/tests.rs14
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs10
5 files changed, 128 insertions, 23 deletions
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index a32e2f9b6..1158adbbc 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -71,6 +71,7 @@ fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool {
71 ast::PathSegmentKind::SelfKw => a == "self", 71 ast::PathSegmentKind::SelfKw => a == "self",
72 ast::PathSegmentKind::SuperKw => a == "super", 72 ast::PathSegmentKind::SuperKw => a == "super",
73 ast::PathSegmentKind::CrateKw => a == "crate", 73 ast::PathSegmentKind::CrateKw => a == "crate",
74 ast::PathSegmentKind::Type { .. } => false, // not allowed in imports
74 } 75 }
75 } else { 76 } else {
76 false 77 false
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)]
26pub struct GenericArgs { 26pub 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
154impl From<Name> for Path { 186impl 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}
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 894ba0695..24ec77fcf 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -8,7 +8,7 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use super::{FnSig, GenericPredicate, Substs, TraitRef, Ty, TypeCtor}; 11use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor};
12use crate::{ 12use crate::{
13 adt::VariantDef, 13 adt::VariantDef,
14 generics::HasGenericParams, 14 generics::HasGenericParams,
@@ -64,7 +64,8 @@ impl Ty {
64 64
65 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { 65 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self {
66 // Resolve the path (in type namespace) 66 // Resolve the path (in type namespace)
67 let resolution = resolver.resolve_path_without_assoc_items(db, path).take_types(); 67 let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner();
68 let resolution = resolution.take_types();
68 69
69 let def = match resolution { 70 let def = match resolution {
70 Some(Resolution::Def(def)) => def, 71 Some(Resolution::Def(def)) => def,
@@ -73,6 +74,10 @@ impl Ty {
73 panic!("path resolved to local binding in type ns"); 74 panic!("path resolved to local binding in type ns");
74 } 75 }
75 Some(Resolution::GenericParam(idx)) => { 76 Some(Resolution::GenericParam(idx)) => {
77 if remaining_index.is_some() {
78 // e.g. T::Item
79 return Ty::Unknown;
80 }
76 return Ty::Param { 81 return Ty::Param {
77 idx, 82 idx,
78 // FIXME: maybe return name in resolution? 83 // FIXME: maybe return name in resolution?
@@ -83,18 +88,59 @@ impl Ty {
83 }; 88 };
84 } 89 }
85 Some(Resolution::SelfType(impl_block)) => { 90 Some(Resolution::SelfType(impl_block)) => {
91 if remaining_index.is_some() {
92 // e.g. Self::Item
93 return Ty::Unknown;
94 }
86 return impl_block.target_ty(db); 95 return impl_block.target_ty(db);
87 } 96 }
88 None => return Ty::Unknown, 97 None => {
98 // path did not resolve
99 return Ty::Unknown;
100 }
89 }; 101 };
90 102
91 let typable: TypableDef = match def.into() { 103 if let ModuleDef::Trait(trait_) = def {
92 None => return Ty::Unknown, 104 let segment = match remaining_index {
93 Some(it) => it, 105 None => path.segments.last().expect("resolved path has at least one element"),
94 }; 106 Some(i) => &path.segments[i - 1],
95 let ty = db.type_for_def(typable, Namespace::Types); 107 };
96 let substs = Ty::substs_from_path(db, resolver, path, typable); 108 let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None);
97 ty.subst(&substs) 109 if let Some(remaining_index) = remaining_index {
110 if remaining_index == path.segments.len() - 1 {
111 let segment = &path.segments[remaining_index];
112 let associated_ty =
113 match trait_ref.trait_.associated_type_by_name(db, segment.name.clone()) {
114 Some(t) => t,
115 None => {
116 // associated type not found
117 return Ty::Unknown;
118 }
119 };
120 eprintln!(
121 "assoc ty: {:?}, parameters: {:?}",
122 associated_ty.name(db),
123 trait_ref.substs
124 );
125 // FIXME handle type parameters on the segment
126 Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs })
127 } else {
128 // FIXME more than one segment remaining, is this possible?
129 Ty::Unknown
130 }
131 } else {
132 // FIXME dyn Trait without the dyn
133 Ty::Unknown
134 }
135 } else {
136 let typable: TypableDef = match def.into() {
137 None => return Ty::Unknown,
138 Some(it) => it,
139 };
140 let ty = db.type_for_def(typable, Namespace::Types);
141 let substs = Ty::substs_from_path(db, resolver, path, typable);
142 ty.subst(&substs)
143 }
98 } 144 }
99 145
100 pub(super) fn substs_from_path_segment( 146 pub(super) fn substs_from_path_segment(
@@ -219,14 +265,25 @@ impl TraitRef {
219 Resolution::Def(ModuleDef::Trait(tr)) => tr, 265 Resolution::Def(ModuleDef::Trait(tr)) => tr,
220 _ => return None, 266 _ => return None,
221 }; 267 };
222 let mut substs = Self::substs_from_path(db, resolver, path, resolved); 268 let segment = path.segments.last().expect("path should have at least one segment");
269 Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty))
270 }
271
272 fn from_resolved_path(
273 db: &impl HirDatabase,
274 resolver: &Resolver,
275 resolved: Trait,
276 segment: &PathSegment,
277 explicit_self_ty: Option<Ty>,
278 ) -> Self {
279 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
223 if let Some(self_ty) = explicit_self_ty { 280 if let Some(self_ty) = explicit_self_ty {
224 // FIXME this could be nicer 281 // FIXME this could be nicer
225 let mut substs_vec = substs.0.to_vec(); 282 let mut substs_vec = substs.0.to_vec();
226 substs_vec[0] = self_ty; 283 substs_vec[0] = self_ty;
227 substs.0 = substs_vec.into(); 284 substs.0 = substs_vec.into();
228 } 285 }
229 Some(TraitRef { trait_: resolved, substs }) 286 TraitRef { trait_: resolved, substs }
230 } 287 }
231 288
232 pub(crate) fn from_hir( 289 pub(crate) fn from_hir(
@@ -245,11 +302,12 @@ impl TraitRef {
245 fn substs_from_path( 302 fn substs_from_path(
246 db: &impl HirDatabase, 303 db: &impl HirDatabase,
247 resolver: &Resolver, 304 resolver: &Resolver,
248 path: &Path, 305 segment: &PathSegment,
249 resolved: Trait, 306 resolved: Trait,
250 ) -> Substs { 307 ) -> Substs {
251 let segment = path.segments.last().expect("path should have at least one segment"); 308 let has_self_param =
252 substs_from_path_segment(db, resolver, segment, Some(resolved.into()), true) 309 segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false);
310 substs_from_path_segment(db, resolver, segment, Some(resolved.into()), !has_self_param)
253 } 311 }
254 312
255 pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { 313 pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 9d412ff61..01b358335 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2515,10 +2515,10 @@ fn test<T: Iterable>() {
2515 @r###" 2515 @r###"
2516 2516
2517 ⋮[108; 227) '{ ...ter; }': () 2517 ⋮[108; 227) '{ ...ter; }': ()
2518 ⋮[118; 119) 'x': i32 2518 ⋮[118; 119) 'x': <S as Iterable>::Item
2519 ⋮[145; 146) '1': i32 2519 ⋮[145; 146) '1': <S as Iterable>::Item
2520 ⋮[156; 157) 'y': {unknown} 2520 ⋮[156; 157) 'y': <T as Iterable>::Item
2521 ⋮[183; 192) 'no_matter': {unknown} 2521 ⋮[183; 192) 'no_matter': <T as Iterable>::Item
2522 ⋮[202; 203) 'z': {unknown} 2522 ⋮[202; 203) 'z': {unknown}
2523 ⋮[215; 224) 'no_matter': {unknown} 2523 ⋮[215; 224) 'no_matter': {unknown}
2524 "### 2524 "###
@@ -2552,9 +2552,9 @@ fn test() {
2552 ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown} 2552 ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown}
2553 ⋮[205; 212) 'foo1(S)': {unknown} 2553 ⋮[205; 212) 'foo1(S)': {unknown}
2554 ⋮[210; 211) 'S': S 2554 ⋮[210; 211) 'S': S
2555 ⋮[222; 223) 'y': {unknown} 2555 ⋮[222; 223) 'y': <S as Iterable>::Item
2556 ⋮[226; 230) 'foo2': fn foo2<S>(T) -> {unknown} 2556 ⋮[226; 230) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
2557 ⋮[226; 233) 'foo2(S)': {unknown} 2557 ⋮[226; 233) 'foo2(S)': <S as Iterable>::Item
2558 ⋮[231; 232) 'S': S 2558 ⋮[231; 232) 'S': S
2559 "### 2559 "###
2560 ); 2560 );
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index d4873b39a..2a59cf653 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -91,6 +91,7 @@ impl ast::Attr {
91#[derive(Debug, Clone, PartialEq, Eq)] 91#[derive(Debug, Clone, PartialEq, Eq)]
92pub enum PathSegmentKind { 92pub enum PathSegmentKind {
93 Name(ast::NameRef), 93 Name(ast::NameRef),
94 Type { type_ref: Option<ast::TypeRef>, trait_ref: Option<ast::PathType> },
94 SelfKw, 95 SelfKw,
95 SuperKw, 96 SuperKw,
96 CrateKw, 97 CrateKw,
@@ -112,6 +113,15 @@ impl ast::PathSegment {
112 T![self] => PathSegmentKind::SelfKw, 113 T![self] => PathSegmentKind::SelfKw,
113 T![super] => PathSegmentKind::SuperKw, 114 T![super] => PathSegmentKind::SuperKw,
114 T![crate] => PathSegmentKind::CrateKw, 115 T![crate] => PathSegmentKind::CrateKw,
116 T![<] => {
117 // <T> or <T as Trait>
118 // T is any TypeRef, Trait has to be a PathType
119 let mut type_refs =
120 self.syntax().children().filter(|node| ast::TypeRef::can_cast(node.kind()));
121 let type_ref = type_refs.next().and_then(ast::TypeRef::cast);
122 let trait_ref = type_refs.next().and_then(ast::PathType::cast);
123 PathSegmentKind::Type { type_ref, trait_ref }
124 }
115 _ => return None, 125 _ => return None,
116 } 126 }
117 }; 127 };