aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_ty/src/lib.rs11
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs8
-rw-r--r--crates/ra_hir_ty/src/traits.rs10
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs112
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs4
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]
581fn coerce_unsize_trait_object() { 580fn 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)]
339pub 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};
4use hir_expand::name::name; 4use hir_expand::name::name;
5use ra_db::CrateId; 5use ra_db::CrateId;
6 6
7use super::{AssocTyValue, Impl}; 7use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData};
8use crate::{db::HirDatabase, utils::generics, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; 8use crate::{
9 db::HirDatabase,
10 utils::{all_super_traits, generics},
11 ApplicationTy, GenericPredicate, Substs, TraitRef, Ty, TypeCtor,
12};
9 13
10pub(super) struct BuiltinImplData { 14pub(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
61fn 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
260fn 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
291fn 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
219fn get_fn_trait( 317fn 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