diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_def/src/generics.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/utils.rs | 10 |
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)] |
55 | pub struct WherePredicate { | 55 | pub 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)] | ||
61 | pub enum WherePredicateTarget { | ||
62 | TypeRef(TypeRef), | ||
63 | /// For desugared where predicates that can directly refer to a type param. | ||
64 | TypeParam(LocalTypeParamId) | ||
65 | } | ||
66 | |||
60 | type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>; | 67 | type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>; |
61 | 68 | ||
62 | impl GenericParams { | 69 | impl 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 | ||
216 | impl HasChildSource for GenericDefId { | 235 | impl 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 | ||
11 | use hir_def::{ | 11 | use 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 | }; |
14 | use hir_expand::name::{name, Name}; | 14 | use hir_expand::name::{name, Name}; |
15 | use hir_def::generics::WherePredicateTarget; | ||
15 | 16 | ||
16 | fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 17 | fn 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()) { |