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.
This commit is contained in:
Florian Diebold 2019-09-07 16:24:26 +02:00
parent d21cdf3c99
commit a1776b27c7
4 changed files with 44 additions and 21 deletions

View file

@ -847,16 +847,22 @@ impl Trait {
.collect() .collect()
} }
/// Returns an iterator over the whole super trait hierarchy (not including /// Returns an iterator over the whole super trait hierarchy (including the
/// the trait itself). (This iterator may be infinite in case of circular /// trait itself).
/// super trait dependencies, which are possible in malformed code.)
pub fn all_super_traits<'a>( pub fn all_super_traits<'a>(
self, self,
db: &'a impl HirDatabase, db: &'a impl HirDatabase,
) -> impl Iterator<Item = Trait> + 'a { ) -> impl Iterator<Item = Trait> + 'a {
self.direct_super_traits(db).into_iter().flat_map(move |t| { self.all_super_traits_inner(db).unique()
}
fn all_super_traits_inner<'a>(
self,
db: &'a impl HirDatabase,
) -> impl Iterator<Item = Trait> + 'a {
iter::once(self).chain(self.direct_super_traits(db).into_iter().flat_map(move |t| {
iter::once(t).chain(Box::new(t.all_super_traits(db)) as Box<dyn Iterator<Item = Trait>>) iter::once(t).chain(Box::new(t.all_super_traits(db)) as Box<dyn Iterator<Item = Trait>>)
}) }))
} }
pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
@ -876,10 +882,7 @@ impl Trait {
db: &impl HirDatabase, db: &impl HirDatabase,
name: &Name, name: &Name,
) -> Option<TypeAlias> { ) -> Option<TypeAlias> {
iter::once(self) self.all_super_traits(db).find_map(|t| t.associated_type_by_name(db, name))
.chain(self.all_super_traits(db))
.unique()
.find_map(|t| t.associated_type_by_name(db, name))
} }
pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {

View file

@ -212,7 +212,13 @@ fn iterate_trait_method_candidates<T>(
// FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) // 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); let env = lower::trait_env(db, resolver);
// if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope // 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 { 'traits: for t in traits {
let data = t.trait_data(db); let data = t.trait_data(db);

View file

@ -3660,8 +3660,7 @@ fn test<T: foo::Trait>(x: T) {
} }
"#, "#,
); );
// FIXME should be u32 assert_eq!(t, "u32");
assert_eq!(t, "{unknown}");
} }
#[test] #[test]
@ -3673,8 +3672,8 @@ mod foo {
fn foo(&self) -> u32 {} fn foo(&self) -> u32 {}
} }
} }
trait Trait1: SuperTrait {} trait Trait1: foo::SuperTrait {}
trait Trait2 where Self: SuperTrait {} trait Trait2 where Self: foo::SuperTrait {}
fn test<T: Trait1, U: Trait2>(x: T, y: U) { fn test<T: Trait1, U: Trait2>(x: T, y: U) {
x.foo(); x.foo();
@ -3684,13 +3683,13 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
@r###" @r###"
[50; 54) 'self': &Self [50; 54) 'self': &Self
[63; 65) '{}': () [63; 65) '{}': ()
[172; 173) 'x': T [182; 183) 'x': T
[178; 179) 'y': U [188; 189) 'y': U
[184; 213) '{ ...o(); }': () [194; 223) '{ ...o(); }': ()
[190; 191) 'x': T [200; 201) 'x': T
[190; 197) 'x.foo()': {unknown} [200; 207) 'x.foo()': {unknown}
[203; 204) 'y': U [213; 214) 'y': U
[203; 210) 'y.foo()': {unknown} [213; 220) 'y.foo()': {unknown}
"### "###
); );
} }

View file

@ -96,6 +96,21 @@ pub struct TraitEnvironment {
pub predicates: Vec<GenericPredicate>, pub predicates: Vec<GenericPredicate>,
} }
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<T: SomeTrait>()`, 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<Item = &'a TraitRef> + '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. /// Something (usually a goal), along with an environment.
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct InEnvironment<T> { pub struct InEnvironment<T> {