aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits/builtin.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/traits/builtin.rs')
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs201
1 files changed, 4 insertions, 197 deletions
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index 6d5f2d46a..86e22e459 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -1,15 +1,12 @@
1//! This module provides the built-in trait implementations, e.g. to make 1//! This module provides the built-in trait implementations, e.g. to make
2//! closures implement `Fn`. 2//! closures implement `Fn`.
3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; 3use hir_def::{expr::Expr, 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, UnsizeToSuperTraitObjectData}; 7use super::{AssocTyValue, Impl};
8use crate::{ 8use crate::{
9 db::HirDatabase, 9 db::HirDatabase, ApplicationTy, BoundVar, DebruijnIndex, Substs, TraitRef, Ty, TypeCtor,
10 utils::{all_super_traits, generics},
11 ApplicationTy, Binders, BoundVar, DebruijnIndex, GenericPredicate, Substs, TraitRef, Ty,
12 TypeCtor, TypeWalk,
13}; 10};
14 11
15pub(super) struct BuiltinImplData { 12pub(super) struct BuiltinImplData {
@@ -31,7 +28,7 @@ pub(super) fn get_builtin_impls(
31 krate: CrateId, 28 krate: CrateId,
32 ty: &Ty, 29 ty: &Ty,
33 // The first argument for the trait, if present 30 // The first argument for the trait, if present
34 arg: &Option<Ty>, 31 _arg: &Option<Ty>,
35 trait_: TraitId, 32 trait_: TraitId,
36 mut callback: impl FnMut(Impl), 33 mut callback: impl FnMut(Impl),
37) { 34) {
@@ -50,60 +47,12 @@ pub(super) fn get_builtin_impls(
50 } 47 }
51 } 48 }
52 } 49 }
53
54 let unsize_trait = get_unsize_trait(db, krate);
55 if let Some(actual_trait) = unsize_trait {
56 if trait_ == actual_trait {
57 get_builtin_unsize_impls(db, krate, ty, arg, callback);
58 }
59 }
60}
61
62fn get_builtin_unsize_impls(
63 db: &dyn HirDatabase,
64 krate: CrateId,
65 ty: &Ty,
66 // The first argument for the trait, if present
67 arg: &Option<Ty>,
68 mut callback: impl FnMut(Impl),
69) {
70 if !check_unsize_impl_prerequisites(db, krate) {
71 return;
72 }
73
74 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty {
75 callback(Impl::UnsizeArray);
76 return; // array is unsized, the rest of the impls shouldn't apply
77 }
78
79 if let Some(target_trait) = arg.as_ref().and_then(|t| t.dyn_trait_ref()) {
80 // FIXME what about more complicated dyn tys with marker traits?
81 if let Some(trait_ref) = ty.dyn_trait_ref() {
82 if trait_ref.trait_ != target_trait.trait_ {
83 let super_traits = all_super_traits(db.upcast(), trait_ref.trait_);
84 if super_traits.contains(&target_trait.trait_) {
85 callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData {
86 trait_: trait_ref.trait_,
87 super_trait: target_trait.trait_,
88 }));
89 }
90 }
91 } else {
92 // FIXME only for sized types
93 callback(Impl::UnsizeToTraitObject(target_trait.trait_));
94 }
95 }
96} 50}
97 51
98pub(super) fn impl_datum(db: &dyn HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { 52pub(super) fn impl_datum(db: &dyn HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData {
99 match impl_ { 53 match impl_ {
100 Impl::ImplDef(_) => unreachable!(), 54 Impl::ImplDef(_) => unreachable!(),
101 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), 55 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
102 Impl::UnsizeArray => array_unsize_impl_datum(db, krate),
103 Impl::UnsizeToTraitObject(trait_) => trait_object_unsize_impl_datum(db, krate, trait_),
104 Impl::UnsizeToSuperTraitObject(data) => {
105 super_trait_object_unsize_impl_datum(db, krate, data)
106 }
107 } 56 }
108} 57}
109 58
@@ -227,145 +176,3 @@ fn closure_fn_trait_output_assoc_ty_value(
227 value: output_ty, 176 value: output_ty,
228 } 177 }
229} 178}
230
231// Array unsizing
232
233fn check_unsize_impl_prerequisites(db: &dyn HirDatabase, krate: CrateId) -> bool {
234 // the Unsize trait needs to exist and have two type parameters (Self and T)
235 let unsize_trait = match get_unsize_trait(db, krate) {
236 Some(t) => t,
237 None => return false,
238 };
239 let generic_params = generics(db.upcast(), unsize_trait.into());
240 generic_params.len() == 2
241}
242
243fn array_unsize_impl_datum(db: &dyn HirDatabase, krate: CrateId) -> BuiltinImplData {
244 // impl<T> Unsize<[T]> for [T; _]
245 // (this can be a single impl because we don't distinguish array sizes currently)
246
247 let trait_ = get_unsize_trait(db, krate) // get unsize trait
248 // the existence of the Unsize trait has been checked before
249 .expect("Unsize trait missing");
250
251 let var = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
252 let substs = Substs::builder(2)
253 .push(Ty::apply_one(TypeCtor::Array, var.clone()))
254 .push(Ty::apply_one(TypeCtor::Slice, var))
255 .build();
256
257 let trait_ref = TraitRef { trait_, substs };
258
259 BuiltinImplData {
260 num_vars: 1,
261 trait_ref,
262 where_clauses: Vec::new(),
263 assoc_ty_values: Vec::new(),
264 }
265}
266
267// Trait object unsizing
268
269fn trait_object_unsize_impl_datum(
270 db: &dyn HirDatabase,
271 krate: CrateId,
272 trait_: TraitId,
273) -> BuiltinImplData {
274 // impl<T, T1, ...> Unsize<dyn Trait<T1, ...>> for T where T: Trait<T1, ...>
275
276 let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
277 // the existence of the Unsize trait has been checked before
278 .expect("Unsize trait missing");
279
280 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
281
282 let target_substs = Substs::build_for_def(db, trait_)
283 .push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
284 .fill_with_bound_vars(DebruijnIndex::ONE, 1)
285 .build();
286 let num_vars = target_substs.len();
287 let target_trait_ref = TraitRef { trait_, substs: target_substs };
288 let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)];
289
290 let self_substs =
291 Substs::build_for_def(db, trait_).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
292 let self_trait_ref = TraitRef { trait_, substs: self_substs };
293 let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
294
295 let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build();
296
297 let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
298
299 BuiltinImplData { num_vars, trait_ref, where_clauses, assoc_ty_values: Vec::new() }
300}
301
302fn super_trait_object_unsize_impl_datum(
303 db: &dyn HirDatabase,
304 krate: CrateId,
305 data: UnsizeToSuperTraitObjectData,
306) -> BuiltinImplData {
307 // impl<T1, ...> Unsize<dyn SuperTrait> for dyn Trait<T1, ...>
308
309 let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
310 // the existence of the Unsize trait has been checked before
311 .expect("Unsize trait missing");
312
313 let self_substs = Substs::build_for_def(db, data.trait_)
314 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
315 .build();
316 let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() };
317
318 let num_vars = self_substs.len() - 1;
319
320 // we need to go from our trait to the super trait, substituting type parameters
321 let path = crate::utils::find_super_trait_path(db.upcast(), data.trait_, data.super_trait);
322
323 let mut current_trait_ref = self_trait_ref.clone();
324 for t in path.into_iter().skip(1) {
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
331 && tr.substs[0]
332 == Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)) =>
333 {
334 Some(Binders { value: tr, num_binders: b.num_binders })
335 }
336 _ => None,
337 })
338 .expect("trait bound for known super trait not found");
339 current_trait_ref = super_trait_ref.cloned().subst(&current_trait_ref.substs);
340 }
341
342 // We need to renumber the variables a bit now: from ^0.0, ^0.1, ^0.2, ...
343 // to ^0.0, ^1.0, ^1.1. The reason for this is that the first variable comes
344 // from the dyn Trait binder, while the other variables come from the impl.
345 let new_substs = Substs::builder(num_vars + 1)
346 .push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
347 .fill_with_bound_vars(DebruijnIndex::ONE, 0)
348 .build();
349
350 let self_bounds =
351 vec![GenericPredicate::Implemented(self_trait_ref.subst_bound_vars(&new_substs))];
352 let super_bounds =
353 vec![GenericPredicate::Implemented(current_trait_ref.subst_bound_vars(&new_substs))];
354
355 let substs = Substs::builder(2)
356 .push(Ty::Dyn(self_bounds.into()))
357 .push(Ty::Dyn(super_bounds.into()))
358 .build();
359
360 let trait_ref = TraitRef { trait_: unsize_trait, substs };
361
362 BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() }
363}
364
365fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
366 let target = db.lang_item(krate, "unsize".into())?;
367 match target {
368 LangItemTarget::TraitId(t) => Some(t),
369 _ => None,
370 }
371}