From de39d221a15c0a146ed8adbdb1616692180948bb Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 21 Feb 2020 18:24:18 +0100 Subject: Implement unsize coercion using proper trait solving --- crates/ra_hir_ty/src/traits/builtin.rs | 61 +++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir_ty/src/traits') 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; use ra_db::CrateId; use super::{AssocTyValue, Impl}; -use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; +use crate::{db::HirDatabase, utils::generics, ApplicationTy, Substs, TraitRef, Ty, TypeCtor}; pub(super) struct BuiltinImplData { pub num_vars: usize, @@ -43,12 +43,22 @@ pub(super) fn get_builtin_impls( } } } + if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty { + if let Some(actual_trait) = get_unsize_trait(db, krate) { + if trait_ == actual_trait { + if check_unsize_impl_prerequisites(db, krate) { + callback(Impl::UnsizeArray); + } + } + } + } } pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData { match impl_ { Impl::ImplBlock(_) => unreachable!(), Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), + Impl::UnsizeArray => array_unsize_impl_datum(db, krate), } } @@ -65,6 +75,8 @@ pub(super) fn associated_ty_value( } } +// Closure Fn trait impls + fn check_closure_fn_trait_impl_prerequisites( db: &impl HirDatabase, krate: CrateId, @@ -165,6 +177,45 @@ fn closure_fn_trait_output_assoc_ty_value( } } +// Array unsizing + +fn check_unsize_impl_prerequisites(db: &impl HirDatabase, krate: CrateId) -> bool { + // the Unsize trait needs to exist and have two type parameters (Self and T) + let unsize_trait = match get_unsize_trait(db, krate) { + Some(t) => t, + None => return false, + }; + let generic_params = generics(db, unsize_trait.into()); + if generic_params.len() != 2 { + return false; + } + true +} + +fn array_unsize_impl_datum(db: &impl HirDatabase, krate: CrateId) -> BuiltinImplData { + // impl Unsize<[T]> for [T; _] + // (this can be a single impl because we don't distinguish array sizes currently) + + let trait_ = get_unsize_trait(db, krate) // get unsize trait + // the existence of the Unsize trait has been checked before + .expect("Unsize trait missing"); + + let var = Ty::Bound(0); + let substs = Substs::builder(2) + .push(Ty::apply_one(TypeCtor::Array, var.clone())) + .push(Ty::apply_one(TypeCtor::Slice, var)) + .build(); + + let trait_ref = TraitRef { trait_, substs }; + + BuiltinImplData { + num_vars: 1, + trait_ref, + where_clauses: Vec::new(), + assoc_ty_values: Vec::new(), + } +} + fn get_fn_trait( db: &impl HirDatabase, krate: CrateId, @@ -176,3 +227,11 @@ fn get_fn_trait( _ => None, } } + +fn get_unsize_trait(db: &impl HirDatabase, krate: CrateId) -> Option { + let target = db.lang_item(krate, "unsize".into())?; + match target { + LangItemTarget::TraitId(t) => Some(t), + _ => None, + } +} -- cgit v1.2.3