diff options
author | Florian Diebold <[email protected]> | 2020-02-21 18:05:27 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-02-22 10:09:21 +0000 |
commit | 0dfbbaf03b03618dcb7ba203ddc453533bb8d1b4 (patch) | |
tree | ef862c881d191030007f6b6ef40ce2250d45c916 | |
parent | de39d221a15c0a146ed8adbdb1616692180948bb (diff) |
Implement dyn Trait unsizing as well
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/coercion.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 112 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 4 |
5 files changed, 136 insertions, 9 deletions
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 13c5e6c6b..15356ab37 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -661,6 +661,17 @@ impl Ty { | |||
661 | } | 661 | } |
662 | } | 662 | } |
663 | 663 | ||
664 | /// If this is a `dyn Trait` type, this returns the `Trait` part. | ||
665 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { | ||
666 | match self { | ||
667 | Ty::Dyn(bounds) => bounds.get(0).and_then(|b| match b { | ||
668 | GenericPredicate::Implemented(trait_ref) => Some(trait_ref), | ||
669 | _ => None, | ||
670 | }), | ||
671 | _ => None, | ||
672 | } | ||
673 | } | ||
674 | |||
664 | fn builtin_deref(&self) -> Option<Ty> { | 675 | fn builtin_deref(&self) -> Option<Ty> { |
665 | match self { | 676 | match self { |
666 | Ty::Apply(a_ty) => match a_ty.ctor { | 677 | Ty::Apply(a_ty) => match a_ty.ctor { |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index aa2dfb5f0..b6fce9377 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -576,7 +576,6 @@ fn test() { | |||
576 | ); | 576 | ); |
577 | } | 577 | } |
578 | 578 | ||
579 | #[ignore] | ||
580 | #[test] | 579 | #[test] |
581 | fn coerce_unsize_trait_object() { | 580 | fn coerce_unsize_trait_object() { |
582 | assert_snapshot!( | 581 | assert_snapshot!( |
@@ -600,6 +599,13 @@ fn test() { | |||
600 | } | 599 | } |
601 | "#, true), | 600 | "#, true), |
602 | @r###" | 601 | @r###" |
602 | [240; 300) '{ ...obj; }': () | ||
603 | [250; 253) 'obj': &dyn Bar | ||
604 | [266; 268) '&S': &S | ||
605 | [267; 268) 'S': S | ||
606 | [278; 281) 'obj': &dyn Foo | ||
607 | [294; 297) 'obj': &dyn Bar | ||
608 | [294; 297): expected &dyn Foo, got &dyn Bar | ||
603 | "### | 609 | "### |
604 | ); | 610 | ); |
605 | } | 611 | } |
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index c385f0098..2317fcac3 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -335,6 +335,12 @@ pub struct ClosureFnTraitImplData { | |||
335 | fn_trait: FnTrait, | 335 | fn_trait: FnTrait, |
336 | } | 336 | } |
337 | 337 | ||
338 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
339 | pub struct UnsizeToSuperTraitObjectData { | ||
340 | trait_: TraitId, | ||
341 | super_trait: TraitId, | ||
342 | } | ||
343 | |||
338 | /// An impl. Usually this comes from an impl block, but some built-in types get | 344 | /// An impl. Usually this comes from an impl block, but some built-in types get |
339 | /// synthetic impls. | 345 | /// synthetic impls. |
340 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 346 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -345,6 +351,10 @@ pub enum Impl { | |||
345 | ClosureFnTraitImpl(ClosureFnTraitImplData), | 351 | ClosureFnTraitImpl(ClosureFnTraitImplData), |
346 | /// [T; n]: Unsize<[T]> | 352 | /// [T; n]: Unsize<[T]> |
347 | UnsizeArray, | 353 | UnsizeArray, |
354 | /// T: Unsize<dyn Trait> where T: Trait | ||
355 | UnsizeToTraitObject(TraitId), | ||
356 | /// dyn Trait: Unsize<dyn SuperTrait> if Trait: SuperTrait | ||
357 | UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData), | ||
348 | } | 358 | } |
349 | /// This exists just for Chalk, because our ImplIds are only unique per module. | 359 | /// This exists just for Chalk, because our ImplIds are only unique per module. |
350 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 360 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index 394232fd9..3c8dd4af8 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -4,8 +4,12 @@ use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; | |||
4 | use hir_expand::name::name; | 4 | use hir_expand::name::name; |
5 | use ra_db::CrateId; | 5 | use ra_db::CrateId; |
6 | 6 | ||
7 | use super::{AssocTyValue, Impl}; | 7 | use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData}; |
8 | use crate::{db::HirDatabase, utils::generics, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; | 8 | use crate::{ |
9 | db::HirDatabase, | ||
10 | utils::{all_super_traits, generics}, | ||
11 | ApplicationTy, GenericPredicate, Substs, TraitRef, Ty, TypeCtor, | ||
12 | }; | ||
9 | 13 | ||
10 | pub(super) struct BuiltinImplData { | 14 | pub(super) struct BuiltinImplData { |
11 | pub num_vars: usize, | 15 | pub num_vars: usize, |
@@ -25,6 +29,8 @@ pub(super) fn get_builtin_impls( | |||
25 | db: &impl HirDatabase, | 29 | db: &impl HirDatabase, |
26 | krate: CrateId, | 30 | krate: CrateId, |
27 | ty: &Ty, | 31 | ty: &Ty, |
32 | // The first argument for the trait, if present | ||
33 | arg: &Option<Ty>, | ||
28 | trait_: TraitId, | 34 | trait_: TraitId, |
29 | mut callback: impl FnMut(Impl), | 35 | mut callback: impl FnMut(Impl), |
30 | ) { | 36 | ) { |
@@ -43,14 +49,43 @@ pub(super) fn get_builtin_impls( | |||
43 | } | 49 | } |
44 | } | 50 | } |
45 | } | 51 | } |
52 | |||
53 | let unsize_trait = get_unsize_trait(db, krate); | ||
54 | if let Some(actual_trait) = unsize_trait { | ||
55 | if trait_ == actual_trait { | ||
56 | get_builtin_unsize_impls(db, krate, ty, arg, callback); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | fn get_builtin_unsize_impls( | ||
62 | db: &impl HirDatabase, | ||
63 | krate: CrateId, | ||
64 | ty: &Ty, | ||
65 | // The first argument for the trait, if present | ||
66 | arg: &Option<Ty>, | ||
67 | mut callback: impl FnMut(Impl), | ||
68 | ) { | ||
69 | if !check_unsize_impl_prerequisites(db, krate) { | ||
70 | return; | ||
71 | } | ||
72 | |||
46 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty { | 73 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty { |
47 | if let Some(actual_trait) = get_unsize_trait(db, krate) { | 74 | callback(Impl::UnsizeArray); |
48 | if trait_ == actual_trait { | 75 | } |
49 | if check_unsize_impl_prerequisites(db, krate) { | 76 | |
50 | callback(Impl::UnsizeArray); | 77 | if let Some(target_trait) = arg.as_ref().and_then(|t| t.dyn_trait_ref()) { |
51 | } | 78 | if let Some(trait_ref) = ty.dyn_trait_ref() { |
79 | let super_traits = all_super_traits(db, trait_ref.trait_); | ||
80 | if super_traits.contains(&target_trait.trait_) { | ||
81 | // callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData { | ||
82 | // trait_: trait_ref.trait_, | ||
83 | // super_trait: target_trait.trait_, | ||
84 | // })); | ||
52 | } | 85 | } |
53 | } | 86 | } |
87 | |||
88 | callback(Impl::UnsizeToTraitObject(target_trait.trait_)); | ||
54 | } | 89 | } |
55 | } | 90 | } |
56 | 91 | ||
@@ -59,6 +94,10 @@ pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> | |||
59 | Impl::ImplBlock(_) => unreachable!(), | 94 | Impl::ImplBlock(_) => unreachable!(), |
60 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), | 95 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), |
61 | Impl::UnsizeArray => array_unsize_impl_datum(db, krate), | 96 | Impl::UnsizeArray => array_unsize_impl_datum(db, krate), |
97 | Impl::UnsizeToTraitObject(trait_) => trait_object_unsize_impl_datum(db, krate, trait_), | ||
98 | Impl::UnsizeToSuperTraitObject(data) => { | ||
99 | super_trait_object_unsize_impl_datum(db, krate, data) | ||
100 | } | ||
62 | } | 101 | } |
63 | } | 102 | } |
64 | 103 | ||
@@ -216,6 +255,65 @@ fn array_unsize_impl_datum(db: &impl HirDatabase, krate: CrateId) -> BuiltinImpl | |||
216 | } | 255 | } |
217 | } | 256 | } |
218 | 257 | ||
258 | // Trait object unsizing | ||
259 | |||
260 | fn trait_object_unsize_impl_datum( | ||
261 | db: &impl HirDatabase, | ||
262 | krate: CrateId, | ||
263 | trait_: TraitId, | ||
264 | ) -> BuiltinImplData { | ||
265 | // impl<T, T1, ...> Unsize<dyn Trait<T1, ...>> for T where T: Trait<T1, ...> | ||
266 | |||
267 | let unsize_trait = get_unsize_trait(db, krate) // get unsize trait | ||
268 | // the existence of the Unsize trait has been checked before | ||
269 | .expect("Unsize trait missing"); | ||
270 | |||
271 | let self_ty = Ty::Bound(0); | ||
272 | |||
273 | let substs = Substs::build_for_def(db, trait_) | ||
274 | // this fits together nicely: $0 is our self type, and the rest are the type | ||
275 | // args for the trait | ||
276 | .fill_with_bound_vars(0) | ||
277 | .build(); | ||
278 | let trait_ref = TraitRef { trait_, substs }; | ||
279 | // This is both the bound for the `dyn` type, *and* the bound for the impl! | ||
280 | // This works because the self type for `dyn` is always Ty::Bound(0), which | ||
281 | // we've also made the parameter for our impl self type. | ||
282 | let bounds = vec![GenericPredicate::Implemented(trait_ref)]; | ||
283 | |||
284 | let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(bounds.clone().into())).build(); | ||
285 | |||
286 | let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; | ||
287 | |||
288 | BuiltinImplData { num_vars: 1, trait_ref, where_clauses: bounds, assoc_ty_values: Vec::new() } | ||
289 | } | ||
290 | |||
291 | fn super_trait_object_unsize_impl_datum( | ||
292 | db: &impl HirDatabase, | ||
293 | krate: CrateId, | ||
294 | _data: UnsizeToSuperTraitObjectData, | ||
295 | ) -> BuiltinImplData { | ||
296 | // impl Unsize<dyn SuperTrait> for dyn Trait | ||
297 | |||
298 | let unsize_trait = get_unsize_trait(db, krate) // get unsize trait | ||
299 | // the existence of the Unsize trait has been checked before | ||
300 | .expect("Unsize trait missing"); | ||
301 | |||
302 | let substs = Substs::builder(2) | ||
303 | // .push(Ty::Dyn(todo!())) | ||
304 | // .push(Ty::Dyn(todo!())) | ||
305 | .build(); | ||
306 | |||
307 | let trait_ref = TraitRef { trait_: unsize_trait, substs }; | ||
308 | |||
309 | BuiltinImplData { | ||
310 | num_vars: 1, | ||
311 | trait_ref, | ||
312 | where_clauses: Vec::new(), | ||
313 | assoc_ty_values: Vec::new(), | ||
314 | } | ||
315 | } | ||
316 | |||
219 | fn get_fn_trait( | 317 | fn get_fn_trait( |
220 | db: &impl HirDatabase, | 318 | db: &impl HirDatabase, |
221 | krate: CrateId, | 319 | krate: CrateId, |
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 1bdf13e48..e1e430aeb 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -572,8 +572,10 @@ where | |||
572 | .collect(); | 572 | .collect(); |
573 | 573 | ||
574 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); | 574 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); |
575 | let arg: Option<Ty> = | ||
576 | parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref().clone())); | ||
575 | 577 | ||
576 | builtin::get_builtin_impls(self.db, self.krate, &ty, trait_, |i| { | 578 | builtin::get_builtin_impls(self.db, self.krate, &ty, &arg, trait_, |i| { |
577 | result.push(i.to_chalk(self.db)) | 579 | result.push(i.to_chalk(self.db)) |
578 | }); | 580 | }); |
579 | 581 | ||