aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits/builtin.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-02-22 12:31:30 +0000
committerGitHub <[email protected]>2020-02-22 12:31:30 +0000
commit2cbe8a4c4be2a69b27c248ab96341c2336f983cd (patch)
treeee1a32b47f889ed132a314286cd90a07f3700216 /crates/ra_hir_ty/src/traits/builtin.rs
parent7836720f2e9a7fa01ae09ff9d51413ecd5877139 (diff)
parent5a6e770f99d1549432c1e8a1abb1aada09ad2590 (diff)
Merge #3263
3263: Implement unsizing coercions using Chalk r=matklad a=flodiebold These are coercions like `&[T; n] -> &[T]`, which are handled by the `Unsize` and `CoerceUnsized` traits. The impls for `Unsize` are all built in to the compiler and require special handling, so we need to provide them to Chalk. This adds the following `Unsize` impls: - `Unsize<[T]> for [T; _]` - `Unsize<dyn Trait> for T where T: Trait` - `Unsize<dyn SuperTrait> for dyn SubTrait` Hence we are still missing the 'unsizing the last field of a generic struct' case. Co-authored-by: Florian Diebold <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty/src/traits/builtin.rs')
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs191
1 files changed, 189 insertions, 2 deletions
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index a537420a5..cc0f3eeb4 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, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; 8use crate::{
9 db::HirDatabase,
10 utils::{all_super_traits, generics},
11 ApplicationTy, Binders, 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,12 +49,60 @@ 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
73 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty {
74 callback(Impl::UnsizeArray);
75 return; // array is unsized, the rest of the impls shouldn't apply
76 }
77
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?
80 if let Some(trait_ref) = ty.dyn_trait_ref() {
81 if trait_ref.trait_ != target_trait.trait_ {
82 let super_traits = all_super_traits(db, trait_ref.trait_);
83 if super_traits.contains(&target_trait.trait_) {
84 callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData {
85 trait_: trait_ref.trait_,
86 super_trait: target_trait.trait_,
87 }));
88 }
89 }
90 } else {
91 // FIXME only for sized types
92 callback(Impl::UnsizeToTraitObject(target_trait.trait_));
93 }
94 }
46} 95}
47 96
48pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { 97pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData {
49 match impl_ { 98 match impl_ {
50 Impl::ImplBlock(_) => unreachable!(), 99 Impl::ImplBlock(_) => unreachable!(),
51 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), 100 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
101 Impl::UnsizeArray => array_unsize_impl_datum(db, krate),
102 Impl::UnsizeToTraitObject(trait_) => trait_object_unsize_impl_datum(db, krate, trait_),
103 Impl::UnsizeToSuperTraitObject(data) => {
104 super_trait_object_unsize_impl_datum(db, krate, data)
105 }
52 } 106 }
53} 107}
54 108
@@ -65,6 +119,8 @@ pub(super) fn associated_ty_value(
65 } 119 }
66} 120}
67 121
122// Closure Fn trait impls
123
68fn check_closure_fn_trait_impl_prerequisites( 124fn check_closure_fn_trait_impl_prerequisites(
69 db: &impl HirDatabase, 125 db: &impl HirDatabase,
70 krate: CrateId, 126 krate: CrateId,
@@ -165,6 +221,129 @@ fn closure_fn_trait_output_assoc_ty_value(
165 } 221 }
166} 222}
167 223
224// Array unsizing
225
226fn check_unsize_impl_prerequisites(db: &impl HirDatabase, krate: CrateId) -> bool {
227 // the Unsize trait needs to exist and have two type parameters (Self and T)
228 let unsize_trait = match get_unsize_trait(db, krate) {
229 Some(t) => t,
230 None => return false,
231 };
232 let generic_params = generics(db, unsize_trait.into());
233 generic_params.len() == 2
234}
235
236fn array_unsize_impl_datum(db: &impl HirDatabase, krate: CrateId) -> BuiltinImplData {
237 // impl<T> Unsize<[T]> for [T; _]
238 // (this can be a single impl because we don't distinguish array sizes currently)
239
240 let trait_ = get_unsize_trait(db, krate) // get unsize trait
241 // the existence of the Unsize trait has been checked before
242 .expect("Unsize trait missing");
243
244 let var = Ty::Bound(0);
245 let substs = Substs::builder(2)
246 .push(Ty::apply_one(TypeCtor::Array, var.clone()))
247 .push(Ty::apply_one(TypeCtor::Slice, var))
248 .build();
249
250 let trait_ref = TraitRef { trait_, substs };
251
252 BuiltinImplData {
253 num_vars: 1,
254 trait_ref,
255 where_clauses: Vec::new(),
256 assoc_ty_values: Vec::new(),
257 }
258}
259
260// Trait object unsizing
261
262fn trait_object_unsize_impl_datum(
263 db: &impl HirDatabase,
264 krate: CrateId,
265 trait_: TraitId,
266) -> BuiltinImplData {
267 // impl<T, T1, ...> Unsize<dyn Trait<T1, ...>> for T where T: Trait<T1, ...>
268
269 let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
270 // the existence of the Unsize trait has been checked before
271 .expect("Unsize trait missing");
272
273 let self_ty = Ty::Bound(0);
274
275 let target_substs = Substs::build_for_def(db, trait_)
276 .push(Ty::Bound(0))
277 // starting from ^2 because we want to start with ^1 outside of the
278 // `dyn`, which is ^2 inside
279 .fill_with_bound_vars(2)
280 .build();
281 let num_vars = target_substs.len();
282 let target_trait_ref = TraitRef { trait_, substs: target_substs };
283 let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)];
284
285 let self_substs = Substs::build_for_def(db, trait_).fill_with_bound_vars(0).build();
286 let self_trait_ref = TraitRef { trait_, substs: self_substs };
287 let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
288
289 let impl_substs =
290 Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build();
291
292 let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
293
294 BuiltinImplData { num_vars, trait_ref, where_clauses, assoc_ty_values: Vec::new() }
295}
296
297fn super_trait_object_unsize_impl_datum(
298 db: &impl HirDatabase,
299 krate: CrateId,
300 data: UnsizeToSuperTraitObjectData,
301) -> BuiltinImplData {
302 // impl<T1, ...> Unsize<dyn SuperTrait> for dyn Trait<T1, ...>
303
304 let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
305 // the existence of the Unsize trait has been checked before
306 .expect("Unsize trait missing");
307
308 let self_substs = Substs::build_for_def(db, data.trait_).fill_with_bound_vars(0).build();
309
310 let num_vars = self_substs.len() - 1;
311
312 let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() };
313 let self_bounds = vec![GenericPredicate::Implemented(self_trait_ref.clone())];
314
315 // we need to go from our trait to the super trait, substituting type parameters
316 let path = crate::utils::find_super_trait_path(db, data.trait_, data.super_trait);
317
318 let mut current_trait_ref = self_trait_ref;
319 for t in path.into_iter().skip(1) {
320 let bounds = db.generic_predicates(current_trait_ref.trait_.into());
321 let super_trait_ref = bounds
322 .iter()
323 .find_map(|b| match &b.value {
324 GenericPredicate::Implemented(tr)
325 if tr.trait_ == t && tr.substs[0] == Ty::Bound(0) =>
326 {
327 Some(Binders { value: tr, num_binders: b.num_binders })
328 }
329 _ => None,
330 })
331 .expect("trait bound for known super trait not found");
332 current_trait_ref = super_trait_ref.cloned().subst(&current_trait_ref.substs);
333 }
334
335 let super_bounds = vec![GenericPredicate::Implemented(current_trait_ref)];
336
337 let substs = Substs::builder(2)
338 .push(Ty::Dyn(self_bounds.into()))
339 .push(Ty::Dyn(super_bounds.into()))
340 .build();
341
342 let trait_ref = TraitRef { trait_: unsize_trait, substs };
343
344 BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() }
345}
346
168fn get_fn_trait( 347fn get_fn_trait(
169 db: &impl HirDatabase, 348 db: &impl HirDatabase,
170 krate: CrateId, 349 krate: CrateId,
@@ -176,3 +355,11 @@ fn get_fn_trait(
176 _ => None, 355 _ => None,
177 } 356 }
178} 357}
358
359fn get_unsize_trait(db: &impl HirDatabase, krate: CrateId) -> Option<TraitId> {
360 let target = db.lang_item(krate, "unsize".into())?;
361 match target {
362 LangItemTarget::TraitId(t) => Some(t),
363 _ => None,
364 }
365}