mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 05:53:45 +00:00
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:
parent
d21cdf3c99
commit
a1776b27c7
4 changed files with 44 additions and 21 deletions
|
@ -847,16 +847,22 @@ impl Trait {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Returns an iterator over the whole super trait hierarchy (not including
|
||||
/// the trait itself). (This iterator may be infinite in case of circular
|
||||
/// super trait dependencies, which are possible in malformed code.)
|
||||
/// Returns an iterator over the whole super trait hierarchy (including the
|
||||
/// trait itself).
|
||||
pub fn all_super_traits<'a>(
|
||||
self,
|
||||
db: &'a impl HirDatabase,
|
||||
) -> 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>>)
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
|
||||
|
@ -876,10 +882,7 @@ impl Trait {
|
|||
db: &impl HirDatabase,
|
||||
name: &Name,
|
||||
) -> Option<TypeAlias> {
|
||||
iter::once(self)
|
||||
.chain(self.all_super_traits(db))
|
||||
.unique()
|
||||
.find_map(|t| t.associated_type_by_name(db, name))
|
||||
self.all_super_traits(db).find_map(|t| t.associated_type_by_name(db, name))
|
||||
}
|
||||
|
||||
pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
|
||||
|
|
|
@ -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)
|
||||
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);
|
||||
|
||||
|
|
|
@ -3660,8 +3660,7 @@ fn test<T: foo::Trait>(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<T: Trait1, U: Trait2>(x: T, y: U) {
|
||||
x.foo();
|
||||
|
@ -3684,13 +3683,13 @@ fn test<T: Trait1, U: Trait2>(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}
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
|
|
@ -96,6 +96,21 @@ pub struct TraitEnvironment {
|
|||
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.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct InEnvironment<T> {
|
||||
|
|
Loading…
Reference in a new issue