diff options
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 65 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 175 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 4 |
4 files changed, 246 insertions, 14 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index debedcbb8..47d161277 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -17,7 +17,7 @@ use crate::{ | |||
17 | path::{GenericArg, PathSegment}, | 17 | path::{GenericArg, PathSegment}, |
18 | resolve::{Resolution, Resolver}, | 18 | resolve::{Resolution, Resolver}, |
19 | ty::AdtDef, | 19 | ty::AdtDef, |
20 | type_ref::TypeRef, | 20 | type_ref::{TypeBound, TypeRef}, |
21 | BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct, | 21 | BuiltinType, Const, Enum, EnumVariant, Function, HirDatabase, ModuleDef, Path, Static, Struct, |
22 | StructField, Trait, TypeAlias, Union, | 22 | StructField, Trait, TypeAlias, Union, |
23 | }; | 23 | }; |
@@ -58,6 +58,22 @@ impl Ty { | |||
58 | let sig = Substs(inner_tys.into()); | 58 | let sig = Substs(inner_tys.into()); |
59 | Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) | 59 | Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) |
60 | } | 60 | } |
61 | TypeRef::DynTrait(bounds) => { | ||
62 | let self_ty = Ty::Bound(0); | ||
63 | let predicates = bounds | ||
64 | .iter() | ||
65 | .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) | ||
66 | .collect::<Vec<_>>(); | ||
67 | Ty::Dyn(predicates.into()) | ||
68 | } | ||
69 | TypeRef::ImplTrait(bounds) => { | ||
70 | let self_ty = Ty::Bound(0); | ||
71 | let predicates = bounds | ||
72 | .iter() | ||
73 | .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) | ||
74 | .collect::<Vec<_>>(); | ||
75 | Ty::Opaque(predicates.into()) | ||
76 | } | ||
61 | TypeRef::Error => Ty::Unknown, | 77 | TypeRef::Error => Ty::Unknown, |
62 | } | 78 | } |
63 | } | 79 | } |
@@ -310,13 +326,46 @@ impl TraitRef { | |||
310 | TraitRef { trait_, substs } | 326 | TraitRef { trait_, substs } |
311 | } | 327 | } |
312 | 328 | ||
313 | pub(crate) fn for_where_predicate( | 329 | pub(crate) fn from_where_predicate( |
314 | db: &impl HirDatabase, | 330 | db: &impl HirDatabase, |
315 | resolver: &Resolver, | 331 | resolver: &Resolver, |
316 | pred: &WherePredicate, | 332 | pred: &WherePredicate, |
317 | ) -> Option<TraitRef> { | 333 | ) -> Option<TraitRef> { |
318 | let self_ty = Ty::from_hir(db, resolver, &pred.type_ref); | 334 | let self_ty = Ty::from_hir(db, resolver, &pred.type_ref); |
319 | TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty)) | 335 | TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty) |
336 | } | ||
337 | |||
338 | pub(crate) fn from_type_bound( | ||
339 | db: &impl HirDatabase, | ||
340 | resolver: &Resolver, | ||
341 | bound: &TypeBound, | ||
342 | self_ty: Ty, | ||
343 | ) -> Option<TraitRef> { | ||
344 | match bound { | ||
345 | TypeBound::Path(path) => TraitRef::from_path(db, resolver, path, Some(self_ty)), | ||
346 | TypeBound::Error => None, | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | impl GenericPredicate { | ||
352 | pub(crate) fn from_where_predicate( | ||
353 | db: &impl HirDatabase, | ||
354 | resolver: &Resolver, | ||
355 | where_predicate: &WherePredicate, | ||
356 | ) -> GenericPredicate { | ||
357 | TraitRef::from_where_predicate(db, &resolver, where_predicate) | ||
358 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | ||
359 | } | ||
360 | |||
361 | pub(crate) fn from_type_bound( | ||
362 | db: &impl HirDatabase, | ||
363 | resolver: &Resolver, | ||
364 | bound: &TypeBound, | ||
365 | self_ty: Ty, | ||
366 | ) -> GenericPredicate { | ||
367 | TraitRef::from_type_bound(db, &resolver, bound, self_ty) | ||
368 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | ||
320 | } | 369 | } |
321 | } | 370 | } |
322 | 371 | ||
@@ -376,10 +425,7 @@ pub(crate) fn trait_env( | |||
376 | ) -> Arc<super::TraitEnvironment> { | 425 | ) -> Arc<super::TraitEnvironment> { |
377 | let predicates = resolver | 426 | let predicates = resolver |
378 | .where_predicates_in_scope() | 427 | .where_predicates_in_scope() |
379 | .map(|pred| { | 428 | .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
380 | TraitRef::for_where_predicate(db, &resolver, pred) | ||
381 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | ||
382 | }) | ||
383 | .collect::<Vec<_>>(); | 429 | .collect::<Vec<_>>(); |
384 | 430 | ||
385 | Arc::new(super::TraitEnvironment { predicates }) | 431 | Arc::new(super::TraitEnvironment { predicates }) |
@@ -393,10 +439,7 @@ pub(crate) fn generic_predicates_query( | |||
393 | let resolver = def.resolver(db); | 439 | let resolver = def.resolver(db); |
394 | let predicates = resolver | 440 | let predicates = resolver |
395 | .where_predicates_in_scope() | 441 | .where_predicates_in_scope() |
396 | .map(|pred| { | 442 | .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
397 | TraitRef::for_where_predicate(db, &resolver, pred) | ||
398 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | ||
399 | }) | ||
400 | .collect::<Vec<_>>(); | 443 | .collect::<Vec<_>>(); |
401 | predicates.into() | 444 | predicates.into() |
402 | } | 445 | } |
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 57fd5492d..c5818b738 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3273,6 +3273,181 @@ fn test<T: ApplyL>(t: T) { | |||
3273 | assert_eq!(t, "{unknown}"); | 3273 | assert_eq!(t, "{unknown}"); |
3274 | } | 3274 | } |
3275 | 3275 | ||
3276 | #[test] | ||
3277 | fn impl_trait() { | ||
3278 | assert_snapshot_matches!( | ||
3279 | infer(r#" | ||
3280 | trait Trait<T> { | ||
3281 | fn foo(&self) -> T; | ||
3282 | fn foo2(&self) -> i64; | ||
3283 | } | ||
3284 | fn bar() -> impl Trait<u64> {} | ||
3285 | |||
3286 | fn test(x: impl Trait<u64>, y: &impl Trait<u64>) { | ||
3287 | x; | ||
3288 | y; | ||
3289 | let z = bar(); | ||
3290 | x.foo(); | ||
3291 | y.foo(); | ||
3292 | z.foo(); | ||
3293 | x.foo2(); | ||
3294 | y.foo2(); | ||
3295 | z.foo2(); | ||
3296 | } | ||
3297 | "#), | ||
3298 | @r###" | ||
3299 | ⋮ | ||
3300 | ⋮[30; 34) 'self': &Self | ||
3301 | ⋮[55; 59) 'self': &Self | ||
3302 | ⋮[99; 101) '{}': () | ||
3303 | ⋮[111; 112) 'x': impl Trait<u64> | ||
3304 | ⋮[131; 132) 'y': &impl Trait<u64> | ||
3305 | ⋮[152; 269) '{ ...2(); }': () | ||
3306 | ⋮[158; 159) 'x': impl Trait<u64> | ||
3307 | ⋮[165; 166) 'y': &impl Trait<u64> | ||
3308 | ⋮[176; 177) 'z': impl Trait<u64> | ||
3309 | ⋮[180; 183) 'bar': fn bar() -> impl Trait<u64> | ||
3310 | ⋮[180; 185) 'bar()': impl Trait<u64> | ||
3311 | ⋮[191; 192) 'x': impl Trait<u64> | ||
3312 | ⋮[191; 198) 'x.foo()': {unknown} | ||
3313 | ⋮[204; 205) 'y': &impl Trait<u64> | ||
3314 | ⋮[204; 211) 'y.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 | ||
3323 | "### | ||
3324 | ); | ||
3325 | } | ||
3326 | |||
3327 | #[test] | ||
3328 | fn dyn_trait() { | ||
3329 | assert_snapshot_matches!( | ||
3330 | infer(r#" | ||
3331 | trait Trait<T> { | ||
3332 | fn foo(&self) -> T; | ||
3333 | fn foo2(&self) -> i64; | ||
3334 | } | ||
3335 | fn bar() -> dyn Trait<u64> {} | ||
3336 | |||
3337 | fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) { | ||
3338 | x; | ||
3339 | y; | ||
3340 | let z = bar(); | ||
3341 | x.foo(); | ||
3342 | y.foo(); | ||
3343 | z.foo(); | ||
3344 | x.foo2(); | ||
3345 | y.foo2(); | ||
3346 | z.foo2(); | ||
3347 | } | ||
3348 | "#), | ||
3349 | @r###" | ||
3350 | ⋮ | ||
3351 | ⋮[30; 34) 'self': &Self | ||
3352 | ⋮[55; 59) 'self': &Self | ||
3353 | ⋮[98; 100) '{}': () | ||
3354 | ⋮[110; 111) 'x': dyn Trait<u64> | ||
3355 | ⋮[129; 130) 'y': &dyn Trait<u64> | ||
3356 | ⋮[149; 266) '{ ...2(); }': () | ||
3357 | ⋮[155; 156) 'x': dyn Trait<u64> | ||
3358 | ⋮[162; 163) 'y': &dyn Trait<u64> | ||
3359 | ⋮[173; 174) 'z': dyn Trait<u64> | ||
3360 | ⋮[177; 180) 'bar': fn bar() -> dyn Trait<u64> | ||
3361 | ⋮[177; 182) 'bar()': dyn Trait<u64> | ||
3362 | ⋮[188; 189) 'x': dyn Trait<u64> | ||
3363 | ⋮[188; 195) 'x.foo()': {unknown} | ||
3364 | ⋮[201; 202) 'y': &dyn Trait<u64> | ||
3365 | ⋮[201; 208) 'y.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 | ||
3374 | "### | ||
3375 | ); | ||
3376 | } | ||
3377 | |||
3378 | #[test] | ||
3379 | fn dyn_trait_bare() { | ||
3380 | assert_snapshot_matches!( | ||
3381 | infer(r#" | ||
3382 | trait Trait { | ||
3383 | fn foo(&self) -> u64; | ||
3384 | } | ||
3385 | fn bar() -> Trait {} | ||
3386 | |||
3387 | fn test(x: Trait, y: &Trait) -> u64 { | ||
3388 | x; | ||
3389 | y; | ||
3390 | let z = bar(); | ||
3391 | x.foo(); | ||
3392 | y.foo(); | ||
3393 | z.foo(); | ||
3394 | } | ||
3395 | "#), | ||
3396 | @r###" | ||
3397 | ⋮ | ||
3398 | ⋮[27; 31) 'self': &Self | ||
3399 | ⋮[61; 63) '{}': () | ||
3400 | ⋮[73; 74) 'x': {unknown} | ||
3401 | ⋮[83; 84) 'y': &{unknown} | ||
3402 | ⋮[101; 176) '{ ...o(); }': () | ||
3403 | ⋮[107; 108) 'x': {unknown} | ||
3404 | ⋮[114; 115) 'y': &{unknown} | ||
3405 | ⋮[125; 126) 'z': {unknown} | ||
3406 | ⋮[129; 132) 'bar': fn bar() -> {unknown} | ||
3407 | ⋮[129; 134) 'bar()': {unknown} | ||
3408 | ⋮[140; 141) 'x': {unknown} | ||
3409 | ⋮[140; 147) 'x.foo()': {unknown} | ||
3410 | ⋮[153; 154) 'y': &{unknown} | ||
3411 | ⋮[153; 160) 'y.foo()': {unknown} | ||
3412 | ⋮[166; 167) 'z': {unknown} | ||
3413 | ⋮[166; 173) 'z.foo()': {unknown} | ||
3414 | "### | ||
3415 | ); | ||
3416 | } | ||
3417 | |||
3418 | #[test] | ||
3419 | fn weird_bounds() { | ||
3420 | assert_snapshot_matches!( | ||
3421 | infer(r#" | ||
3422 | trait Trait {} | ||
3423 | fn test() { | ||
3424 | let a: impl Trait + 'lifetime = foo; | ||
3425 | let b: impl 'lifetime = foo; | ||
3426 | let b: impl (Trait) = foo; | ||
3427 | let b: impl ('lifetime) = foo; | ||
3428 | let d: impl ?Sized = foo; | ||
3429 | let e: impl Trait + ?Sized = foo; | ||
3430 | } | ||
3431 | "#), | ||
3432 | @r###" | ||
3433 | ⋮ | ||
3434 | ⋮[26; 237) '{ ...foo; }': () | ||
3435 | ⋮[36; 37) 'a': impl Trait + {error} | ||
3436 | ⋮[64; 67) 'foo': impl Trait + {error} | ||
3437 | ⋮[77; 78) 'b': impl {error} | ||
3438 | ⋮[97; 100) 'foo': impl {error} | ||
3439 | ⋮[110; 111) 'b': impl Trait | ||
3440 | ⋮[128; 131) 'foo': impl Trait | ||
3441 | ⋮[141; 142) 'b': impl {error} | ||
3442 | ⋮[163; 166) 'foo': impl {error} | ||
3443 | ⋮[176; 177) 'd': impl {error} | ||
3444 | ⋮[193; 196) 'foo': impl {error} | ||
3445 | ⋮[206; 207) 'e': impl Trait + {error} | ||
3446 | ⋮[231; 234) 'foo': impl Trait + {error} | ||
3447 | "### | ||
3448 | ); | ||
3449 | } | ||
3450 | |||
3276 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3451 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3277 | let file = db.parse(pos.file_id).ok().unwrap(); | 3452 | let file = db.parse(pos.file_id).ok().unwrap(); |
3278 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 3453 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 6df7094c5..2ebc06135 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -80,7 +80,9 @@ impl ToChalk for Ty { | |||
80 | // FIXME this is clearly incorrect, but probably not too incorrect | 80 | // FIXME this is clearly incorrect, but probably not too incorrect |
81 | // and I'm not sure what to actually do with Ty::Unknown | 81 | // and I'm not sure what to actually do with Ty::Unknown |
82 | // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty) | 82 | // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty) |
83 | Ty::Unknown => { | 83 | // |
84 | // FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet | ||
85 | Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { | ||
84 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() | 86 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() |
85 | } | 87 | } |
86 | } | 88 | } |