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/traits | |
parent | f126808b2ee79792631edc377bc8c2b0f329eebf (diff) |
Add &dyn Trait -> &dyn SuperTrait coercion, and fix &T -> &dyn Trait
Diffstat (limited to 'crates/ra_hir_ty/src/traits')
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 95 |
1 files changed, 65 insertions, 30 deletions
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( |