aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/generics.rs27
-rw-r--r--crates/ra_hir_ty/src/lower.rs29
-rw-r--r--crates/ra_hir_ty/src/utils.rs10
3 files changed, 56 insertions, 10 deletions
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 7553d8a87..e4e616519 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -53,10 +53,17 @@ pub struct GenericParams {
53/// associated type bindings like `Iterator<Item = u32>`. 53/// associated type bindings like `Iterator<Item = u32>`.
54#[derive(Clone, PartialEq, Eq, Debug)] 54#[derive(Clone, PartialEq, Eq, Debug)]
55pub struct WherePredicate { 55pub struct WherePredicate {
56 pub type_ref: TypeRef, 56 pub target: WherePredicateTarget,
57 pub bound: TypeBound, 57 pub bound: TypeBound,
58} 58}
59 59
60#[derive(Clone, PartialEq, Eq, Debug)]
61pub enum WherePredicateTarget {
62 TypeRef(TypeRef),
63 /// For desugared where predicates that can directly refer to a type param.
64 TypeParam(LocalTypeParamId)
65}
66
60type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>; 67type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>;
61 68
62impl GenericParams { 69impl GenericParams {
@@ -190,18 +197,24 @@ impl GenericParams {
190 return; 197 return;
191 } 198 }
192 let bound = TypeBound::from_ast(bound); 199 let bound = TypeBound::from_ast(bound);
193 self.where_predicates.push(WherePredicate { type_ref, bound }); 200 self.where_predicates.push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound });
194 } 201 }
195 202
196 fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { 203 fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
197 type_ref.walk(&mut |type_ref| { 204 type_ref.walk(&mut |type_ref| {
198 if let TypeRef::ImplTrait(_) = type_ref { 205 if let TypeRef::ImplTrait(bounds) = type_ref {
199 let param = TypeParamData { 206 let param = TypeParamData {
200 name: None, 207 name: None,
201 default: None, 208 default: None,
202 provenance: TypeParamProvenance::ArgumentImplTrait, 209 provenance: TypeParamProvenance::ArgumentImplTrait,
203 }; 210 };
204 let _param_id = self.types.alloc(param); 211 let param_id = self.types.alloc(param);
212 for bound in bounds {
213 self.where_predicates.push(WherePredicate {
214 target: WherePredicateTarget::TypeParam(param_id),
215 bound: bound.clone()
216 });
217 }
205 } 218 }
206 }); 219 });
207 } 220 }
@@ -211,6 +224,12 @@ impl GenericParams {
211 .iter() 224 .iter()
212 .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) 225 .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
213 } 226 }
227
228 pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
229 self.types
230 .iter()
231 .find_map(|(id, p)| if p.provenance == TypeParamProvenance::TraitSelf { Some(id) } else { None })
232 }
214} 233}
215 234
216impl HasChildSource for GenericDefId { 235impl HasChildSource for GenericDefId {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 459b96280..f1a11e073 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -10,7 +10,7 @@ use std::sync::Arc;
10 10
11use hir_def::{ 11use hir_def::{
12 builtin_type::BuiltinType, 12 builtin_type::BuiltinType,
13 generics::WherePredicate, 13 generics::{WherePredicateTarget, WherePredicate},
14 path::{GenericArg, Path, PathSegment, PathSegments}, 14 path::{GenericArg, Path, PathSegment, PathSegments},
15 resolver::{HasResolver, Resolver, TypeNs}, 15 resolver::{HasResolver, Resolver, TypeNs},
16 type_ref::{TypeBound, TypeRef}, 16 type_ref::{TypeBound, TypeRef},
@@ -505,7 +505,22 @@ impl GenericPredicate {
505 ctx: &'a TyLoweringContext<'a, impl HirDatabase>, 505 ctx: &'a TyLoweringContext<'a, impl HirDatabase>,
506 where_predicate: &'a WherePredicate, 506 where_predicate: &'a WherePredicate,
507 ) -> impl Iterator<Item = GenericPredicate> + 'a { 507 ) -> impl Iterator<Item = GenericPredicate> + 'a {
508 let self_ty = Ty::from_hir(ctx, &where_predicate.type_ref); 508 let self_ty = match &where_predicate.target {
509 WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref),
510 WherePredicateTarget::TypeParam(param_id) => {
511 let generic_def = ctx.resolver.generic_def().expect("generics in scope");
512 let generics = generics(ctx.db, generic_def);
513 let param_id = hir_def::TypeParamId { parent: generic_def, local_id: *param_id };
514 let idx = generics.param_idx(param_id);
515 match ctx.type_param_mode {
516 TypeParamLoweringMode::Placeholder => {
517 let name = generics.param_name(param_id);
518 Ty::Param { idx, name }
519 },
520 TypeParamLoweringMode::Variable => Ty::Bound(idx),
521 }
522 },
523 };
509 GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty) 524 GenericPredicate::from_type_bound(ctx, &where_predicate.bound, self_ty)
510 } 525 }
511 526
@@ -595,10 +610,18 @@ pub(crate) fn generic_predicates_for_param_query(
595) -> Arc<[GenericPredicate]> { 610) -> Arc<[GenericPredicate]> {
596 let resolver = def.resolver(db); 611 let resolver = def.resolver(db);
597 let ctx = TyLoweringContext::new(db, &resolver); 612 let ctx = TyLoweringContext::new(db, &resolver);
613 let generics = generics(db, def);
598 resolver 614 resolver
599 .where_predicates_in_scope() 615 .where_predicates_in_scope()
600 // we have to filter out all other predicates *first*, before attempting to lower them 616 // we have to filter out all other predicates *first*, before attempting to lower them
601 .filter(|pred| Ty::from_hir_only_param(&ctx, &pred.type_ref) == Some(param_idx)) 617 .filter(|pred| match &pred.target {
618 WherePredicateTarget::TypeRef(type_ref) => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_idx),
619 WherePredicateTarget::TypeParam(local_id) => {
620 let param_id = hir_def::TypeParamId { parent: def, local_id: *local_id };
621 let idx = generics.param_idx(param_id);
622 idx == param_idx
623 }
624 })
602 .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred)) 625 .flat_map(|pred| GenericPredicate::from_where_predicate(&ctx, pred))
603 .collect() 626 .collect()
604} 627}
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index f116b95e7..77b7de729 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -12,6 +12,7 @@ use hir_def::{
12 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, 12 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
13}; 13};
14use hir_expand::name::{name, Name}; 14use hir_expand::name::{name, Name};
15use hir_def::generics::WherePredicateTarget;
15 16
16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> { 17fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
17 let resolver = trait_.resolver(db); 18 let resolver = trait_.resolver(db);
@@ -19,11 +20,14 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
19 // lifetime problems, but since there usually shouldn't be more than a 20 // lifetime problems, but since there usually shouldn't be more than a
20 // few direct traits this should be fine (we could even use some kind of 21 // few direct traits this should be fine (we could even use some kind of
21 // SmallVec if performance is a concern) 22 // SmallVec if performance is a concern)
22 db.generic_params(trait_.into()) 23 let generic_params = db.generic_params(trait_.into());
24 let trait_self = generic_params.find_trait_self_param();
25 generic_params
23 .where_predicates 26 .where_predicates
24 .iter() 27 .iter()
25 .filter_map(|pred| match &pred.type_ref { 28 .filter_map(|pred| match &pred.target {
26 TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(), 29 WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => pred.bound.as_path(),
30 WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => pred.bound.as_path(),
27 _ => None, 31 _ => None,
28 }) 32 })
29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { 33 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {