aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-09-07 15:24:26 +0100
committerFlorian Diebold <[email protected]>2019-09-07 15:30:31 +0100
commita1776b27c7d7c266d751360b80cc573b1520ef65 (patch)
tree743356958f4968ae08f5891f10a09bfbc6eb6443 /crates/ra_hir
parentd21cdf3c998bb24e48e81a7e6909df2146ce097c (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')
-rw-r--r--crates/ra_hir/src/code_model.rs21
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs8
-rw-r--r--crates/ra_hir/src/ty/tests.rs21
-rw-r--r--crates/ra_hir/src/ty/traits.rs15
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}
3676trait Trait1: SuperTrait {} 3675trait Trait1: foo::SuperTrait {}
3677trait Trait2 where Self: SuperTrait {} 3676trait Trait2 where Self: foo::SuperTrait {}
3678 3677
3679fn test<T: Trait1, U: Trait2>(x: T, y: U) { 3678fn 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
99impl 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)]
101pub struct InEnvironment<T> { 116pub struct InEnvironment<T> {