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/code_model.rs | 53 ++++--------------------------- crates/ra_hir/src/ty.rs | 1 + 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 +++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 49 deletions(-) create mode 100644 crates/ra_hir/src/ty/utils.rs 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::{ builtin_type::BuiltinType, docs::Documentation, per_ns::PerNs, - resolver::{HasResolver, TypeNs}, + resolver::HasResolver, type_ref::{Mutability, TypeRef}, AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, @@ -28,8 +28,8 @@ use crate::{ expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, ty::display::HirFormatter, ty::{ - self, InEnvironment, InferenceResult, Namespace, TraitEnvironment, TraitRef, Ty, TypeCtor, - TypeWalk, + self, utils::all_super_traits, InEnvironment, InferenceResult, Namespace, TraitEnvironment, + TraitRef, Ty, TypeCtor, TypeWalk, }, CallableDef, Either, HirDisplay, Name, Source, }; @@ -740,48 +740,6 @@ impl Trait { db.trait_data(self.id).items.iter().map(|it| (*it).into()).collect() } - fn direct_super_traits(self, db: &impl HirDatabase) -> Vec { - let resolver = self.id.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(self.id.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, - }) - .map(Trait::from) - .collect() - } - - /// Returns an iterator over the whole super trait hierarchy (including the - /// trait itself). - pub fn all_super_traits(self, db: &impl HirDatabase) -> 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![self]; - 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 t.direct_super_traits(db) { - if !result.contains(&tt) { - result.push(tt); - } - } - i += 1; - } - result - } - pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option { let trait_data = db.trait_data(self.id); let res = @@ -794,7 +752,10 @@ impl Trait { db: &impl HirDatabase, name: &Name, ) -> Option { - self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name)) + all_super_traits(db, self.id) + .into_iter() + .map(Trait::from) + .find_map(|t| t.associated_type_by_name(db, name)) } 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; mod lower; mod infer; pub(crate) mod display; +pub(crate) mod utils; #[cfg(test)] mod 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::{ 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