From 4a0792362e2c6cae2809520da454471d5a917384 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 26 Nov 2019 16:59:24 +0300 Subject: Detangle ty from traits a bit --- crates/ra_hir/src/ty/lower.rs | 3 +- crates/ra_hir/src/ty/method_resolution.rs | 5 ++-- crates/ra_hir/src/ty/utils.rs | 50 +++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 crates/ra_hir/src/ty/utils.rs (limited to 'crates/ra_hir/src/ty') 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::{ db::HirDatabase, ty::{ primitive::{FloatTy, IntTy}, + utils::all_super_traits, Adt, }, util::make_mut_slice, @@ -260,7 +261,7 @@ impl Ty { GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_), _ => None, }); - let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); + let traits = traits_from_env.flat_map(|t| all_super_traits(db, t.id)).map(Trait::from); for t in traits { if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { 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; use crate::{ db::HirDatabase, ty::primitive::{FloatBitness, Uncertain}, - ty::{Ty, TypeCtor}, + ty::{utils::all_super_traits, Ty, TypeCtor}, AssocItem, Crate, Function, Mutability, Name, Trait, }; @@ -249,7 +249,8 @@ fn iterate_trait_method_candidates( let traits_from_env = env .trait_predicates_for_self_ty(&ty.value) .map(|tr| tr.trait_) - .flat_map(|t| t.all_super_traits(db)); + .flat_map(|t| all_super_traits(db, t.id)) + .map(Trait::from); let traits = inherent_trait .chain(traits_from_env) .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 @@ +use hir_def::{ + db::DefDatabase, + resolver::{HasResolver, TypeNs}, + type_ref::TypeRef, + TraitId, +}; +use hir_expand::name; + +// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`. +// We should return a `TraitREf` here. +fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { + let resolver = trait_.resolver(db); + // returning the iterator directly doesn't easily work because of + // lifetime problems, but since there usually shouldn't be more than a + // few direct traits this should be fine (we could even use some kind of + // SmallVec if performance is a concern) + db.generic_params(trait_.into()) + .where_predicates + .iter() + .filter_map(|pred| match &pred.type_ref { + TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(), + _ => None, + }) + .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { + Some(TypeNs::TraitId(t)) => Some(t), + _ => None, + }) + .collect() +} + +/// Returns an iterator over the whole super trait hierarchy (including the +/// trait itself). +pub(crate) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec { + // we need to take care a bit here to avoid infinite loops in case of cycles + // (i.e. if we have `trait A: B; trait B: A;`) + let mut result = vec![trait_]; + let mut i = 0; + while i < result.len() { + let t = result[i]; + // yeah this is quadratic, but trait hierarchies should be flat + // enough that this doesn't matter + for tt in direct_super_traits(db, t) { + if !result.contains(&tt) { + result.push(tt); + } + } + i += 1; + } + result +} -- cgit v1.2.3