diff options
author | Florian Diebold <[email protected]> | 2020-02-21 20:49:02 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-02-22 10:09:21 +0000 |
commit | 2d5ab6324795e5fc36e4b61cb66737958dc67e7a (patch) | |
tree | 2027747769d99c7733ac4f4366ccffd4fcf4983f /crates/ra_hir_ty/src | |
parent | f126808b2ee79792631edc377bc8c2b0f329eebf (diff) |
Add &dyn Trait -> &dyn SuperTrait coercion, and fix &T -> &dyn Trait
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/coercion.rs | 40 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 95 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/utils.rs | 21 |
4 files changed, 132 insertions, 44 deletions
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 15356ab37..2f2d3080e 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -461,6 +461,12 @@ impl<T> Binders<T> { | |||
461 | } | 461 | } |
462 | } | 462 | } |
463 | 463 | ||
464 | impl<T: Clone> Binders<&T> { | ||
465 | pub fn cloned(&self) -> Binders<T> { | ||
466 | Binders { num_binders: self.num_binders, value: self.value.clone() } | ||
467 | } | ||
468 | } | ||
469 | |||
464 | impl<T: TypeWalk> Binders<T> { | 470 | impl<T: TypeWalk> Binders<T> { |
465 | /// Substitutes all variables. | 471 | /// Substitutes all variables. |
466 | pub fn subst(self, subst: &Substs) -> T { | 472 | pub fn subst(self, subst: &Substs) -> T { |
@@ -757,6 +763,20 @@ pub trait TypeWalk { | |||
757 | /// variable for the self type. | 763 | /// variable for the self type. |
758 | fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize); | 764 | fn walk_mut_binders(&mut self, f: &mut impl FnMut(&mut Ty, usize), binders: usize); |
759 | 765 | ||
766 | fn fold_binders(mut self, f: &mut impl FnMut(Ty, usize) -> Ty, binders: usize) -> Self | ||
767 | where | ||
768 | Self: Sized, | ||
769 | { | ||
770 | self.walk_mut_binders( | ||
771 | &mut |ty_mut, binders| { | ||
772 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
773 | *ty_mut = f(ty, binders); | ||
774 | }, | ||
775 | binders, | ||
776 | ); | ||
777 | self | ||
778 | } | ||
779 | |||
760 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self | 780 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self |
761 | where | 781 | where |
762 | Self: Sized, | 782 | Self: Sized, |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index b6fce9377..5594ed394 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -587,25 +587,37 @@ pub trait CoerceUnsized<T> {} | |||
587 | 587 | ||
588 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} | 588 | impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} |
589 | 589 | ||
590 | trait Foo {} | 590 | trait Foo<T, U> {} |
591 | trait Bar: Foo {} | 591 | trait Bar<U, T, X>: Foo<T, U> {} |
592 | struct S; | 592 | trait Baz<T, X>: Bar<usize, T, X> {} |
593 | impl Foo for S {} | 593 | |
594 | impl Bar for S {} | 594 | struct S<T, X>; |
595 | impl<T, X> Foo<T, usize> for S<T, X> {} | ||
596 | impl<T, X> Bar<usize, T, X> for S<T, X> {} | ||
597 | impl<T, X> Baz<T, X> for S<T, X> {} | ||
595 | 598 | ||
596 | fn test() { | 599 | fn test() { |
597 | let obj: &dyn Bar = &S; | 600 | let obj: &dyn Baz<i8, i16> = &S; |
598 | let obj: &dyn Foo = obj; | 601 | let obj: &dyn Bar<_, _, _> = obj; |
602 | let obj: &dyn Foo<_, _> = obj; | ||
603 | let obj2: &dyn Baz<i8, i16> = &S; | ||
604 | let _: &dyn Foo<_, _> = obj2; | ||
599 | } | 605 | } |
600 | "#, true), | 606 | "#, true), |
601 | @r###" | 607 | @r###" |
602 | [240; 300) '{ ...obj; }': () | 608 | [388; 573) '{ ...bj2; }': () |
603 | [250; 253) 'obj': &dyn Bar | 609 | [398; 401) 'obj': &dyn Baz<i8, i16> |
604 | [266; 268) '&S': &S | 610 | [423; 425) '&S': &S<i8, i16> |
605 | [267; 268) 'S': S | 611 | [424; 425) 'S': S<i8, i16> |
606 | [278; 281) 'obj': &dyn Foo | 612 | [435; 438) 'obj': &dyn Bar<usize, i8, i16> |
607 | [294; 297) 'obj': &dyn Bar | 613 | [460; 463) 'obj': &dyn Baz<i8, i16> |
608 | [294; 297): expected &dyn Foo, got &dyn Bar | 614 | [473; 476) 'obj': &dyn Foo<i8, usize> |
615 | [495; 498) 'obj': &dyn Bar<usize, i8, i16> | ||
616 | [508; 512) 'obj2': &dyn Baz<i8, i16> | ||
617 | [534; 536) '&S': &S<i8, i16> | ||
618 | [535; 536) 'S': S<i8, i16> | ||
619 | [546; 547) '_': &dyn Foo<i8, usize> | ||
620 | [566; 570) 'obj2': &dyn Baz<i8, i16> | ||
609 | "### | 621 | "### |
610 | ); | 622 | ); |
611 | } | 623 | } |
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index 3c8dd4af8..19e533cee 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -8,7 +8,7 @@ use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData}; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | db::HirDatabase, | 9 | db::HirDatabase, |
10 | utils::{all_super_traits, generics}, | 10 | utils::{all_super_traits, generics}, |
11 | ApplicationTy, GenericPredicate, Substs, TraitRef, Ty, TypeCtor, | 11 | ApplicationTy, Binders, GenericPredicate, Substs, TraitRef, Ty, TypeCtor, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | pub(super) struct BuiltinImplData { | 14 | pub(super) struct BuiltinImplData { |
@@ -72,20 +72,25 @@ fn get_builtin_unsize_impls( | |||
72 | 72 | ||
73 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty { | 73 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty { |
74 | callback(Impl::UnsizeArray); | 74 | callback(Impl::UnsizeArray); |
75 | return; // array is unsized, the rest of the impls shouldn't apply | ||
75 | } | 76 | } |
76 | 77 | ||
77 | if let Some(target_trait) = arg.as_ref().and_then(|t| t.dyn_trait_ref()) { | 78 | if let Some(target_trait) = arg.as_ref().and_then(|t| t.dyn_trait_ref()) { |
79 | // FIXME what about more complicated dyn tys with marker traits? | ||
78 | if let Some(trait_ref) = ty.dyn_trait_ref() { | 80 | if let Some(trait_ref) = ty.dyn_trait_ref() { |
79 | let super_traits = all_super_traits(db, trait_ref.trait_); | 81 | if trait_ref.trait_ != target_trait.trait_ { |
80 | if super_traits.contains(&target_trait.trait_) { | 82 | let super_traits = all_super_traits(db, trait_ref.trait_); |
81 | // callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData { | 83 | if super_traits.contains(&target_trait.trait_) { |
82 | // trait_: trait_ref.trait_, | 84 | callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData { |
83 | // super_trait: target_trait.trait_, | 85 | trait_: trait_ref.trait_, |
84 | // })); | 86 | super_trait: target_trait.trait_, |
87 | })); | ||
88 | } | ||
85 | } | 89 | } |
90 | } else { | ||
91 | // FIXME only for sized types | ||
92 | callback(Impl::UnsizeToTraitObject(target_trait.trait_)); | ||
86 | } | 93 | } |
87 | |||
88 | callback(Impl::UnsizeToTraitObject(target_trait.trait_)); | ||
89 | } | 94 | } |
90 | } | 95 | } |
91 | 96 | ||
@@ -270,48 +275,78 @@ fn trait_object_unsize_impl_datum( | |||
270 | 275 | ||
271 | let self_ty = Ty::Bound(0); | 276 | let self_ty = Ty::Bound(0); |
272 | 277 | ||
273 | let substs = Substs::build_for_def(db, trait_) | 278 | let target_substs = Substs::build_for_def(db, trait_) |
274 | // this fits together nicely: $0 is our self type, and the rest are the type | 279 | .push(Ty::Bound(0)) |
275 | // args for the trait | 280 | // starting from ^2 because we want to start with ^1 outside of the |
276 | .fill_with_bound_vars(0) | 281 | // `dyn`, which is ^2 inside |
282 | .fill_with_bound_vars(2) | ||
277 | .build(); | 283 | .build(); |
278 | let trait_ref = TraitRef { trait_, substs }; | 284 | let num_vars = target_substs.len(); |
279 | // This is both the bound for the `dyn` type, *and* the bound for the impl! | 285 | let target_trait_ref = TraitRef { trait_, substs: target_substs }; |
280 | // This works because the self type for `dyn` is always Ty::Bound(0), which | 286 | let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)]; |
281 | // we've also made the parameter for our impl self type. | ||
282 | let bounds = vec![GenericPredicate::Implemented(trait_ref)]; | ||
283 | 287 | ||
284 | let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(bounds.clone().into())).build(); | 288 | let self_substs = Substs::build_for_def(db, trait_).fill_with_bound_vars(0).build(); |
289 | let self_trait_ref = TraitRef { trait_, substs: self_substs }; | ||
290 | let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; | ||
291 | |||
292 | let impl_substs = | ||
293 | Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build(); | ||
285 | 294 | ||
286 | let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; | 295 | let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; |
287 | 296 | ||
288 | BuiltinImplData { num_vars: 1, trait_ref, where_clauses: bounds, assoc_ty_values: Vec::new() } | 297 | BuiltinImplData { num_vars, trait_ref, where_clauses, assoc_ty_values: Vec::new() } |
289 | } | 298 | } |
290 | 299 | ||
291 | fn super_trait_object_unsize_impl_datum( | 300 | fn super_trait_object_unsize_impl_datum( |
292 | db: &impl HirDatabase, | 301 | db: &impl HirDatabase, |
293 | krate: CrateId, | 302 | krate: CrateId, |
294 | _data: UnsizeToSuperTraitObjectData, | 303 | data: UnsizeToSuperTraitObjectData, |
295 | ) -> BuiltinImplData { | 304 | ) -> BuiltinImplData { |
296 | // impl Unsize<dyn SuperTrait> for dyn Trait | 305 | // impl<T1, ...> Unsize<dyn SuperTrait> for dyn Trait<T1, ...> |
297 | 306 | ||
298 | let unsize_trait = get_unsize_trait(db, krate) // get unsize trait | 307 | let unsize_trait = get_unsize_trait(db, krate) // get unsize trait |
299 | // the existence of the Unsize trait has been checked before | 308 | // the existence of the Unsize trait has been checked before |
300 | .expect("Unsize trait missing"); | 309 | .expect("Unsize trait missing"); |
301 | 310 | ||
311 | let self_substs = Substs::build_for_def(db, data.trait_).fill_with_bound_vars(0).build(); | ||
312 | |||
313 | let num_vars = self_substs.len() - 1; | ||
314 | |||
315 | let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() }; | ||
316 | let self_bounds = vec![GenericPredicate::Implemented(self_trait_ref.clone())]; | ||
317 | |||
318 | // we need to go from our trait to the super trait, substituting type parameters | ||
319 | let mut path = crate::utils::find_super_trait_path(db, data.super_trait, data.trait_); | ||
320 | path.pop(); // the last one is our current trait, we don't need that | ||
321 | path.reverse(); // we want to go from trait to super trait | ||
322 | |||
323 | let mut current_trait_ref = self_trait_ref; | ||
324 | for t in path { | ||
325 | let bounds = db.generic_predicates(current_trait_ref.trait_.into()); | ||
326 | let super_trait_ref = bounds | ||
327 | .iter() | ||
328 | .find_map(|b| match &b.value { | ||
329 | GenericPredicate::Implemented(tr) | ||
330 | if tr.trait_ == t && tr.substs[0] == Ty::Bound(0) => | ||
331 | { | ||
332 | Some(Binders { value: tr, num_binders: b.num_binders }) | ||
333 | } | ||
334 | _ => None, | ||
335 | }) | ||
336 | .expect("trait bound for known super trait not found"); | ||
337 | current_trait_ref = super_trait_ref.cloned().subst(¤t_trait_ref.substs); | ||
338 | } | ||
339 | |||
340 | let super_bounds = vec![GenericPredicate::Implemented(current_trait_ref)]; | ||
341 | |||
302 | let substs = Substs::builder(2) | 342 | let substs = Substs::builder(2) |
303 | // .push(Ty::Dyn(todo!())) | 343 | .push(Ty::Dyn(self_bounds.into())) |
304 | // .push(Ty::Dyn(todo!())) | 344 | .push(Ty::Dyn(super_bounds.into())) |
305 | .build(); | 345 | .build(); |
306 | 346 | ||
307 | let trait_ref = TraitRef { trait_: unsize_trait, substs }; | 347 | let trait_ref = TraitRef { trait_: unsize_trait, substs }; |
308 | 348 | ||
309 | BuiltinImplData { | 349 | BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() } |
310 | num_vars: 1, | ||
311 | trait_ref, | ||
312 | where_clauses: Vec::new(), | ||
313 | assoc_ty_values: Vec::new(), | ||
314 | } | ||
315 | } | 350 | } |
316 | 351 | ||
317 | fn get_fn_trait( | 352 | fn get_fn_trait( |
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index 508ae9046..0d1583c39 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs | |||
@@ -62,6 +62,27 @@ pub(super) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<Tr | |||
62 | result | 62 | result |
63 | } | 63 | } |
64 | 64 | ||
65 | /// Finds a path from a trait to one of its descendant traits. Returns an empty | ||
66 | /// vector if there is no path. | ||
67 | pub(super) fn find_super_trait_path( | ||
68 | db: &impl DefDatabase, | ||
69 | super_trait: TraitId, | ||
70 | trait_: TraitId, | ||
71 | ) -> Vec<TraitId> { | ||
72 | if trait_ == super_trait { | ||
73 | return vec![trait_]; | ||
74 | } | ||
75 | |||
76 | for tt in direct_super_traits(db, trait_) { | ||
77 | let mut path = find_super_trait_path(db, super_trait, tt); | ||
78 | if !path.is_empty() { | ||
79 | path.push(trait_); | ||
80 | return path; | ||
81 | } | ||
82 | } | ||
83 | Vec::new() | ||
84 | } | ||
85 | |||
65 | pub(super) fn associated_type_by_name_including_super_traits( | 86 | pub(super) fn associated_type_by_name_including_super_traits( |
66 | db: &impl DefDatabase, | 87 | db: &impl DefDatabase, |
67 | trait_: TraitId, | 88 | trait_: TraitId, |