aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-02-21 20:49:02 +0000
committerFlorian Diebold <[email protected]>2020-02-22 10:09:21 +0000
commit2d5ab6324795e5fc36e4b61cb66737958dc67e7a (patch)
tree2027747769d99c7733ac4f4366ccffd4fcf4983f /crates
parentf126808b2ee79792631edc377bc8c2b0f329eebf (diff)
Add &dyn Trait -> &dyn SuperTrait coercion, and fix &T -> &dyn Trait
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_ty/src/lib.rs20
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs40
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs95
-rw-r--r--crates/ra_hir_ty/src/utils.rs21
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
464impl<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
464impl<T: TypeWalk> Binders<T> { 470impl<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
588impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {} 588impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
589 589
590trait Foo {} 590trait Foo<T, U> {}
591trait Bar: Foo {} 591trait Bar<U, T, X>: Foo<T, U> {}
592struct S; 592trait Baz<T, X>: Bar<usize, T, X> {}
593impl Foo for S {} 593
594impl Bar for S {} 594struct S<T, X>;
595impl<T, X> Foo<T, usize> for S<T, X> {}
596impl<T, X> Bar<usize, T, X> for S<T, X> {}
597impl<T, X> Baz<T, X> for S<T, X> {}
595 598
596fn test() { 599fn 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};
8use crate::{ 8use 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
14pub(super) struct BuiltinImplData { 14pub(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
291fn super_trait_object_unsize_impl_datum( 300fn 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(&current_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
317fn get_fn_trait( 352fn 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.
67pub(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
65pub(super) fn associated_type_by_name_including_super_traits( 86pub(super) fn associated_type_by_name_including_super_traits(
66 db: &impl DefDatabase, 87 db: &impl DefDatabase,
67 trait_: TraitId, 88 trait_: TraitId,