diff options
author | Florian Diebold <[email protected]> | 2020-02-21 17:24:18 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2020-02-22 10:09:21 +0000 |
commit | de39d221a15c0a146ed8adbdb1616692180948bb (patch) | |
tree | c88cddbadedb021365e518d68502e8c2f9c21077 /crates/ra_hir_ty/src/traits | |
parent | baf832d6d903afbc39e3a01c752a1aa5218c020e (diff) |
Implement unsize coercion using proper trait solving
Diffstat (limited to 'crates/ra_hir_ty/src/traits')
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index a537420a5..394232fd9 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -5,7 +5,7 @@ use hir_expand::name::name; | |||
5 | use ra_db::CrateId; | 5 | use ra_db::CrateId; |
6 | 6 | ||
7 | use super::{AssocTyValue, Impl}; | 7 | use super::{AssocTyValue, Impl}; |
8 | use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; | 8 | use crate::{db::HirDatabase, utils::generics, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; |
9 | 9 | ||
10 | pub(super) struct BuiltinImplData { | 10 | pub(super) struct BuiltinImplData { |
11 | pub num_vars: usize, | 11 | pub num_vars: usize, |
@@ -43,12 +43,22 @@ pub(super) fn get_builtin_impls( | |||
43 | } | 43 | } |
44 | } | 44 | } |
45 | } | 45 | } |
46 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty { | ||
47 | if let Some(actual_trait) = get_unsize_trait(db, krate) { | ||
48 | if trait_ == actual_trait { | ||
49 | if check_unsize_impl_prerequisites(db, krate) { | ||
50 | callback(Impl::UnsizeArray); | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | } | ||
46 | } | 55 | } |
47 | 56 | ||
48 | pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { | 57 | pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { |
49 | match impl_ { | 58 | match impl_ { |
50 | Impl::ImplBlock(_) => unreachable!(), | 59 | Impl::ImplBlock(_) => unreachable!(), |
51 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), | 60 | Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), |
61 | Impl::UnsizeArray => array_unsize_impl_datum(db, krate), | ||
52 | } | 62 | } |
53 | } | 63 | } |
54 | 64 | ||
@@ -65,6 +75,8 @@ pub(super) fn associated_ty_value( | |||
65 | } | 75 | } |
66 | } | 76 | } |
67 | 77 | ||
78 | // Closure Fn trait impls | ||
79 | |||
68 | fn check_closure_fn_trait_impl_prerequisites( | 80 | fn check_closure_fn_trait_impl_prerequisites( |
69 | db: &impl HirDatabase, | 81 | db: &impl HirDatabase, |
70 | krate: CrateId, | 82 | krate: CrateId, |
@@ -165,6 +177,45 @@ fn closure_fn_trait_output_assoc_ty_value( | |||
165 | } | 177 | } |
166 | } | 178 | } |
167 | 179 | ||
180 | // Array unsizing | ||
181 | |||
182 | fn check_unsize_impl_prerequisites(db: &impl HirDatabase, krate: CrateId) -> bool { | ||
183 | // the Unsize trait needs to exist and have two type parameters (Self and T) | ||
184 | let unsize_trait = match get_unsize_trait(db, krate) { | ||
185 | Some(t) => t, | ||
186 | None => return false, | ||
187 | }; | ||
188 | let generic_params = generics(db, unsize_trait.into()); | ||
189 | if generic_params.len() != 2 { | ||
190 | return false; | ||
191 | } | ||
192 | true | ||
193 | } | ||
194 | |||
195 | fn array_unsize_impl_datum(db: &impl HirDatabase, krate: CrateId) -> BuiltinImplData { | ||
196 | // impl<T> Unsize<[T]> for [T; _] | ||
197 | // (this can be a single impl because we don't distinguish array sizes currently) | ||
198 | |||
199 | let trait_ = get_unsize_trait(db, krate) // get unsize trait | ||
200 | // the existence of the Unsize trait has been checked before | ||
201 | .expect("Unsize trait missing"); | ||
202 | |||
203 | let var = Ty::Bound(0); | ||
204 | let substs = Substs::builder(2) | ||
205 | .push(Ty::apply_one(TypeCtor::Array, var.clone())) | ||
206 | .push(Ty::apply_one(TypeCtor::Slice, var)) | ||
207 | .build(); | ||
208 | |||
209 | let trait_ref = TraitRef { trait_, substs }; | ||
210 | |||
211 | BuiltinImplData { | ||
212 | num_vars: 1, | ||
213 | trait_ref, | ||
214 | where_clauses: Vec::new(), | ||
215 | assoc_ty_values: Vec::new(), | ||
216 | } | ||
217 | } | ||
218 | |||
168 | fn get_fn_trait( | 219 | fn get_fn_trait( |
169 | db: &impl HirDatabase, | 220 | db: &impl HirDatabase, |
170 | krate: CrateId, | 221 | krate: CrateId, |
@@ -176,3 +227,11 @@ fn get_fn_trait( | |||
176 | _ => None, | 227 | _ => None, |
177 | } | 228 | } |
178 | } | 229 | } |
230 | |||
231 | fn get_unsize_trait(db: &impl HirDatabase, krate: CrateId) -> Option<TraitId> { | ||
232 | let target = db.lang_item(krate, "unsize".into())?; | ||
233 | match target { | ||
234 | LangItemTarget::TraitId(t) => Some(t), | ||
235 | _ => None, | ||
236 | } | ||
237 | } | ||