aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/code_model.rs61
-rw-r--r--crates/ra_hir/src/ty.rs1
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs10
-rw-r--r--crates/ra_hir/src/ty/infer.rs14
-rw-r--r--crates/ra_hir/src/ty/lower.rs32
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs11
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs33
-rw-r--r--crates/ra_hir/src/ty/utils.rs63
-rw-r--r--crates/ra_hir_def/src/data.rs55
9 files changed, 156 insertions, 124 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 821f919d4..9578c20b0 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,
@@ -737,64 +737,7 @@ impl Trait {
737 } 737 }
738 738
739 pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> { 739 pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> {
740 db.trait_data(self.id).items.iter().map(|it| (*it).into()).collect() 740 db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
741 }
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> {
786 let trait_data = db.trait_data(self.id);
787 let res =
788 trait_data.associated_types().map(TypeAlias::from).find(|t| &t.name(db) == name)?;
789 Some(res)
790 }
791
792 pub fn associated_type_by_name_including_super_traits(
793 self,
794 db: &impl HirDatabase,
795 name: &Name,
796 ) -> Option<TypeAlias> {
797 self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name))
798 } 741 }
799 742
800 pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef { 743 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/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 9e7593b8b..ae68234ac 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -10,7 +10,7 @@ use hir_expand::name;
10use log::{info, warn}; 10use log::{info, warn};
11use ra_db::CrateId; 11use ra_db::CrateId;
12 12
13use crate::{db::HirDatabase, Trait}; 13use crate::db::HirDatabase;
14 14
15use super::{ 15use super::{
16 traits::{InEnvironment, Solution}, 16 traits::{InEnvironment, Solution},
@@ -49,12 +49,12 @@ fn deref_by_trait(
49 ty: InEnvironment<&Canonical<Ty>>, 49 ty: InEnvironment<&Canonical<Ty>>,
50) -> Option<Canonical<Ty>> { 50) -> Option<Canonical<Ty>> {
51 let deref_trait = match db.lang_item(krate.into(), "deref".into())? { 51 let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
52 LangItemTarget::TraitId(t) => Trait::from(t), 52 LangItemTarget::TraitId(it) => it,
53 _ => return None, 53 _ => return None,
54 }; 54 };
55 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; 55 let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?;
56 56
57 let generic_params = db.generic_params(target.id.into()); 57 let generic_params = db.generic_params(target.into());
58 if generic_params.count_params_including_parent() != 1 { 58 if generic_params.count_params_including_parent() != 1 {
59 // the Target type + Deref trait should only have one generic parameter, 59 // the Target type + Deref trait should only have one generic parameter,
60 // namely Deref's Self type 60 // namely Deref's Self type
@@ -69,7 +69,7 @@ fn deref_by_trait(
69 69
70 let projection = super::traits::ProjectionPredicate { 70 let projection = super::traits::ProjectionPredicate {
71 ty: Ty::Bound(0), 71 ty: Ty::Bound(0),
72 projection_ty: super::ProjectionTy { associated_ty: target.id, parameters }, 72 projection_ty: super::ProjectionTy { associated_ty: target, parameters },
73 }; 73 };
74 74
75 let obligation = super::Obligation::Projection(projection); 75 let obligation = super::Obligation::Projection(projection);
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index fce45321d..b023ae690 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -43,7 +43,7 @@ use crate::{
43 db::HirDatabase, 43 db::HirDatabase,
44 expr::{BindingAnnotation, Body, ExprId, PatId}, 44 expr::{BindingAnnotation, Body, ExprId, PatId},
45 ty::infer::diagnostics::InferenceDiagnostic, 45 ty::infer::diagnostics::InferenceDiagnostic,
46 Adt, AssocItem, DefWithBody, FloatTy, Function, IntTy, Path, StructField, Trait, VariantDef, 46 Adt, AssocItem, DefWithBody, FloatTy, Function, IntTy, Path, StructField, VariantDef,
47}; 47};
48 48
49macro_rules! ty_app { 49macro_rules! ty_app {
@@ -582,20 +582,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
582 582
583 fn resolve_into_iter_item(&self) -> Option<TypeAlias> { 583 fn resolve_into_iter_item(&self) -> Option<TypeAlias> {
584 let path = known::std_iter_into_iterator(); 584 let path = known::std_iter_into_iterator();
585 let trait_: Trait = self.resolver.resolve_known_trait(self.db, &path)?.into(); 585 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
586 trait_.associated_type_by_name(self.db, &name::ITEM_TYPE) 586 self.db.trait_data(trait_).associated_type_by_name(&name::ITEM_TYPE).map(TypeAlias::from)
587 } 587 }
588 588
589 fn resolve_ops_try_ok(&self) -> Option<TypeAlias> { 589 fn resolve_ops_try_ok(&self) -> Option<TypeAlias> {
590 let path = known::std_ops_try(); 590 let path = known::std_ops_try();
591 let trait_: Trait = self.resolver.resolve_known_trait(self.db, &path)?.into(); 591 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
592 trait_.associated_type_by_name(self.db, &name::OK_TYPE) 592 self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE).map(TypeAlias::from)
593 } 593 }
594 594
595 fn resolve_future_future_output(&self) -> Option<TypeAlias> { 595 fn resolve_future_future_output(&self) -> Option<TypeAlias> {
596 let path = known::std_future_future(); 596 let path = known::std_future_future();
597 let trait_: Trait = self.resolver.resolve_known_trait(self.db, &path)?.into(); 597 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
598 trait_.associated_type_by_name(self.db, &name::OUTPUT_TYPE) 598 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE).map(TypeAlias::from)
599 } 599 }
600 600
601 fn resolve_boxed_box(&self) -> Option<AdtId> { 601 fn resolve_boxed_box(&self) -> Option<AdtId> {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 2d23890a5..805a73ff5 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, associated_type_by_name_including_super_traits},
31 Adt, 32 Adt,
32 }, 33 },
33 util::make_mut_slice, 34 util::make_mut_slice,
@@ -169,14 +170,16 @@ impl Ty {
169 ); 170 );
170 return if remaining_segments.len() == 1 { 171 return if remaining_segments.len() == 1 {
171 let segment = &remaining_segments[0]; 172 let segment = &remaining_segments[0];
172 match trait_ref 173 let associated_ty = associated_type_by_name_including_super_traits(
173 .trait_ 174 db,
174 .associated_type_by_name_including_super_traits(db, &segment.name) 175 trait_ref.trait_.id,
175 { 176 &segment.name,
177 );
178 match associated_ty {
176 Some(associated_ty) => { 179 Some(associated_ty) => {
177 // FIXME handle type parameters on the segment 180 // FIXME handle type parameters on the segment
178 Ty::Projection(ProjectionTy { 181 Ty::Projection(ProjectionTy {
179 associated_ty: associated_ty.id, 182 associated_ty,
180 parameters: trait_ref.substs, 183 parameters: trait_ref.substs,
181 }) 184 })
182 } 185 }
@@ -260,18 +263,16 @@ impl Ty {
260 GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_), 263 GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_),
261 _ => None, 264 _ => None,
262 }); 265 });
263 let traits = traits_from_env.flat_map(|t| t.all_super_traits(db)); 266 let traits = traits_from_env.flat_map(|t| all_super_traits(db, t.id)).map(Trait::from);
264 for t in traits { 267 for t in traits {
265 if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) { 268 if let Some(associated_ty) = db.trait_data(t.id).associated_type_by_name(&segment.name)
269 {
266 let substs = Substs::build_for_def(db, t.id) 270 let substs = Substs::build_for_def(db, t.id)
267 .push(self_ty.clone()) 271 .push(self_ty.clone())
268 .fill_with_unknown() 272 .fill_with_unknown()
269 .build(); 273 .build();
270 // FIXME handle type parameters on the segment 274 // FIXME handle type parameters on the segment
271 return Ty::Projection(ProjectionTy { 275 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
272 associated_ty: associated_ty.id,
273 parameters: substs,
274 });
275 } 276 }
276 } 277 }
277 Ty::Unknown 278 Ty::Unknown
@@ -509,10 +510,11 @@ fn assoc_type_bindings_from_type_bound<'a>(
509 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) 510 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
510 .map(move |(name, type_ref)| { 511 .map(move |(name, type_ref)| {
511 let associated_ty = 512 let associated_ty =
512 match trait_ref.trait_.associated_type_by_name_including_super_traits(db, &name) { 513 associated_type_by_name_including_super_traits(db, trait_ref.trait_.id, &name);
513 None => return GenericPredicate::Error, 514 let associated_ty = match associated_ty {
514 Some(t) => t.id, 515 None => return GenericPredicate::Error,
515 }; 516 Some(t) => t,
517 };
516 let projection_ty = 518 let projection_ty =
517 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; 519 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
518 let ty = Ty::from_hir(db, resolver, type_ref); 520 let ty = Ty::from_hir(db, resolver, type_ref);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 489fcd64b..9988570e8 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));
@@ -260,8 +261,8 @@ fn iterate_trait_method_candidates<T>(
260 // trait, but if we find out it doesn't, we'll skip the rest of the 261 // trait, but if we find out it doesn't, we'll skip the rest of the
261 // iteration 262 // iteration
262 let mut known_implemented = false; 263 let mut known_implemented = false;
263 for &item in data.items.iter() { 264 for (_name, item) in data.items.iter() {
264 if !is_valid_candidate(db, name, mode, item.into()) { 265 if !is_valid_candidate(db, name, mode, (*item).into()) {
265 continue; 266 continue;
266 } 267 }
267 if !known_implemented { 268 if !known_implemented {
@@ -271,7 +272,7 @@ fn iterate_trait_method_candidates<T>(
271 } 272 }
272 } 273 }
273 known_implemented = true; 274 known_implemented = true;
274 if let Some(result) = callback(&ty.value, item.into()) { 275 if let Some(result) = callback(&ty.value, (*item).into()) {
275 return Some(result); 276 return Some(result);
276 } 277 }
277 } 278 }
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 06388a3ce..78f4b3e27 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -9,7 +9,7 @@ use chalk_ir::{
9}; 9};
10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11 11
12use hir_def::{lang_item::LangItemTarget, ContainerId, GenericDefId, Lookup, TypeAliasId}; 12use hir_def::{lang_item::LangItemTarget, ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId};
13use hir_expand::name; 13use hir_expand::name;
14 14
15use ra_db::salsa::{InternId, InternKey}; 15use ra_db::salsa::{InternId, InternKey};
@@ -459,7 +459,7 @@ where
459 [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() 459 [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
460 { 460 {
461 if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) { 461 if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
462 if trait_ == actual_trait { 462 if trait_.id == actual_trait {
463 let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait }; 463 let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait };
464 result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db)); 464 result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db));
465 } 465 }
@@ -661,6 +661,7 @@ fn impl_block_datum(
661 }; 661 };
662 662
663 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses }; 663 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses };
664 let trait_data = db.trait_data(trait_.id);
664 let associated_ty_value_ids = impl_block 665 let associated_ty_value_ids = impl_block
665 .items(db) 666 .items(db)
666 .into_iter() 667 .into_iter()
@@ -670,7 +671,7 @@ fn impl_block_datum(
670 }) 671 })
671 .filter(|type_alias| { 672 .filter(|type_alias| {
672 // don't include associated types that don't exist in the trait 673 // don't include associated types that don't exist in the trait
673 trait_.associated_type_by_name(db, &type_alias.name(db)).is_some() 674 trait_data.associated_type_by_name(&type_alias.name(db)).is_some()
674 }) 675 })
675 .map(|type_alias| AssocTyValue::TypeAlias(type_alias).to_chalk(db)) 676 .map(|type_alias| AssocTyValue::TypeAlias(type_alias).to_chalk(db))
676 .collect(); 677 .collect();
@@ -713,7 +714,7 @@ fn closure_fn_trait_impl_datum(
713 // and don't want to return a valid value only to find out later that FnOnce 714 // and don't want to return a valid value only to find out later that FnOnce
714 // is broken 715 // is broken
715 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; 716 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
716 fn_once_trait.associated_type_by_name(db, &name::OUTPUT_TYPE)?; 717 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?;
717 718
718 let num_args: u16 = match &db.body(data.def.into())[data.expr] { 719 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
719 crate::expr::Expr::Lambda { args, .. } => args.len() as u16, 720 crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
@@ -735,8 +736,8 @@ fn closure_fn_trait_impl_datum(
735 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); 736 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
736 737
737 let trait_ref = TraitRef { 738 let trait_ref = TraitRef {
738 trait_, 739 trait_: trait_.into(),
739 substs: Substs::build_for_def(db, trait_.id).push(self_ty).push(arg_ty).build(), 740 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
740 }; 741 };
741 742
742 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db); 743 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db);
@@ -783,10 +784,10 @@ fn type_alias_associated_ty_value(
783 .target_trait_ref(db) 784 .target_trait_ref(db)
784 .expect("assoc ty value should not exist") // we don't return any assoc ty values if the impl'd trait can't be resolved 785 .expect("assoc ty value should not exist") // we don't return any assoc ty values if the impl'd trait can't be resolved
785 .trait_; 786 .trait_;
786 let assoc_ty = trait_ 787 let assoc_ty = db
787 .associated_type_by_name(db, &type_alias.name(db)) 788 .trait_data(trait_.id)
788 .expect("assoc ty value should not exist") // validated when building the impl data as well 789 .associated_type_by_name(&type_alias.name(db))
789 .id; 790 .expect("assoc ty value should not exist"); // validated when building the impl data as well
790 let generic_params = db.generic_params(impl_block.id.into()); 791 let generic_params = db.generic_params(impl_block.id.into());
791 let bound_vars = Substs::bound_vars(&generic_params); 792 let bound_vars = Substs::bound_vars(&generic_params);
792 let ty = db.type_for_def(type_alias.into(), crate::ty::Namespace::Types).subst(&bound_vars); 793 let ty = db.type_for_def(type_alias.into(), crate::ty::Namespace::Types).subst(&bound_vars);
@@ -819,10 +820,10 @@ fn closure_fn_trait_output_assoc_ty_value(
819 let fn_once_trait = 820 let fn_once_trait =
820 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist"); 821 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
821 822
822 let output_ty_id = fn_once_trait 823 let output_ty_id = db
823 .associated_type_by_name(db, &name::OUTPUT_TYPE) 824 .trait_data(fn_once_trait)
824 .expect("assoc ty value should not exist") 825 .associated_type_by_name(&name::OUTPUT_TYPE)
825 .id; 826 .expect("assoc ty value should not exist");
826 827
827 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) }; 828 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) };
828 829
@@ -834,10 +835,10 @@ fn closure_fn_trait_output_assoc_ty_value(
834 Arc::new(value) 835 Arc::new(value)
835} 836}
836 837
837fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { 838fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<TraitId> {
838 let target = db.lang_item(krate.crate_id, fn_trait.lang_item_name().into())?; 839 let target = db.lang_item(krate.crate_id, fn_trait.lang_item_name().into())?;
839 match target { 840 match target {
840 LangItemTarget::TraitId(t) => Some(t.into()), 841 LangItemTarget::TraitId(t) => Some(t),
841 _ => None, 842 _ => None,
842 } 843 }
843} 844}
diff --git a/crates/ra_hir/src/ty/utils.rs b/crates/ra_hir/src/ty/utils.rs
new file mode 100644
index 000000000..52994b9e3
--- /dev/null
+++ b/crates/ra_hir/src/ty/utils.rs
@@ -0,0 +1,63 @@
1//! Helper functions for working with def, which don't need to be a separate
2//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3
4use hir_def::{
5 db::DefDatabase,
6 resolver::{HasResolver, TypeNs},
7 type_ref::TypeRef,
8 TraitId, TypeAliasId,
9};
10use hir_expand::name::{self, Name};
11
12// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
13// We should return a `TraitREf` here.
14fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
15 let resolver = trait_.resolver(db);
16 // returning the iterator directly doesn't easily work because of
17 // lifetime problems, but since there usually shouldn't be more than a
18 // few direct traits this should be fine (we could even use some kind of
19 // SmallVec if performance is a concern)
20 db.generic_params(trait_.into())
21 .where_predicates
22 .iter()
23 .filter_map(|pred| match &pred.type_ref {
24 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
25 _ => None,
26 })
27 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
28 Some(TypeNs::TraitId(t)) => Some(t),
29 _ => None,
30 })
31 .collect()
32}
33
34/// Returns an iterator over the whole super trait hierarchy (including the
35/// trait itself).
36pub(crate) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
37 // we need to take care a bit here to avoid infinite loops in case of cycles
38 // (i.e. if we have `trait A: B; trait B: A;`)
39 let mut result = vec![trait_];
40 let mut i = 0;
41 while i < result.len() {
42 let t = result[i];
43 // yeah this is quadratic, but trait hierarchies should be flat
44 // enough that this doesn't matter
45 for tt in direct_super_traits(db, t) {
46 if !result.contains(&tt) {
47 result.push(tt);
48 }
49 }
50 i += 1;
51 }
52 result
53}
54
55pub(crate) fn associated_type_by_name_including_super_traits(
56 db: &impl DefDatabase,
57 trait_: TraitId,
58 name: &Name,
59) -> Option<TypeAliasId> {
60 all_super_traits(db, trait_)
61 .into_iter()
62 .find_map(|t| db.trait_data(t).associated_type_by_name(name))
63}
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 68bea34df..813099a05 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -87,7 +87,7 @@ impl TypeAliasData {
87#[derive(Debug, Clone, PartialEq, Eq)] 87#[derive(Debug, Clone, PartialEq, Eq)]
88pub struct TraitData { 88pub struct TraitData {
89 pub name: Option<Name>, 89 pub name: Option<Name>,
90 pub items: Vec<AssocItemId>, 90 pub items: Vec<(Name, AssocItemId)>,
91 pub auto: bool, 91 pub auto: bool,
92} 92}
93 93
@@ -97,28 +97,42 @@ impl TraitData {
97 let name = src.value.name().map(|n| n.as_name()); 97 let name = src.value.name().map(|n| n.as_name());
98 let auto = src.value.is_auto(); 98 let auto = src.value.is_auto();
99 let ast_id_map = db.ast_id_map(src.file_id); 99 let ast_id_map = db.ast_id_map(src.file_id);
100
101 let container = ContainerId::TraitId(tr);
100 let items = if let Some(item_list) = src.value.item_list() { 102 let items = if let Some(item_list) = src.value.item_list() {
101 item_list 103 item_list
102 .impl_items() 104 .impl_items()
103 .map(|item_node| match item_node { 105 .map(|item_node| match item_node {
104 ast::ImplItem::FnDef(it) => FunctionLoc { 106 ast::ImplItem::FnDef(it) => {
105 container: ContainerId::TraitId(tr), 107 let name = it.name().map(|it| it.as_name()).unwrap_or_else(Name::missing);
106 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), 108 let def = FunctionLoc {
109 container,
110 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
111 }
112 .intern(db)
113 .into();
114 (name, def)
107 } 115 }
108 .intern(db) 116 ast::ImplItem::ConstDef(it) => {
109 .into(), 117 let name = it.name().map(|it| it.as_name()).unwrap_or_else(Name::missing);
110 ast::ImplItem::ConstDef(it) => ConstLoc { 118 let def = ConstLoc {
111 container: ContainerId::TraitId(tr), 119 container,
112 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), 120 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
121 }
122 .intern(db)
123 .into();
124 (name, def)
113 } 125 }
114 .intern(db) 126 ast::ImplItem::TypeAliasDef(it) => {
115 .into(), 127 let name = it.name().map(|it| it.as_name()).unwrap_or_else(Name::missing);
116 ast::ImplItem::TypeAliasDef(it) => TypeAliasLoc { 128 let def = TypeAliasLoc {
117 container: ContainerId::TraitId(tr), 129 container,
118 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), 130 ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
131 }
132 .intern(db)
133 .into();
134 (name, def)
119 } 135 }
120 .intern(db)
121 .into(),
122 }) 136 })
123 .collect() 137 .collect()
124 } else { 138 } else {
@@ -128,11 +142,18 @@ impl TraitData {
128 } 142 }
129 143
130 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { 144 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
131 self.items.iter().filter_map(|item| match item { 145 self.items.iter().filter_map(|(_name, item)| match item {
132 AssocItemId::TypeAliasId(t) => Some(*t), 146 AssocItemId::TypeAliasId(t) => Some(*t),
133 _ => None, 147 _ => None,
134 }) 148 })
135 } 149 }
150
151 pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> {
152 self.items.iter().find_map(|(item_name, item)| match item {
153 AssocItemId::TypeAliasId(t) if item_name == name => Some(*t),
154 _ => None,
155 })
156 }
136} 157}
137 158
138#[derive(Debug, Clone, PartialEq, Eq)] 159#[derive(Debug, Clone, PartialEq, Eq)]