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.rs371
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`.
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) = 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
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 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
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_ = 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
198fn 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
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}