diff options
author | Florian Diebold <[email protected]> | 2019-09-07 15:24:26 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-07 15:30:31 +0100 |
commit | a1776b27c7d7c266d751360b80cc573b1520ef65 (patch) | |
tree | 743356958f4968ae08f5891f10a09bfbc6eb6443 /crates/ra_hir/src | |
parent | d21cdf3c998bb24e48e81a7e6909df2146ce097c (diff) |
Use traits from where clauses for method resolution
E.g. if we have `T: some::Trait`, we can call methods from that trait without it
needing to be in scope.
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 15 |
4 files changed, 44 insertions, 21 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 4739246cb..52ee1834f 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -847,16 +847,22 @@ impl Trait { | |||
847 | .collect() | 847 | .collect() |
848 | } | 848 | } |
849 | 849 | ||
850 | /// Returns an iterator over the whole super trait hierarchy (not including | 850 | /// Returns an iterator over the whole super trait hierarchy (including the |
851 | /// the trait itself). (This iterator may be infinite in case of circular | 851 | /// trait itself). |
852 | /// super trait dependencies, which are possible in malformed code.) | ||
853 | pub fn all_super_traits<'a>( | 852 | pub fn all_super_traits<'a>( |
854 | self, | 853 | self, |
855 | db: &'a impl HirDatabase, | 854 | db: &'a impl HirDatabase, |
856 | ) -> impl Iterator<Item = Trait> + 'a { | 855 | ) -> impl Iterator<Item = Trait> + 'a { |
857 | self.direct_super_traits(db).into_iter().flat_map(move |t| { | 856 | self.all_super_traits_inner(db).unique() |
857 | } | ||
858 | |||
859 | fn all_super_traits_inner<'a>( | ||
860 | self, | ||
861 | db: &'a impl HirDatabase, | ||
862 | ) -> impl Iterator<Item = Trait> + 'a { | ||
863 | iter::once(self).chain(self.direct_super_traits(db).into_iter().flat_map(move |t| { | ||
858 | iter::once(t).chain(Box::new(t.all_super_traits(db)) as Box<dyn Iterator<Item = Trait>>) | 864 | iter::once(t).chain(Box::new(t.all_super_traits(db)) as Box<dyn Iterator<Item = Trait>>) |
859 | }) | 865 | })) |
860 | } | 866 | } |
861 | 867 | ||
862 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { | 868 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { |
@@ -876,10 +882,7 @@ impl Trait { | |||
876 | db: &impl HirDatabase, | 882 | db: &impl HirDatabase, |
877 | name: &Name, | 883 | name: &Name, |
878 | ) -> Option<TypeAlias> { | 884 | ) -> Option<TypeAlias> { |
879 | iter::once(self) | 885 | self.all_super_traits(db).find_map(|t| t.associated_type_by_name(db, name)) |
880 | .chain(self.all_super_traits(db)) | ||
881 | .unique() | ||
882 | .find_map(|t| t.associated_type_by_name(db, name)) | ||
883 | } | 886 | } |
884 | 887 | ||
885 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | 888 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 9873a0440..cf787bdaa 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -212,7 +212,13 @@ fn iterate_trait_method_candidates<T>( | |||
212 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) | 212 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) |
213 | let env = lower::trait_env(db, resolver); | 213 | let env = lower::trait_env(db, resolver); |
214 | // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope | 214 | // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope |
215 | let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db)); | 215 | let inherent_trait = ty.value.inherent_trait().into_iter(); |
216 | // if we have `T: Trait` in the param env, the trait doesn't need to be in scope | ||
217 | let traits_from_env = env | ||
218 | .trait_predicates_for_self_ty(&ty.value) | ||
219 | .map(|tr| tr.trait_) | ||
220 | .flat_map(|t| t.all_super_traits(db)); | ||
221 | let traits = inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db)); | ||
216 | 'traits: for t in traits { | 222 | 'traits: for t in traits { |
217 | let data = t.trait_data(db); | 223 | let data = t.trait_data(db); |
218 | 224 | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index c414e6a95..127c69f8a 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3660,8 +3660,7 @@ fn test<T: foo::Trait>(x: T) { | |||
3660 | } | 3660 | } |
3661 | "#, | 3661 | "#, |
3662 | ); | 3662 | ); |
3663 | // FIXME should be u32 | 3663 | assert_eq!(t, "u32"); |
3664 | assert_eq!(t, "{unknown}"); | ||
3665 | } | 3664 | } |
3666 | 3665 | ||
3667 | #[test] | 3666 | #[test] |
@@ -3673,8 +3672,8 @@ mod foo { | |||
3673 | fn foo(&self) -> u32 {} | 3672 | fn foo(&self) -> u32 {} |
3674 | } | 3673 | } |
3675 | } | 3674 | } |
3676 | trait Trait1: SuperTrait {} | 3675 | trait Trait1: foo::SuperTrait {} |
3677 | trait Trait2 where Self: SuperTrait {} | 3676 | trait Trait2 where Self: foo::SuperTrait {} |
3678 | 3677 | ||
3679 | fn test<T: Trait1, U: Trait2>(x: T, y: U) { | 3678 | fn test<T: Trait1, U: Trait2>(x: T, y: U) { |
3680 | x.foo(); | 3679 | x.foo(); |
@@ -3684,13 +3683,13 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) { | |||
3684 | @r###" | 3683 | @r###" |
3685 | [50; 54) 'self': &Self | 3684 | [50; 54) 'self': &Self |
3686 | [63; 65) '{}': () | 3685 | [63; 65) '{}': () |
3687 | [172; 173) 'x': T | 3686 | [182; 183) 'x': T |
3688 | [178; 179) 'y': U | 3687 | [188; 189) 'y': U |
3689 | [184; 213) '{ ...o(); }': () | 3688 | [194; 223) '{ ...o(); }': () |
3690 | [190; 191) 'x': T | 3689 | [200; 201) 'x': T |
3691 | [190; 197) 'x.foo()': {unknown} | 3690 | [200; 207) 'x.foo()': {unknown} |
3692 | [203; 204) 'y': U | 3691 | [213; 214) 'y': U |
3693 | [203; 210) 'y.foo()': {unknown} | 3692 | [213; 220) 'y.foo()': {unknown} |
3694 | "### | 3693 | "### |
3695 | ); | 3694 | ); |
3696 | } | 3695 | } |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 6e0271a96..c0c132809 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -96,6 +96,21 @@ pub struct TraitEnvironment { | |||
96 | pub predicates: Vec<GenericPredicate>, | 96 | pub predicates: Vec<GenericPredicate>, |
97 | } | 97 | } |
98 | 98 | ||
99 | impl TraitEnvironment { | ||
100 | /// Returns trait refs with the given self type which are supposed to hold | ||
101 | /// in this trait env. E.g. if we are in `foo<T: SomeTrait>()`, this will | ||
102 | /// find that `T: SomeTrait` if we call it for `T`. | ||
103 | pub(crate) fn trait_predicates_for_self_ty<'a>( | ||
104 | &'a self, | ||
105 | ty: &'a Ty, | ||
106 | ) -> impl Iterator<Item = &'a TraitRef> + 'a { | ||
107 | self.predicates.iter().filter_map(move |pred| match pred { | ||
108 | GenericPredicate::Implemented(tr) if tr.self_ty() == ty => Some(tr), | ||
109 | _ => None, | ||
110 | }) | ||
111 | } | ||
112 | } | ||
113 | |||
99 | /// Something (usually a goal), along with an environment. | 114 | /// Something (usually a goal), along with an environment. |
100 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 115 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
101 | pub struct InEnvironment<T> { | 116 | pub struct InEnvironment<T> { |