diff options
Diffstat (limited to 'crates/ra_hir_ty/src/traits/builtin.rs')
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 371 |
1 files changed, 0 insertions, 371 deletions
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs deleted file mode 100644 index 6d5f2d46a..000000000 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ /dev/null | |||
@@ -1,371 +0,0 @@ | |||
1 | //! This module provides the built-in trait implementations, e.g. to make | ||
2 | //! closures implement `Fn`. | ||
3 | use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId}; | ||
4 | use hir_expand::name::name; | ||
5 | use ra_db::CrateId; | ||
6 | |||
7 | use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData}; | ||
8 | use crate::{ | ||
9 | db::HirDatabase, | ||
10 | utils::{all_super_traits, generics}, | ||
11 | ApplicationTy, Binders, BoundVar, DebruijnIndex, GenericPredicate, Substs, TraitRef, Ty, | ||
12 | TypeCtor, TypeWalk, | ||
13 | }; | ||
14 | |||
15 | pub(super) struct BuiltinImplData { | ||
16 | pub num_vars: usize, | ||
17 | pub trait_ref: TraitRef, | ||
18 | pub where_clauses: Vec<super::GenericPredicate>, | ||
19 | pub assoc_ty_values: Vec<AssocTyValue>, | ||
20 | } | ||
21 | |||
22 | pub(super) struct BuiltinImplAssocTyValueData { | ||
23 | pub impl_: Impl, | ||
24 | pub assoc_ty_id: TypeAliasId, | ||
25 | pub num_vars: usize, | ||
26 | pub value: Ty, | ||
27 | } | ||
28 | |||
29 | pub(super) fn get_builtin_impls( | ||
30 | db: &dyn HirDatabase, | ||
31 | krate: CrateId, | ||
32 | ty: &Ty, | ||
33 | // The first argument for the trait, if present | ||
34 | arg: &Option<Ty>, | ||
35 | trait_: TraitId, | ||
36 | mut callback: impl FnMut(Impl), | ||
37 | ) { | ||
38 | // Note: since impl_datum needs to be infallible, we need to make sure here | ||
39 | // that we have all prerequisites to build the respective impls. | ||
40 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { | ||
41 | for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() | ||
42 | { | ||
43 | if let Some(actual_trait) = fn_trait.get_id(db, krate) { | ||
44 | if trait_ == actual_trait { | ||
45 | let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait }; | ||
46 | if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) { | ||
47 | callback(Impl::ClosureFnTraitImpl(impl_)); | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | } | ||
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 | |||
62 | fn 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 | } | ||
97 | |||
98 | pub(super) fn impl_datum(db: &dyn HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { | ||
99 | match impl_ { | ||
100 | Impl::ImplDef(_) => unreachable!(), | ||
101 | 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 | } | ||
108 | } | ||
109 | |||
110 | pub(super) fn associated_ty_value( | ||
111 | db: &dyn HirDatabase, | ||
112 | krate: CrateId, | ||
113 | data: AssocTyValue, | ||
114 | ) -> BuiltinImplAssocTyValueData { | ||
115 | match data { | ||
116 | AssocTyValue::TypeAlias(_) => unreachable!(), | ||
117 | AssocTyValue::ClosureFnTraitImplOutput(data) => { | ||
118 | closure_fn_trait_output_assoc_ty_value(db, krate, data) | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | // Closure Fn trait impls | ||
124 | |||
125 | fn check_closure_fn_trait_impl_prerequisites( | ||
126 | db: &dyn HirDatabase, | ||
127 | krate: CrateId, | ||
128 | data: super::ClosureFnTraitImplData, | ||
129 | ) -> bool { | ||
130 | // the respective Fn/FnOnce/FnMut trait needs to exist | ||
131 | if data.fn_trait.get_id(db, krate).is_none() { | ||
132 | return false; | ||
133 | } | ||
134 | |||
135 | // FIXME: there are more assumptions that we should probably check here: | ||
136 | // the traits having no type params, FnOnce being a supertrait | ||
137 | |||
138 | // the FnOnce trait needs to exist and have an assoc type named Output | ||
139 | let fn_once_trait = match (super::FnTrait::FnOnce).get_id(db, krate) { | ||
140 | Some(t) => t, | ||
141 | None => return false, | ||
142 | }; | ||
143 | db.trait_data(fn_once_trait).associated_type_by_name(&name![Output]).is_some() | ||
144 | } | ||
145 | |||
146 | fn closure_fn_trait_impl_datum( | ||
147 | db: &dyn HirDatabase, | ||
148 | krate: CrateId, | ||
149 | data: super::ClosureFnTraitImplData, | ||
150 | ) -> BuiltinImplData { | ||
151 | // for some closure |X, Y| -> Z: | ||
152 | // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } | ||
153 | |||
154 | let trait_ = data | ||
155 | .fn_trait | ||
156 | .get_id(db, krate) // get corresponding fn trait | ||
157 | // the existence of the Fn trait has been checked before | ||
158 | .expect("fn trait for closure impl missing"); | ||
159 | |||
160 | let num_args: u16 = match &db.body(data.def)[data.expr] { | ||
161 | Expr::Lambda { args, .. } => args.len() as u16, | ||
162 | _ => { | ||
163 | log::warn!("closure for closure type {:?} not found", data); | ||
164 | 0 | ||
165 | } | ||
166 | }; | ||
167 | |||
168 | let arg_ty = Ty::apply( | ||
169 | TypeCtor::Tuple { cardinality: num_args }, | ||
170 | Substs::builder(num_args as usize) | ||
171 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) | ||
172 | .build(), | ||
173 | ); | ||
174 | let sig_ty = Ty::apply( | ||
175 | TypeCtor::FnPtr { num_args }, | ||
176 | Substs::builder(num_args as usize + 1) | ||
177 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) | ||
178 | .build(), | ||
179 | ); | ||
180 | |||
181 | let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty); | ||
182 | |||
183 | let trait_ref = TraitRef { | ||
184 | trait_, | ||
185 | substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(), | ||
186 | }; | ||
187 | |||
188 | let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data); | ||
189 | |||
190 | BuiltinImplData { | ||
191 | num_vars: num_args as usize + 1, | ||
192 | trait_ref, | ||
193 | where_clauses: Vec::new(), | ||
194 | assoc_ty_values: vec![output_ty_id], | ||
195 | } | ||
196 | } | ||
197 | |||
198 | fn closure_fn_trait_output_assoc_ty_value( | ||
199 | db: &dyn HirDatabase, | ||
200 | krate: CrateId, | ||
201 | data: super::ClosureFnTraitImplData, | ||
202 | ) -> BuiltinImplAssocTyValueData { | ||
203 | let impl_ = Impl::ClosureFnTraitImpl(data); | ||
204 | |||
205 | let num_args: u16 = match &db.body(data.def)[data.expr] { | ||
206 | Expr::Lambda { args, .. } => args.len() as u16, | ||
207 | _ => { | ||
208 | log::warn!("closure for closure type {:?} not found", data); | ||
209 | 0 | ||
210 | } | ||
211 | }; | ||
212 | |||
213 | let output_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, num_args.into())); | ||
214 | |||
215 | let fn_once_trait = | ||
216 | (super::FnTrait::FnOnce).get_id(db, krate).expect("assoc ty value should not exist"); | ||
217 | |||
218 | let output_ty_id = db | ||
219 | .trait_data(fn_once_trait) | ||
220 | .associated_type_by_name(&name![Output]) | ||
221 | .expect("assoc ty value should not exist"); | ||
222 | |||
223 | BuiltinImplAssocTyValueData { | ||
224 | impl_, | ||
225 | assoc_ty_id: output_ty_id, | ||
226 | num_vars: num_args as usize + 1, | ||
227 | value: output_ty, | ||
228 | } | ||
229 | } | ||
230 | |||
231 | // Array unsizing | ||
232 | |||
233 | fn 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 | |||
243 | fn 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 | |||
269 | fn 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 | |||
302 | fn 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(¤t_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 | |||
365 | fn 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 | } | ||