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.rs377
1 files changed, 0 insertions, 377 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 88a422d2c..000000000
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ /dev/null
@@ -1,377 +0,0 @@
1//! This module provides the built-in trait implementations, e.g. to make
2//! closures implement `Fn`.
3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
4use hir_expand::name::name;
5use ra_db::CrateId;
6
7use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData};
8use crate::{
9 db::HirDatabase,
10 utils::{all_super_traits, generics},
11 ApplicationTy, Binders, BoundVar, DebruijnIndex, GenericPredicate, Substs, TraitRef, Ty,
12 TypeCtor, TypeWalk,
13};
14
15pub(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
22pub(super) struct BuiltinImplAssocTyValueData {
23 pub impl_: Impl,
24 pub assoc_ty_id: TypeAliasId,
25 pub num_vars: usize,
26 pub value: Ty,
27}
28
29pub(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) = get_fn_trait(db, krate, fn_trait) {
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
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}
97
98pub(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
110pub(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
125fn 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 get_fn_trait(db, krate, data.fn_trait).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 get_fn_trait(db, krate, super::FnTrait::FnOnce) {
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
146fn 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_ = get_fn_trait(db, krate, data.fn_trait) // get corresponding fn trait
155 // the existence of the Fn trait has been checked before
156 .expect("fn trait for closure impl missing");
157
158 let num_args: u16 = match &db.body(data.def)[data.expr] {
159 Expr::Lambda { args, .. } => args.len() as u16,
160 _ => {
161 log::warn!("closure for closure type {:?} not found", data);
162 0
163 }
164 };
165
166 let arg_ty = Ty::apply(
167 TypeCtor::Tuple { cardinality: num_args },
168 Substs::builder(num_args as usize)
169 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
170 .build(),
171 );
172 let sig_ty = Ty::apply(
173 TypeCtor::FnPtr { num_args },
174 Substs::builder(num_args as usize + 1)
175 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
176 .build(),
177 );
178
179 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
180
181 let trait_ref = TraitRef {
182 trait_,
183 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
184 };
185
186 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data);
187
188 BuiltinImplData {
189 num_vars: num_args as usize + 1,
190 trait_ref,
191 where_clauses: Vec::new(),
192 assoc_ty_values: vec![output_ty_id],
193 }
194}
195
196fn closure_fn_trait_output_assoc_ty_value(
197 db: &dyn HirDatabase,
198 krate: CrateId,
199 data: super::ClosureFnTraitImplData,
200) -> BuiltinImplAssocTyValueData {
201 let impl_ = Impl::ClosureFnTraitImpl(data);
202
203 let num_args: u16 = match &db.body(data.def)[data.expr] {
204 Expr::Lambda { args, .. } => args.len() as u16,
205 _ => {
206 log::warn!("closure for closure type {:?} not found", data);
207 0
208 }
209 };
210
211 let output_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, num_args.into()));
212
213 let fn_once_trait =
214 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
215
216 let output_ty_id = db
217 .trait_data(fn_once_trait)
218 .associated_type_by_name(&name![Output])
219 .expect("assoc ty value should not exist");
220
221 BuiltinImplAssocTyValueData {
222 impl_,
223 assoc_ty_id: output_ty_id,
224 num_vars: num_args as usize + 1,
225 value: output_ty,
226 }
227}
228
229// Array unsizing
230
231fn check_unsize_impl_prerequisites(db: &dyn HirDatabase, krate: CrateId) -> bool {
232 // the Unsize trait needs to exist and have two type parameters (Self and T)
233 let unsize_trait = match get_unsize_trait(db, krate) {
234 Some(t) => t,
235 None => return false,
236 };
237 let generic_params = generics(db.upcast(), unsize_trait.into());
238 generic_params.len() == 2
239}
240
241fn array_unsize_impl_datum(db: &dyn HirDatabase, krate: CrateId) -> BuiltinImplData {
242 // impl<T> Unsize<[T]> for [T; _]
243 // (this can be a single impl because we don't distinguish array sizes currently)
244
245 let trait_ = get_unsize_trait(db, krate) // get unsize trait
246 // the existence of the Unsize trait has been checked before
247 .expect("Unsize trait missing");
248
249 let var = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
250 let substs = Substs::builder(2)
251 .push(Ty::apply_one(TypeCtor::Array, var.clone()))
252 .push(Ty::apply_one(TypeCtor::Slice, var))
253 .build();
254
255 let trait_ref = TraitRef { trait_, substs };
256
257 BuiltinImplData {
258 num_vars: 1,
259 trait_ref,
260 where_clauses: Vec::new(),
261 assoc_ty_values: Vec::new(),
262 }
263}
264
265// Trait object unsizing
266
267fn trait_object_unsize_impl_datum(
268 db: &dyn HirDatabase,
269 krate: CrateId,
270 trait_: TraitId,
271) -> BuiltinImplData {
272 // impl<T, T1, ...> Unsize<dyn Trait<T1, ...>> for T where T: Trait<T1, ...>
273
274 let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
275 // the existence of the Unsize trait has been checked before
276 .expect("Unsize trait missing");
277
278 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
279
280 let target_substs = Substs::build_for_def(db, trait_)
281 .push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
282 .fill_with_bound_vars(DebruijnIndex::ONE, 1)
283 .build();
284 let num_vars = target_substs.len();
285 let target_trait_ref = TraitRef { trait_, substs: target_substs };
286 let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)];
287
288 let self_substs =
289 Substs::build_for_def(db, trait_).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
290 let self_trait_ref = TraitRef { trait_, substs: self_substs };
291 let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
292
293 let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build();
294
295 let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
296
297 BuiltinImplData { num_vars, trait_ref, where_clauses, assoc_ty_values: Vec::new() }
298}
299
300fn super_trait_object_unsize_impl_datum(
301 db: &dyn HirDatabase,
302 krate: CrateId,
303 data: UnsizeToSuperTraitObjectData,
304) -> BuiltinImplData {
305 // impl<T1, ...> Unsize<dyn SuperTrait> for dyn Trait<T1, ...>
306
307 let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
308 // the existence of the Unsize trait has been checked before
309 .expect("Unsize trait missing");
310
311 let self_substs = Substs::build_for_def(db, data.trait_)
312 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
313 .build();
314 let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() };
315
316 let num_vars = self_substs.len() - 1;
317
318 // we need to go from our trait to the super trait, substituting type parameters
319 let path = crate::utils::find_super_trait_path(db.upcast(), data.trait_, data.super_trait);
320
321 let mut current_trait_ref = self_trait_ref.clone();
322 for t in path.into_iter().skip(1) {
323 let bounds = db.generic_predicates(current_trait_ref.trait_.into());
324 let super_trait_ref = bounds
325 .iter()
326 .find_map(|b| match &b.value {
327 GenericPredicate::Implemented(tr)
328 if tr.trait_ == t
329 && tr.substs[0]
330 == Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 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(&current_trait_ref.substs);
338 }
339
340 // We need to renumber the variables a bit now: from ^0.0, ^0.1, ^0.2, ...
341 // to ^0.0, ^1.0, ^1.1. The reason for this is that the first variable comes
342 // from the dyn Trait binder, while the other variables come from the impl.
343 let new_substs = Substs::builder(num_vars + 1)
344 .push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
345 .fill_with_bound_vars(DebruijnIndex::ONE, 0)
346 .build();
347
348 let self_bounds =
349 vec![GenericPredicate::Implemented(self_trait_ref.subst_bound_vars(&new_substs))];
350 let super_bounds =
351 vec![GenericPredicate::Implemented(current_trait_ref.subst_bound_vars(&new_substs))];
352
353 let substs = Substs::builder(2)
354 .push(Ty::Dyn(self_bounds.into()))
355 .push(Ty::Dyn(super_bounds.into()))
356 .build();
357
358 let trait_ref = TraitRef { trait_: unsize_trait, substs };
359
360 BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() }
361}
362
363fn get_fn_trait(db: &dyn HirDatabase, krate: CrateId, fn_trait: super::FnTrait) -> Option<TraitId> {
364 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
365 match target {
366 LangItemTarget::TraitId(t) => Some(t),
367 _ => None,
368 }
369}
370
371fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
372 let target = db.lang_item(krate, "unsize".into())?;
373 match target {
374 LangItemTarget::TraitId(t) => Some(t),
375 _ => None,
376 }
377}