diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 4e5bdbae462..b54c8031852 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -583,6 +583,19 @@ pub fn shift_bound_vars(self, n: i32) -> Ty { ty => ty, }) } + + /// If this is an `impl Trait` or `dyn Trait`, returns that trait. + pub fn inherent_trait(&self) -> Option { + 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 { diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 3f4c43aee8f..9873a0440bc 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -211,12 +211,19 @@ fn iterate_trait_method_candidates( let krate = resolver.krate()?; // 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); - '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); + + // 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 // trait, but if we find out it doesn't, we'll skip the rest of the // iteration - let mut known_implemented = false; + let mut known_implemented = inherently_implemented; for item in data.items() { if let TraitItem::Function(m) = *item { let data = m.data(db); @@ -271,6 +278,11 @@ pub(crate) fn implements_trait( krate: Crate, trait_: Trait, ) -> 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 goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); let solution = db.trait_solve(krate, goal); diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 93c62b0d402..41cea9564fb 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3279,6 +3279,7 @@ fn impl_trait() { infer(r#" trait Trait { fn foo(&self) -> T; + fn foo2(&self) -> i64; } fn bar() -> impl Trait {} @@ -3289,26 +3290,36 @@ fn test(x: impl Trait, y: &impl Trait) { x.foo(); y.foo(); z.foo(); + x.foo2(); + y.foo2(); + z.foo2(); } "#), @r###" ⋮ ⋮[30; 34) 'self': &Self - ⋮[72; 74) '{}': () - ⋮[84; 85) 'x': impl Trait - ⋮[104; 105) 'y': &impl Trait - ⋮[125; 200) '{ ...o(); }': () - ⋮[131; 132) 'x': impl Trait - ⋮[138; 139) 'y': &impl Trait - ⋮[149; 150) 'z': impl Trait - ⋮[153; 156) 'bar': fn bar() -> impl Trait - ⋮[153; 158) 'bar()': impl Trait - ⋮[164; 165) 'x': impl Trait - ⋮[164; 171) 'x.foo()': {unknown} - ⋮[177; 178) 'y': &impl Trait - ⋮[177; 184) 'y.foo()': {unknown} - ⋮[190; 191) 'z': impl Trait - ⋮[190; 197) 'z.foo()': {unknown} + ⋮[55; 59) 'self': &Self + ⋮[99; 101) '{}': () + ⋮[111; 112) 'x': impl Trait + ⋮[131; 132) 'y': &impl Trait + ⋮[152; 269) '{ ...2(); }': () + ⋮[158; 159) 'x': impl Trait + ⋮[165; 166) 'y': &impl Trait + ⋮[176; 177) 'z': impl Trait + ⋮[180; 183) 'bar': fn bar() -> impl Trait + ⋮[180; 185) 'bar()': impl Trait + ⋮[191; 192) 'x': impl Trait + ⋮[191; 198) 'x.foo()': {unknown} + ⋮[204; 205) 'y': &impl Trait + ⋮[204; 211) 'y.foo()': {unknown} + ⋮[217; 218) 'z': impl Trait + ⋮[217; 224) 'z.foo()': {unknown} + ⋮[230; 231) 'x': impl Trait + ⋮[230; 238) 'x.foo2()': i64 + ⋮[244; 245) 'y': &impl Trait + ⋮[244; 252) 'y.foo2()': i64 + ⋮[258; 259) 'z': impl Trait + ⋮[258; 266) 'z.foo2()': i64 "### ); } @@ -3319,6 +3330,7 @@ fn dyn_trait() { infer(r#" trait Trait { fn foo(&self) -> T; + fn foo2(&self) -> i64; } fn bar() -> dyn Trait {} @@ -3329,26 +3341,36 @@ fn test(x: dyn Trait, y: &dyn Trait) { x.foo(); y.foo(); z.foo(); + x.foo2(); + y.foo2(); + z.foo2(); } "#), @r###" ⋮ ⋮[30; 34) 'self': &Self - ⋮[71; 73) '{}': () - ⋮[83; 84) 'x': dyn Trait - ⋮[102; 103) 'y': &dyn Trait - ⋮[122; 197) '{ ...o(); }': () - ⋮[128; 129) 'x': dyn Trait - ⋮[135; 136) 'y': &dyn Trait - ⋮[146; 147) 'z': dyn Trait - ⋮[150; 153) 'bar': fn bar() -> dyn Trait - ⋮[150; 155) 'bar()': dyn Trait - ⋮[161; 162) 'x': dyn Trait - ⋮[161; 168) 'x.foo()': {unknown} - ⋮[174; 175) 'y': &dyn Trait - ⋮[174; 181) 'y.foo()': {unknown} - ⋮[187; 188) 'z': dyn Trait - ⋮[187; 194) 'z.foo()': {unknown} + ⋮[55; 59) 'self': &Self + ⋮[98; 100) '{}': () + ⋮[110; 111) 'x': dyn Trait + ⋮[129; 130) 'y': &dyn Trait + ⋮[149; 266) '{ ...2(); }': () + ⋮[155; 156) 'x': dyn Trait + ⋮[162; 163) 'y': &dyn Trait + ⋮[173; 174) 'z': dyn Trait + ⋮[177; 180) 'bar': fn bar() -> dyn Trait + ⋮[177; 182) 'bar()': dyn Trait + ⋮[188; 189) 'x': dyn Trait + ⋮[188; 195) 'x.foo()': {unknown} + ⋮[201; 202) 'y': &dyn Trait + ⋮[201; 208) 'y.foo()': {unknown} + ⋮[214; 215) 'z': dyn Trait + ⋮[214; 221) 'z.foo()': {unknown} + ⋮[227; 228) 'x': dyn Trait + ⋮[227; 235) 'x.foo2()': i64 + ⋮[241; 242) 'y': &dyn Trait + ⋮[241; 249) 'y.foo2()': i64 + ⋮[255; 256) 'z': dyn Trait + ⋮[255; 263) 'z.foo2()': i64 "### ); }