diff options
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 83 |
1 files changed, 68 insertions, 15 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 894ba0695..debedcbb8 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -8,7 +8,7 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use super::{FnSig, GenericPredicate, Substs, TraitRef, Ty, TypeCtor}; | 11 | use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; |
12 | use crate::{ | 12 | use 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,54 @@ 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 | // FIXME handle type parameters on the segment | ||
121 | Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) | ||
122 | } else { | ||
123 | // FIXME more than one segment remaining, is this possible? | ||
124 | Ty::Unknown | ||
125 | } | ||
126 | } else { | ||
127 | // FIXME dyn Trait without the dyn | ||
128 | Ty::Unknown | ||
129 | } | ||
130 | } else { | ||
131 | let typable: TypableDef = match def.into() { | ||
132 | None => return Ty::Unknown, | ||
133 | Some(it) => it, | ||
134 | }; | ||
135 | let ty = db.type_for_def(typable, Namespace::Types); | ||
136 | let substs = Ty::substs_from_path(db, resolver, path, typable); | ||
137 | ty.subst(&substs) | ||
138 | } | ||
98 | } | 139 | } |
99 | 140 | ||
100 | pub(super) fn substs_from_path_segment( | 141 | pub(super) fn substs_from_path_segment( |
@@ -219,14 +260,25 @@ impl TraitRef { | |||
219 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | 260 | Resolution::Def(ModuleDef::Trait(tr)) => tr, |
220 | _ => return None, | 261 | _ => return None, |
221 | }; | 262 | }; |
222 | let mut substs = Self::substs_from_path(db, resolver, path, resolved); | 263 | let segment = path.segments.last().expect("path should have at least one segment"); |
264 | Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty)) | ||
265 | } | ||
266 | |||
267 | fn from_resolved_path( | ||
268 | db: &impl HirDatabase, | ||
269 | resolver: &Resolver, | ||
270 | resolved: Trait, | ||
271 | segment: &PathSegment, | ||
272 | explicit_self_ty: Option<Ty>, | ||
273 | ) -> Self { | ||
274 | let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); | ||
223 | if let Some(self_ty) = explicit_self_ty { | 275 | if let Some(self_ty) = explicit_self_ty { |
224 | // FIXME this could be nicer | 276 | // FIXME this could be nicer |
225 | let mut substs_vec = substs.0.to_vec(); | 277 | let mut substs_vec = substs.0.to_vec(); |
226 | substs_vec[0] = self_ty; | 278 | substs_vec[0] = self_ty; |
227 | substs.0 = substs_vec.into(); | 279 | substs.0 = substs_vec.into(); |
228 | } | 280 | } |
229 | Some(TraitRef { trait_: resolved, substs }) | 281 | TraitRef { trait_: resolved, substs } |
230 | } | 282 | } |
231 | 283 | ||
232 | pub(crate) fn from_hir( | 284 | pub(crate) fn from_hir( |
@@ -245,11 +297,12 @@ impl TraitRef { | |||
245 | fn substs_from_path( | 297 | fn substs_from_path( |
246 | db: &impl HirDatabase, | 298 | db: &impl HirDatabase, |
247 | resolver: &Resolver, | 299 | resolver: &Resolver, |
248 | path: &Path, | 300 | segment: &PathSegment, |
249 | resolved: Trait, | 301 | resolved: Trait, |
250 | ) -> Substs { | 302 | ) -> Substs { |
251 | let segment = path.segments.last().expect("path should have at least one segment"); | 303 | let has_self_param = |
252 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), true) | 304 | segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false); |
305 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), !has_self_param) | ||
253 | } | 306 | } |
254 | 307 | ||
255 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { | 308 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { |