From a1776b27c7d7c266d751360b80cc573b1520ef65 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 7 Sep 2019 16:24:26 +0200 Subject: 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. --- crates/ra_hir/src/ty/method_resolution.rs | 8 +++++++- crates/ra_hir/src/ty/tests.rs | 21 ++++++++++----------- crates/ra_hir/src/ty/traits.rs | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 12 deletions(-) (limited to 'crates/ra_hir/src/ty') 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( // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) let env = lower::trait_env(db, resolver); // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope - let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db)); + let inherent_trait = ty.value.inherent_trait().into_iter(); + // if we have `T: Trait` in the param env, the trait doesn't need to be in scope + let traits_from_env = env + .trait_predicates_for_self_ty(&ty.value) + .map(|tr| tr.trait_) + .flat_map(|t| t.all_super_traits(db)); + let traits = inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db)); 'traits: for t in traits { let data = t.trait_data(db); 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(x: T) { } "#, ); - // FIXME should be u32 - assert_eq!(t, "{unknown}"); + assert_eq!(t, "u32"); } #[test] @@ -3673,8 +3672,8 @@ mod foo { fn foo(&self) -> u32 {} } } -trait Trait1: SuperTrait {} -trait Trait2 where Self: SuperTrait {} +trait Trait1: foo::SuperTrait {} +trait Trait2 where Self: foo::SuperTrait {} fn test(x: T, y: U) { x.foo(); @@ -3684,13 +3683,13 @@ fn test(x: T, y: U) { @r###" [50; 54) 'self': &Self [63; 65) '{}': () - [172; 173) 'x': T - [178; 179) 'y': U - [184; 213) '{ ...o(); }': () - [190; 191) 'x': T - [190; 197) 'x.foo()': {unknown} - [203; 204) 'y': U - [203; 210) 'y.foo()': {unknown} + [182; 183) 'x': T + [188; 189) 'y': U + [194; 223) '{ ...o(); }': () + [200; 201) 'x': T + [200; 207) 'x.foo()': {unknown} + [213; 214) 'y': U + [213; 220) 'y.foo()': {unknown} "### ); } 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 { pub predicates: Vec, } +impl TraitEnvironment { + /// Returns trait refs with the given self type which are supposed to hold + /// in this trait env. E.g. if we are in `foo()`, this will + /// find that `T: SomeTrait` if we call it for `T`. + pub(crate) fn trait_predicates_for_self_ty<'a>( + &'a self, + ty: &'a Ty, + ) -> impl Iterator + 'a { + self.predicates.iter().filter_map(move |pred| match pred { + GenericPredicate::Implemented(tr) if tr.self_ty() == ty => Some(tr), + _ => None, + }) + } +} + /// Something (usually a goal), along with an environment. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct InEnvironment { -- cgit v1.2.3