diff options
author | Florian Diebold <[email protected]> | 2019-08-22 12:23:50 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-08-22 20:55:11 +0100 |
commit | b1a40042e8f595af0486cf1cc70b63be1ff302b3 (patch) | |
tree | c3f58127c4a330275d2dd635bb5fb11ca7957ddc /crates/ra_hir/src | |
parent | 16a7d8cc850002b427fdc8d21ccde81caaed7902 (diff) |
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()`.
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 82 |
3 files changed, 79 insertions, 32 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 4e5bdbae4..b54c80318 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -583,6 +583,19 @@ impl Ty { | |||
583 | ty => ty, | 583 | ty => ty, |
584 | }) | 584 | }) |
585 | } | 585 | } |
586 | |||
587 | /// If this is an `impl Trait` or `dyn Trait`, returns that trait. | ||
588 | pub fn inherent_trait(&self) -> Option<Trait> { | ||
589 | match self { | ||
590 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
591 | predicates.iter().find_map(|pred| match pred { | ||
592 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | ||
593 | _ => None, | ||
594 | }) | ||
595 | } | ||
596 | _ => None, | ||
597 | } | ||
598 | } | ||
586 | } | 599 | } |
587 | 600 | ||
588 | impl HirDisplay for &Ty { | 601 | 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 3f4c43aee..9873a0440 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<T>( | |||
211 | let krate = resolver.krate()?; | 211 | let krate = resolver.krate()?; |
212 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) | 212 | // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) |
213 | let env = lower::trait_env(db, resolver); | 213 | let env = lower::trait_env(db, resolver); |
214 | 'traits: for t in resolver.traits_in_scope(db) { | 214 | // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope |
215 | let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db)); | ||
216 | 'traits: for t in traits { | ||
215 | let data = t.trait_data(db); | 217 | let data = t.trait_data(db); |
218 | |||
219 | // FIXME this is a bit of a hack, since Chalk should say the same thing | ||
220 | // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet | ||
221 | let inherently_implemented = ty.value.inherent_trait() == Some(t); | ||
222 | |||
216 | // we'll be lazy about checking whether the type implements the | 223 | // we'll be lazy about checking whether the type implements the |
217 | // trait, but if we find out it doesn't, we'll skip the rest of the | 224 | // trait, but if we find out it doesn't, we'll skip the rest of the |
218 | // iteration | 225 | // iteration |
219 | let mut known_implemented = false; | 226 | let mut known_implemented = inherently_implemented; |
220 | for item in data.items() { | 227 | for item in data.items() { |
221 | if let TraitItem::Function(m) = *item { | 228 | if let TraitItem::Function(m) = *item { |
222 | let data = m.data(db); | 229 | let data = m.data(db); |
@@ -271,6 +278,11 @@ pub(crate) fn implements_trait( | |||
271 | krate: Crate, | 278 | krate: Crate, |
272 | trait_: Trait, | 279 | trait_: Trait, |
273 | ) -> bool { | 280 | ) -> bool { |
281 | if ty.value.inherent_trait() == Some(trait_) { | ||
282 | // FIXME this is a bit of a hack, since Chalk should say the same thing | ||
283 | // anyway, but currently Chalk doesn't implement `dyn/impl Trait` yet | ||
284 | return true; | ||
285 | } | ||
274 | let env = lower::trait_env(db, resolver); | 286 | let env = lower::trait_env(db, resolver); |
275 | let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); | 287 | let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); |
276 | let solution = db.trait_solve(krate, goal); | 288 | 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 93c62b0d4..41cea9564 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3279,6 +3279,7 @@ fn impl_trait() { | |||
3279 | infer(r#" | 3279 | infer(r#" |
3280 | trait Trait<T> { | 3280 | trait Trait<T> { |
3281 | fn foo(&self) -> T; | 3281 | fn foo(&self) -> T; |
3282 | fn foo2(&self) -> i64; | ||
3282 | } | 3283 | } |
3283 | fn bar() -> impl Trait<u64> {} | 3284 | fn bar() -> impl Trait<u64> {} |
3284 | 3285 | ||
@@ -3289,26 +3290,36 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u64>) { | |||
3289 | x.foo(); | 3290 | x.foo(); |
3290 | y.foo(); | 3291 | y.foo(); |
3291 | z.foo(); | 3292 | z.foo(); |
3293 | x.foo2(); | ||
3294 | y.foo2(); | ||
3295 | z.foo2(); | ||
3292 | } | 3296 | } |
3293 | "#), | 3297 | "#), |
3294 | @r###" | 3298 | @r###" |
3295 | ⋮ | 3299 | ⋮ |
3296 | ⋮[30; 34) 'self': &Self | 3300 | ⋮[30; 34) 'self': &Self |
3297 | ⋮[72; 74) '{}': () | 3301 | ⋮[55; 59) 'self': &Self |
3298 | ⋮[84; 85) 'x': impl Trait<u64> | 3302 | ⋮[99; 101) '{}': () |
3299 | ⋮[104; 105) 'y': &impl Trait<u64> | 3303 | ⋮[111; 112) 'x': impl Trait<u64> |
3300 | ⋮[125; 200) '{ ...o(); }': () | 3304 | ⋮[131; 132) 'y': &impl Trait<u64> |
3301 | ⋮[131; 132) 'x': impl Trait<u64> | 3305 | ⋮[152; 269) '{ ...2(); }': () |
3302 | ⋮[138; 139) 'y': &impl Trait<u64> | 3306 | ⋮[158; 159) 'x': impl Trait<u64> |
3303 | ⋮[149; 150) 'z': impl Trait<u64> | 3307 | ⋮[165; 166) 'y': &impl Trait<u64> |
3304 | ⋮[153; 156) 'bar': fn bar() -> impl Trait<u64> | 3308 | ⋮[176; 177) 'z': impl Trait<u64> |
3305 | ⋮[153; 158) 'bar()': impl Trait<u64> | 3309 | ⋮[180; 183) 'bar': fn bar() -> impl Trait<u64> |
3306 | ⋮[164; 165) 'x': impl Trait<u64> | 3310 | ⋮[180; 185) 'bar()': impl Trait<u64> |
3307 | ⋮[164; 171) 'x.foo()': {unknown} | 3311 | ⋮[191; 192) 'x': impl Trait<u64> |
3308 | ⋮[177; 178) 'y': &impl Trait<u64> | 3312 | ⋮[191; 198) 'x.foo()': {unknown} |
3309 | ⋮[177; 184) 'y.foo()': {unknown} | 3313 | ⋮[204; 205) 'y': &impl Trait<u64> |
3310 | ⋮[190; 191) 'z': impl Trait<u64> | 3314 | ⋮[204; 211) 'y.foo()': {unknown} |
3311 | ⋮[190; 197) 'z.foo()': {unknown} | 3315 | ⋮[217; 218) 'z': impl Trait<u64> |
3316 | ⋮[217; 224) 'z.foo()': {unknown} | ||
3317 | ⋮[230; 231) 'x': impl Trait<u64> | ||
3318 | ⋮[230; 238) 'x.foo2()': i64 | ||
3319 | ⋮[244; 245) 'y': &impl Trait<u64> | ||
3320 | ⋮[244; 252) 'y.foo2()': i64 | ||
3321 | ⋮[258; 259) 'z': impl Trait<u64> | ||
3322 | ⋮[258; 266) 'z.foo2()': i64 | ||
3312 | "### | 3323 | "### |
3313 | ); | 3324 | ); |
3314 | } | 3325 | } |
@@ -3319,6 +3330,7 @@ fn dyn_trait() { | |||
3319 | infer(r#" | 3330 | infer(r#" |
3320 | trait Trait<T> { | 3331 | trait Trait<T> { |
3321 | fn foo(&self) -> T; | 3332 | fn foo(&self) -> T; |
3333 | fn foo2(&self) -> i64; | ||
3322 | } | 3334 | } |
3323 | fn bar() -> dyn Trait<u64> {} | 3335 | fn bar() -> dyn Trait<u64> {} |
3324 | 3336 | ||
@@ -3329,26 +3341,36 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) { | |||
3329 | x.foo(); | 3341 | x.foo(); |
3330 | y.foo(); | 3342 | y.foo(); |
3331 | z.foo(); | 3343 | z.foo(); |
3344 | x.foo2(); | ||
3345 | y.foo2(); | ||
3346 | z.foo2(); | ||
3332 | } | 3347 | } |
3333 | "#), | 3348 | "#), |
3334 | @r###" | 3349 | @r###" |
3335 | ⋮ | 3350 | ⋮ |
3336 | ⋮[30; 34) 'self': &Self | 3351 | ⋮[30; 34) 'self': &Self |
3337 | ⋮[71; 73) '{}': () | 3352 | ⋮[55; 59) 'self': &Self |
3338 | ⋮[83; 84) 'x': dyn Trait<u64> | 3353 | ⋮[98; 100) '{}': () |
3339 | ⋮[102; 103) 'y': &dyn Trait<u64> | 3354 | ⋮[110; 111) 'x': dyn Trait<u64> |
3340 | ⋮[122; 197) '{ ...o(); }': () | 3355 | ⋮[129; 130) 'y': &dyn Trait<u64> |
3341 | ⋮[128; 129) 'x': dyn Trait<u64> | 3356 | ⋮[149; 266) '{ ...2(); }': () |
3342 | ⋮[135; 136) 'y': &dyn Trait<u64> | 3357 | ⋮[155; 156) 'x': dyn Trait<u64> |
3343 | ⋮[146; 147) 'z': dyn Trait<u64> | 3358 | ⋮[162; 163) 'y': &dyn Trait<u64> |
3344 | ⋮[150; 153) 'bar': fn bar() -> dyn Trait<u64> | 3359 | ⋮[173; 174) 'z': dyn Trait<u64> |
3345 | ⋮[150; 155) 'bar()': dyn Trait<u64> | 3360 | ⋮[177; 180) 'bar': fn bar() -> dyn Trait<u64> |
3346 | ⋮[161; 162) 'x': dyn Trait<u64> | 3361 | ⋮[177; 182) 'bar()': dyn Trait<u64> |
3347 | ⋮[161; 168) 'x.foo()': {unknown} | 3362 | ⋮[188; 189) 'x': dyn Trait<u64> |
3348 | ⋮[174; 175) 'y': &dyn Trait<u64> | 3363 | ⋮[188; 195) 'x.foo()': {unknown} |
3349 | ⋮[174; 181) 'y.foo()': {unknown} | 3364 | ⋮[201; 202) 'y': &dyn Trait<u64> |
3350 | ⋮[187; 188) 'z': dyn Trait<u64> | 3365 | ⋮[201; 208) 'y.foo()': {unknown} |
3351 | ⋮[187; 194) 'z.foo()': {unknown} | 3366 | ⋮[214; 215) 'z': dyn Trait<u64> |
3367 | ⋮[214; 221) 'z.foo()': {unknown} | ||
3368 | ⋮[227; 228) 'x': dyn Trait<u64> | ||
3369 | ⋮[227; 235) 'x.foo2()': i64 | ||
3370 | ⋮[241; 242) 'y': &dyn Trait<u64> | ||
3371 | ⋮[241; 249) 'y.foo2()': i64 | ||
3372 | ⋮[255; 256) 'z': dyn Trait<u64> | ||
3373 | ⋮[255; 263) 'z.foo2()': i64 | ||
3352 | "### | 3374 | "### |
3353 | ); | 3375 | ); |
3354 | } | 3376 | } |