aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/code_model.rs53
-rw-r--r--crates/ra_hir/src/ty.rs1
-rw-r--r--crates/ra_hir/src/ty/lower.rs3
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs5
-rw-r--r--crates/ra_hir/src/ty/utils.rs50
5 files changed, 63 insertions, 49 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 821f919d4..9930cff66 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -9,7 +9,7 @@ use hir_def::{
9 builtin_type::BuiltinType, 9 builtin_type::BuiltinType,
10 docs::Documentation, 10 docs::Documentation,
11 per_ns::PerNs, 11 per_ns::PerNs,
12 resolver::{HasResolver, TypeNs}, 12 resolver::HasResolver,
13 type_ref::{Mutability, TypeRef}, 13 type_ref::{Mutability, TypeRef},
14 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, 14 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId,
15 HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, 15 HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId,
@@ -28,8 +28,8 @@ use crate::{
28 expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, 28 expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId},
29 ty::display::HirFormatter, 29 ty::display::HirFormatter,
30 ty::{ 30 ty::{
31 self, InEnvironment, InferenceResult, Namespace, TraitEnvironment, TraitRef, Ty, TypeCtor, 31 self, utils::all_super_traits, InEnvironment, InferenceResult, Namespace, TraitEnvironment,
32 TypeWalk, 32 TraitRef, Ty, TypeCtor, TypeWalk,
33 }, 33 },
34 CallableDef, Either, HirDisplay, Name, Source, 34 CallableDef, Either, HirDisplay, Name, Source,
35}; 35};
@@ -740,48 +740,6 @@ impl Trait {
740 db.trait_data(self.id).items.iter().map(|it| (*it).into()).collect() 740 db.trait_data(self.id).items.iter().map(|it| (*it).into()).collect()
741 } 741 }
742 742
743 fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
744 let resolver = self.id.resolver(db);
745 // returning the iterator directly doesn't easily work because of
746 // lifetime problems, but since there usually shouldn't be more than a
747 // few direct traits this should be fine (we could even use some kind of
748 // SmallVec if performance is a concern)
749 db.generic_params(self.id.into())
750 .where_predicates
751 .iter()
752 .filter_map(|pred| match &pred.type_ref {
753 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
754 _ => None,
755 })
756 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
757 Some(TypeNs::TraitId(t)) => Some(t),
758 _ => None,
759 })
760 .map(Trait::from)
761 .collect()
762 }
763
764 /// Returns an iterator over the whole super trait hierarchy (including the
765 /// trait itself).
766 pub fn all_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
767 // we need to take care a bit here to avoid infinite loops in case of cycles
768 // (i.e. if we have `trait A: B; trait B: A;`)
769 let mut result = vec![self];
770 let mut i = 0;
771 while i < result.len() {
772 let t = result[i];
773 // yeah this is quadratic, but trait hierarchies should be flat
774 // enough that this doesn't matter
775 for tt in t.direct_super_traits(db) {
776 if !result.contains(&tt) {
777 result.push(tt);
778 }
779 }
780 i += 1;
781 }
782 result
783 }
784
785 pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { 743 pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
786 let trait_data = db.trait_data(self.id); 744 let trait_data = db.trait_data(self.id);
787 let res = 745 let res =
@@ -794,7 +752,10 @@ impl Trait {
794 db: &impl HirDatabase, 752 db: &impl HirDatabase,
795 name: &Name, 753 name: &Name,
796 ) -> Option<TypeAlias> { 754 ) -> Option<TypeAlias> {
797 self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name)) 755 all_super_traits(db, self.id)
756 .into_iter()
757 .map(Trait::from)
758 .find_map(|t| t.associated_type_by_name(db, name))
798 } 759 }
799 760
800 pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef { 761 pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index bd03055b9..2a2dc26b4 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -9,6 +9,7 @@ mod op;
9mod lower; 9mod lower;
10mod infer; 10mod infer;
11pub(crate) mod display; 11pub(crate) mod display;
12pub(crate) mod utils;
12 13
13#[cfg(test)] 14#[cfg(test)]
14mod tests; 15mod tests;
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 2d23890a5..9e3afabe0 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -28,6 +28,7 @@ use crate::{
28 db::HirDatabase, 28 db::HirDatabase,
29 ty::{ 29 ty::{
30 primitive::{FloatTy, IntTy}, 30 primitive::{FloatTy, IntTy},
31 utils::all_super_traits,
31 Adt, 32 Adt,
32 }, 33 },
33 util::make_mut_slice, 34 util::make_mut_slice,
@@ -260,7 +261,7 @@ impl Ty {
260 GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_), 261 GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_),
261 _ => None, 262 _ => None,
262 }); 263 });
263 let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); 264 let traits = traits_from_env.flat_map(|t| all_super_traits(db, t.id)).map(Trait::from);
264 for t in traits { 265 for t in traits {
265 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { 266 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) {
266 let substs = Substs::build_for_def(db, t.id) 267 let substs = Substs::build_for_def(db, t.id)
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 489fcd64b..0e18684ed 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -16,7 +16,7 @@ use rustc_hash::FxHashMap;
16use crate::{ 16use crate::{
17 db::HirDatabase, 17 db::HirDatabase,
18 ty::primitive::{FloatBitness, Uncertain}, 18 ty::primitive::{FloatBitness, Uncertain},
19 ty::{Ty, TypeCtor}, 19 ty::{utils::all_super_traits, Ty, TypeCtor},
20 AssocItem, Crate, Function, Mutability, Name, Trait, 20 AssocItem, Crate, Function, Mutability, Name, Trait,
21}; 21};
22 22
@@ -249,7 +249,8 @@ fn iterate_trait_method_candidates<T>(
249 let traits_from_env = env 249 let traits_from_env = env
250 .trait_predicates_for_self_ty(&ty.value) 250 .trait_predicates_for_self_ty(&ty.value)
251 .map(|tr| tr.trait_) 251 .map(|tr| tr.trait_)
252 .flat_map(|t| t.all_super_traits(db)); 252 .flat_map(|t| all_super_traits(db, t.id))
253 .map(Trait::from);
253 let traits = inherent_trait 254 let traits = inherent_trait
254 .chain(traits_from_env) 255 .chain(traits_from_env)
255 .chain(resolver.traits_in_scope(db).into_iter().map(Trait::from)); 256 .chain(resolver.traits_in_scope(db).into_iter().map(Trait::from));
diff --git a/crates/ra_hir/src/ty/utils.rs b/crates/ra_hir/src/ty/utils.rs
new file mode 100644
index 000000000..345fa9430
--- /dev/null
+++ b/crates/ra_hir/src/ty/utils.rs
@@ -0,0 +1,50 @@
1use hir_def::{
2 db::DefDatabase,
3 resolver::{HasResolver, TypeNs},
4 type_ref::TypeRef,
5 TraitId,
6};
7use hir_expand::name;
8
9// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
10// We should return a `TraitREf` here.
11fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
12 let resolver = trait_.resolver(db);
13 // returning the iterator directly doesn't easily work because of
14 // lifetime problems, but since there usually shouldn't be more than a
15 // few direct traits this should be fine (we could even use some kind of
16 // SmallVec if performance is a concern)
17 db.generic_params(trait_.into())
18 .where_predicates
19 .iter()
20 .filter_map(|pred| match &pred.type_ref {
21 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
22 _ => None,
23 })
24 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
25 Some(TypeNs::TraitId(t)) => Some(t),
26 _ => None,
27 })
28 .collect()
29}
30
31/// Returns an iterator over the whole super trait hierarchy (including the
32/// trait itself).
33pub(crate) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
34 // we need to take care a bit here to avoid infinite loops in case of cycles
35 // (i.e. if we have `trait A: B; trait B: A;`)
36 let mut result = vec![trait_];
37 let mut i = 0;
38 while i < result.len() {
39 let t = result[i];
40 // yeah this is quadratic, but trait hierarchies should be flat
41 // enough that this doesn't matter
42 for tt in direct_super_traits(db, t) {
43 if !result.contains(&tt) {
44 result.push(tt);
45 }
46 }
47 i += 1;
48 }
49 result
50}