aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-02-21 17:24:18 +0000
committerFlorian Diebold <[email protected]>2020-02-22 10:09:21 +0000
commitde39d221a15c0a146ed8adbdb1616692180948bb (patch)
treec88cddbadedb021365e518d68502e8c2f9c21077 /crates/ra_hir_ty/src/traits
parentbaf832d6d903afbc39e3a01c752a1aa5218c020e (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.rs61
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;
5use ra_db::CrateId; 5use ra_db::CrateId;
6 6
7use super::{AssocTyValue, Impl}; 7use super::{AssocTyValue, Impl};
8use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; 8use crate::{db::HirDatabase, utils::generics, ApplicationTy, Substs, TraitRef, Ty, TypeCtor};
9 9
10pub(super) struct BuiltinImplData { 10pub(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
48pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { 57pub(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
68fn check_closure_fn_trait_impl_prerequisites( 80fn 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
182fn 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
195fn 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
168fn get_fn_trait( 219fn 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
231fn 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}