diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-11-26 14:45:31 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2019-11-26 14:45:31 +0000 |
commit | 6560e4ff2eae4e54384896d6ae100f1d2df20518 (patch) | |
tree | 4d6767c90e5ac4ec5d6f6149e434ebf09dfa82be /crates/ra_hir/src/ty | |
parent | 4d753fa6f514ea1105c25ace91201c5324ee0b92 (diff) | |
parent | 24b1e79af51f5af76047a5eee2fe90baf100afca (diff) |
Merge #2413
2413: Remove another helper r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 32 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/utils.rs | 63 |
6 files changed, 115 insertions, 48 deletions
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; | |||
10 | use log::{info, warn}; | 10 | use log::{info, warn}; |
11 | use ra_db::CrateId; | 11 | use ra_db::CrateId; |
12 | 12 | ||
13 | use crate::{db::HirDatabase, Trait}; | 13 | use crate::db::HirDatabase; |
14 | 14 | ||
15 | use super::{ | 15 | use 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 | ||
49 | macro_rules! ty_app { | 49 | macro_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; | |||
16 | use crate::{ | 16 | use 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 | }; |
10 | use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; | 10 | use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; |
11 | 11 | ||
12 | use hir_def::{lang_item::LangItemTarget, ContainerId, GenericDefId, Lookup, TypeAliasId}; | 12 | use hir_def::{lang_item::LangItemTarget, ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId}; |
13 | use hir_expand::name; | 13 | use hir_expand::name; |
14 | 14 | ||
15 | use ra_db::salsa::{InternId, InternKey}; | 15 | use 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 | ||
837 | fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { | 838 | fn 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 | |||
4 | use hir_def::{ | ||
5 | db::DefDatabase, | ||
6 | resolver::{HasResolver, TypeNs}, | ||
7 | type_ref::TypeRef, | ||
8 | TraitId, TypeAliasId, | ||
9 | }; | ||
10 | use 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. | ||
14 | fn 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). | ||
36 | pub(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 | |||
55 | pub(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 | } | ||