aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/lower.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r--crates/ra_hir/src/ty/lower.rs83
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 @@
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,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 {