mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Handle impl/dyn Trait in method resolution
When we have one of these, the `Trait` doesn't need to be in scope to call its methods. So we need to consider this when looking for method candidates. (Actually I think the same is true when we have a bound `T: some::Trait`, but we don't handle that yet). At the same time, since Chalk doesn't handle these types yet, add a small hack to skip Chalk in method resolution and just consider `impl Trait: Trait` always true. This is enough to e.g. get completions for `impl Trait`, but since we don't do any unification we won't infer the return type of e.g. `impl Into<i64>::into()`.
This commit is contained in:
parent
16a7d8cc85
commit
b1a40042e8
3 changed files with 79 additions and 32 deletions
|
@ -583,6 +583,19 @@ impl Ty {
|
||||||
ty => ty,
|
ty => ty,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this is an `impl Trait` or `dyn Trait`, returns that trait.
|
||||||
|
pub fn inherent_trait(&self) -> Option<Trait> {
|
||||||
|
match self {
|
||||||
|
Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
|
||||||
|
predicates.iter().find_map(|pred| match pred {
|
||||||
|
GenericPredicate::Implemented(tr) => Some(tr.trait_),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HirDisplay for &Ty {
|
impl HirDisplay for &Ty {
|
||||||
|
|
|
@ -211,12 +211,19 @@ fn iterate_trait_method_candidates<T>(
|
||||||
let krate = resolver.krate()?;
|
let krate = resolver.krate()?;
|
||||||
// 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);
|
||||||
'traits: for t in resolver.traits_in_scope(db) {
|
// 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));
|
||||||
|
'traits: for t in traits {
|
||||||
let data = t.trait_data(db);
|
let data = t.trait_data(db);
|
||||||
|
|
||||||
|
// FIXME this is a bit of a hack, since Chalk should say the same thing
|
||||||
|
// anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
|
||||||
|
let inherently_implemented = ty.value.inherent_trait() == Some(t);
|
||||||
|
|
||||||
// we'll be lazy about checking whether the type implements the
|
// we'll be lazy about checking whether the type implements the
|
||||||
// trait, but if we find out it doesn't, we'll skip the rest of the
|
// trait, but if we find out it doesn't, we'll skip the rest of the
|
||||||
// iteration
|
// iteration
|
||||||
let mut known_implemented = false;
|
let mut known_implemented = inherently_implemented;
|
||||||
for item in data.items() {
|
for item in data.items() {
|
||||||
if let TraitItem::Function(m) = *item {
|
if let TraitItem::Function(m) = *item {
|
||||||
let data = m.data(db);
|
let data = m.data(db);
|
||||||
|
@ -271,6 +278,11 @@ pub(crate) fn implements_trait(
|
||||||
krate: Crate,
|
krate: Crate,
|
||||||
trait_: Trait,
|
trait_: Trait,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
if ty.value.inherent_trait() == Some(trait_) {
|
||||||
|
// FIXME this is a bit of a hack, since Chalk should say the same thing
|
||||||
|
// anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet
|
||||||
|
return true;
|
||||||
|
}
|
||||||
let env = lower::trait_env(db, resolver);
|
let env = lower::trait_env(db, resolver);
|
||||||
let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
|
let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone());
|
||||||
let solution = db.trait_solve(krate, goal);
|
let solution = db.trait_solve(krate, goal);
|
||||||
|
|
|
@ -3279,6 +3279,7 @@ fn impl_trait() {
|
||||||
infer(r#"
|
infer(r#"
|
||||||
trait Trait<T> {
|
trait Trait<T> {
|
||||||
fn foo(&self) -> T;
|
fn foo(&self) -> T;
|
||||||
|
fn foo2(&self) -> i64;
|
||||||
}
|
}
|
||||||
fn bar() -> impl Trait<u64> {}
|
fn bar() -> impl Trait<u64> {}
|
||||||
|
|
||||||
|
@ -3289,26 +3290,36 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
|
||||||
x.foo();
|
x.foo();
|
||||||
y.foo();
|
y.foo();
|
||||||
z.foo();
|
z.foo();
|
||||||
|
x.foo2();
|
||||||
|
y.foo2();
|
||||||
|
z.foo2();
|
||||||
}
|
}
|
||||||
"#),
|
"#),
|
||||||
@r###"
|
@r###"
|
||||||
⋮
|
⋮
|
||||||
⋮[30; 34) 'self': &Self
|
⋮[30; 34) 'self': &Self
|
||||||
⋮[72; 74) '{}': ()
|
⋮[55; 59) 'self': &Self
|
||||||
⋮[84; 85) 'x': impl Trait<u64>
|
⋮[99; 101) '{}': ()
|
||||||
⋮[104; 105) 'y': &impl Trait<u64>
|
⋮[111; 112) 'x': impl Trait<u64>
|
||||||
⋮[125; 200) '{ ...o(); }': ()
|
⋮[131; 132) 'y': &impl Trait<u64>
|
||||||
⋮[131; 132) 'x': impl Trait<u64>
|
⋮[152; 269) '{ ...2(); }': ()
|
||||||
⋮[138; 139) 'y': &impl Trait<u64>
|
⋮[158; 159) 'x': impl Trait<u64>
|
||||||
⋮[149; 150) 'z': impl Trait<u64>
|
⋮[165; 166) 'y': &impl Trait<u64>
|
||||||
⋮[153; 156) 'bar': fn bar() -> impl Trait<u64>
|
⋮[176; 177) 'z': impl Trait<u64>
|
||||||
⋮[153; 158) 'bar()': impl Trait<u64>
|
⋮[180; 183) 'bar': fn bar() -> impl Trait<u64>
|
||||||
⋮[164; 165) 'x': impl Trait<u64>
|
⋮[180; 185) 'bar()': impl Trait<u64>
|
||||||
⋮[164; 171) 'x.foo()': {unknown}
|
⋮[191; 192) 'x': impl Trait<u64>
|
||||||
⋮[177; 178) 'y': &impl Trait<u64>
|
⋮[191; 198) 'x.foo()': {unknown}
|
||||||
⋮[177; 184) 'y.foo()': {unknown}
|
⋮[204; 205) 'y': &impl Trait<u64>
|
||||||
⋮[190; 191) 'z': impl Trait<u64>
|
⋮[204; 211) 'y.foo()': {unknown}
|
||||||
⋮[190; 197) 'z.foo()': {unknown}
|
⋮[217; 218) 'z': impl Trait<u64>
|
||||||
|
⋮[217; 224) 'z.foo()': {unknown}
|
||||||
|
⋮[230; 231) 'x': impl Trait<u64>
|
||||||
|
⋮[230; 238) 'x.foo2()': i64
|
||||||
|
⋮[244; 245) 'y': &impl Trait<u64>
|
||||||
|
⋮[244; 252) 'y.foo2()': i64
|
||||||
|
⋮[258; 259) 'z': impl Trait<u64>
|
||||||
|
⋮[258; 266) 'z.foo2()': i64
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3319,6 +3330,7 @@ fn dyn_trait() {
|
||||||
infer(r#"
|
infer(r#"
|
||||||
trait Trait<T> {
|
trait Trait<T> {
|
||||||
fn foo(&self) -> T;
|
fn foo(&self) -> T;
|
||||||
|
fn foo2(&self) -> i64;
|
||||||
}
|
}
|
||||||
fn bar() -> dyn Trait<u64> {}
|
fn bar() -> dyn Trait<u64> {}
|
||||||
|
|
||||||
|
@ -3329,26 +3341,36 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
|
||||||
x.foo();
|
x.foo();
|
||||||
y.foo();
|
y.foo();
|
||||||
z.foo();
|
z.foo();
|
||||||
|
x.foo2();
|
||||||
|
y.foo2();
|
||||||
|
z.foo2();
|
||||||
}
|
}
|
||||||
"#),
|
"#),
|
||||||
@r###"
|
@r###"
|
||||||
⋮
|
⋮
|
||||||
⋮[30; 34) 'self': &Self
|
⋮[30; 34) 'self': &Self
|
||||||
⋮[71; 73) '{}': ()
|
⋮[55; 59) 'self': &Self
|
||||||
⋮[83; 84) 'x': dyn Trait<u64>
|
⋮[98; 100) '{}': ()
|
||||||
⋮[102; 103) 'y': &dyn Trait<u64>
|
⋮[110; 111) 'x': dyn Trait<u64>
|
||||||
⋮[122; 197) '{ ...o(); }': ()
|
⋮[129; 130) 'y': &dyn Trait<u64>
|
||||||
⋮[128; 129) 'x': dyn Trait<u64>
|
⋮[149; 266) '{ ...2(); }': ()
|
||||||
⋮[135; 136) 'y': &dyn Trait<u64>
|
⋮[155; 156) 'x': dyn Trait<u64>
|
||||||
⋮[146; 147) 'z': dyn Trait<u64>
|
⋮[162; 163) 'y': &dyn Trait<u64>
|
||||||
⋮[150; 153) 'bar': fn bar() -> dyn Trait<u64>
|
⋮[173; 174) 'z': dyn Trait<u64>
|
||||||
⋮[150; 155) 'bar()': dyn Trait<u64>
|
⋮[177; 180) 'bar': fn bar() -> dyn Trait<u64>
|
||||||
⋮[161; 162) 'x': dyn Trait<u64>
|
⋮[177; 182) 'bar()': dyn Trait<u64>
|
||||||
⋮[161; 168) 'x.foo()': {unknown}
|
⋮[188; 189) 'x': dyn Trait<u64>
|
||||||
⋮[174; 175) 'y': &dyn Trait<u64>
|
⋮[188; 195) 'x.foo()': {unknown}
|
||||||
⋮[174; 181) 'y.foo()': {unknown}
|
⋮[201; 202) 'y': &dyn Trait<u64>
|
||||||
⋮[187; 188) 'z': dyn Trait<u64>
|
⋮[201; 208) 'y.foo()': {unknown}
|
||||||
⋮[187; 194) 'z.foo()': {unknown}
|
⋮[214; 215) 'z': dyn Trait<u64>
|
||||||
|
⋮[214; 221) 'z.foo()': {unknown}
|
||||||
|
⋮[227; 228) 'x': dyn Trait<u64>
|
||||||
|
⋮[227; 235) 'x.foo2()': i64
|
||||||
|
⋮[241; 242) 'y': &dyn Trait<u64>
|
||||||
|
⋮[241; 249) 'y.foo2()': i64
|
||||||
|
⋮[255; 256) 'z': dyn Trait<u64>
|
||||||
|
⋮[255; 263) 'z.foo2()': i64
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue