aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
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/ra_hir/src/ty
parent6cfdfdecbaed38534397f16e1ea1cda38b0b9395 (diff)
Lower fully qualified associated type paths
I.e. `<T as Trait>::Foo`.
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/lower.rs88
-rw-r--r--crates/ra_hir/src/ty/tests.rs14
2 files changed, 80 insertions, 22 deletions
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 );