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.rs97
1 files changed, 88 insertions, 9 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index a83842b0f..8d71abc95 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -86,6 +86,35 @@ impl Ty {
86 } 86 }
87 } 87 }
88 88
89 /// This is only for `generic_predicates_for_param`, where we can't just
90 /// lower the self types of the predicates since that could lead to cycles.
91 /// So we just check here if the `type_ref` resolves to a generic param, and which.
92 fn from_hir_only_param(
93 db: &impl HirDatabase,
94 resolver: &Resolver,
95 type_ref: &TypeRef,
96 ) -> Option<u32> {
97 let path = match type_ref {
98 TypeRef::Path(path) => path,
99 _ => return None,
100 };
101 if let crate::PathKind::Type(_) = &path.kind {
102 return None;
103 }
104 if path.segments.len() > 1 {
105 return None;
106 }
107 let resolution = match resolver.resolve_path_in_type_ns(db, path) {
108 Some((it, None)) => it,
109 _ => return None,
110 };
111 if let TypeNs::GenericParam(idx) = resolution {
112 Some(idx)
113 } else {
114 None
115 }
116 }
117
89 pub(crate) fn from_type_relative_path( 118 pub(crate) fn from_type_relative_path(
90 db: &impl HirDatabase, 119 db: &impl HirDatabase,
91 resolver: &Resolver, 120 resolver: &Resolver,
@@ -189,11 +218,37 @@ impl Ty {
189 } 218 }
190 219
191 fn select_associated_type( 220 fn select_associated_type(
192 _db: &impl HirDatabase, 221 db: &impl HirDatabase,
193 _resolver: &Resolver, 222 resolver: &Resolver,
194 _self_ty: Ty, 223 self_ty: Ty,
195 _segment: &PathSegment, 224 segment: &PathSegment,
196 ) -> Ty { 225 ) -> Ty {
226 let param_idx = match self_ty {
227 Ty::Param { idx, .. } => idx,
228 _ => return Ty::Unknown, // Error: Ambiguous associated type
229 };
230 let def = match resolver.generic_def() {
231 Some(def) => def,
232 None => return Ty::Unknown, // this can't actually happen
233 };
234 let predicates = db.generic_predicates_for_param(def, param_idx);
235 let traits_from_env = predicates.iter().filter_map(|pred| match pred {
236 GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_),
237 _ => None,
238 });
239 let traits = traits_from_env.flat_map(|t| t.all_super_traits(db));
240 for t in traits {
241 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) {
242 let generics = t.generic_params(db);
243 let mut substs = Vec::new();
244 substs.push(self_ty.clone());
245 substs.extend(
246 iter::repeat(Ty::Unknown).take(generics.count_params_including_parent() - 1),
247 );
248 // FIXME handle type parameters on the segment
249 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs.into() });
250 }
251 }
197 Ty::Unknown 252 Ty::Unknown
198 } 253 }
199 254
@@ -269,9 +324,10 @@ pub(super) fn substs_from_path_segment(
269 add_self_param: bool, 324 add_self_param: bool,
270) -> Substs { 325) -> Substs {
271 let mut substs = Vec::new(); 326 let mut substs = Vec::new();
272 let def_generics = def_generic.map(|def| def.generic_params(db)).unwrap_or_default(); 327 let def_generics = def_generic.map(|def| def.generic_params(db));
273 328
274 let parent_param_count = def_generics.count_parent_params(); 329 let (parent_param_count, param_count) =
330 def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len()));
275 substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); 331 substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count));
276 if add_self_param { 332 if add_self_param {
277 // FIXME this add_self_param argument is kind of a hack: Traits have the 333 // FIXME this add_self_param argument is kind of a hack: Traits have the
@@ -283,7 +339,7 @@ pub(super) fn substs_from_path_segment(
283 if let Some(generic_args) = &segment.args_and_bindings { 339 if let Some(generic_args) = &segment.args_and_bindings {
284 // if args are provided, it should be all of them, but we can't rely on that 340 // if args are provided, it should be all of them, but we can't rely on that
285 let self_param_correction = if add_self_param { 1 } else { 0 }; 341 let self_param_correction = if add_self_param { 1 } else { 0 };
286 let param_count = def_generics.params.len() - self_param_correction; 342 let param_count = param_count - self_param_correction;
287 for arg in generic_args.args.iter().take(param_count) { 343 for arg in generic_args.args.iter().take(param_count) {
288 match arg { 344 match arg {
289 GenericArg::Type(type_ref) => { 345 GenericArg::Type(type_ref) => {
@@ -295,10 +351,10 @@ pub(super) fn substs_from_path_segment(
295 } 351 }
296 // add placeholders for args that were not provided 352 // add placeholders for args that were not provided
297 let supplied_params = substs.len(); 353 let supplied_params = substs.len();
298 for _ in supplied_params..def_generics.count_params_including_parent() { 354 for _ in supplied_params..parent_param_count + param_count {
299 substs.push(Ty::Unknown); 355 substs.push(Ty::Unknown);
300 } 356 }
301 assert_eq!(substs.len(), def_generics.count_params_including_parent()); 357 assert_eq!(substs.len(), parent_param_count + param_count);
302 358
303 // handle defaults 359 // handle defaults
304 if let Some(def_generic) = def_generic { 360 if let Some(def_generic) = def_generic {
@@ -491,6 +547,29 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
491 Ty::from_hir(db, &resolver, type_ref) 547 Ty::from_hir(db, &resolver, type_ref)
492} 548}
493 549
550/// This query exists only to be used when resolving short-hand associated types
551/// like `T::Item`.
552///
553/// See the analogous query in rustc and its comment:
554/// https://github.com/rust-lang/rust/blob/9150f844e2624eb013ec78ca08c1d416e6644026/src/librustc_typeck/astconv.rs#L46
555/// This is a query mostly to handle cycles somewhat gracefully; e.g. the
556/// following bounds are disallowed: `T: Foo<U::Item>, U: Foo<T::Item>`, but
557/// these are fine: `T: Foo<U::Item>, U: Foo<()>`.
558pub(crate) fn generic_predicates_for_param_query(
559 db: &impl HirDatabase,
560 def: GenericDef,
561 param_idx: u32,
562) -> Arc<[GenericPredicate]> {
563 let resolver = def.resolver(db);
564 let predicates = resolver
565 .where_predicates_in_scope()
566 // we have to filter out all other predicates *first*, before attempting to lower them
567 .filter(|pred| Ty::from_hir_only_param(db, &resolver, &pred.type_ref) == Some(param_idx))
568 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
569 .collect::<Vec<_>>();
570 predicates.into()
571}
572
494pub(crate) fn trait_env( 573pub(crate) fn trait_env(
495 db: &impl HirDatabase, 574 db: &impl HirDatabase,
496 resolver: &Resolver, 575 resolver: &Resolver,