Remove built-in Unsize impls
They exist in Chalk now.
This commit is contained in:
parent
71d645101d
commit
2a4166501d
@ -295,13 +295,8 @@ pub enum Impl {
|
||||
/// A normal impl from an impl block.
|
||||
ImplDef(ImplId),
|
||||
/// Closure types implement the Fn traits synthetically.
|
||||
// FIXME: implement closure support from Chalk, remove this
|
||||
ClosureFnTraitImpl(ClosureFnTraitImplData),
|
||||
/// [T; n]: Unsize<[T]>
|
||||
UnsizeArray,
|
||||
/// T: Unsize<dyn Trait> where T: Trait
|
||||
UnsizeToTraitObject(TraitId),
|
||||
/// dyn Trait: Unsize<dyn SuperTrait> if Trait: SuperTrait
|
||||
UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData),
|
||||
}
|
||||
/// This exists just for Chalk, because our ImplIds are only unique per module.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
@ -1,15 +1,12 @@
|
||||
//! This module provides the built-in trait implementations, e.g. to make
|
||||
//! closures implement `Fn`.
|
||||
use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
|
||||
use hir_def::{expr::Expr, TraitId, TypeAliasId};
|
||||
use hir_expand::name::name;
|
||||
use ra_db::CrateId;
|
||||
|
||||
use super::{AssocTyValue, Impl, UnsizeToSuperTraitObjectData};
|
||||
use super::{AssocTyValue, Impl};
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
utils::{all_super_traits, generics},
|
||||
ApplicationTy, Binders, BoundVar, DebruijnIndex, GenericPredicate, Substs, TraitRef, Ty,
|
||||
TypeCtor, TypeWalk,
|
||||
db::HirDatabase, ApplicationTy, BoundVar, DebruijnIndex, Substs, TraitRef, Ty, TypeCtor,
|
||||
};
|
||||
|
||||
pub(super) struct BuiltinImplData {
|
||||
@ -31,7 +28,7 @@ pub(super) fn get_builtin_impls(
|
||||
krate: CrateId,
|
||||
ty: &Ty,
|
||||
// The first argument for the trait, if present
|
||||
arg: &Option<Ty>,
|
||||
_arg: &Option<Ty>,
|
||||
trait_: TraitId,
|
||||
mut callback: impl FnMut(Impl),
|
||||
) {
|
||||
@ -50,60 +47,12 @@ pub(super) fn get_builtin_impls(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let unsize_trait = get_unsize_trait(db, krate);
|
||||
if let Some(actual_trait) = unsize_trait {
|
||||
if trait_ == actual_trait {
|
||||
get_builtin_unsize_impls(db, krate, ty, arg, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_builtin_unsize_impls(
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
ty: &Ty,
|
||||
// The first argument for the trait, if present
|
||||
arg: &Option<Ty>,
|
||||
mut callback: impl FnMut(Impl),
|
||||
) {
|
||||
if !check_unsize_impl_prerequisites(db, krate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, .. }) = ty {
|
||||
callback(Impl::UnsizeArray);
|
||||
return; // array is unsized, the rest of the impls shouldn't apply
|
||||
}
|
||||
|
||||
if let Some(target_trait) = arg.as_ref().and_then(|t| t.dyn_trait_ref()) {
|
||||
// FIXME what about more complicated dyn tys with marker traits?
|
||||
if let Some(trait_ref) = ty.dyn_trait_ref() {
|
||||
if trait_ref.trait_ != target_trait.trait_ {
|
||||
let super_traits = all_super_traits(db.upcast(), trait_ref.trait_);
|
||||
if super_traits.contains(&target_trait.trait_) {
|
||||
callback(Impl::UnsizeToSuperTraitObject(UnsizeToSuperTraitObjectData {
|
||||
trait_: trait_ref.trait_,
|
||||
super_trait: target_trait.trait_,
|
||||
}));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// FIXME only for sized types
|
||||
callback(Impl::UnsizeToTraitObject(target_trait.trait_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn impl_datum(db: &dyn HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData {
|
||||
match impl_ {
|
||||
Impl::ImplDef(_) => unreachable!(),
|
||||
Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
|
||||
Impl::UnsizeArray => array_unsize_impl_datum(db, krate),
|
||||
Impl::UnsizeToTraitObject(trait_) => trait_object_unsize_impl_datum(db, krate, trait_),
|
||||
Impl::UnsizeToSuperTraitObject(data) => {
|
||||
super_trait_object_unsize_impl_datum(db, krate, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,145 +176,3 @@ fn closure_fn_trait_output_assoc_ty_value(
|
||||
value: output_ty,
|
||||
}
|
||||
}
|
||||
|
||||
// Array unsizing
|
||||
|
||||
fn check_unsize_impl_prerequisites(db: &dyn 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.upcast(), unsize_trait.into());
|
||||
generic_params.len() == 2
|
||||
}
|
||||
|
||||
fn array_unsize_impl_datum(db: &dyn HirDatabase, krate: CrateId) -> BuiltinImplData {
|
||||
// impl<T> 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(BoundVar::new(DebruijnIndex::INNERMOST, 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(),
|
||||
}
|
||||
}
|
||||
|
||||
// Trait object unsizing
|
||||
|
||||
fn trait_object_unsize_impl_datum(
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
trait_: TraitId,
|
||||
) -> BuiltinImplData {
|
||||
// impl<T, T1, ...> Unsize<dyn Trait<T1, ...>> for T where T: Trait<T1, ...>
|
||||
|
||||
let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
|
||||
// the existence of the Unsize trait has been checked before
|
||||
.expect("Unsize trait missing");
|
||||
|
||||
let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
|
||||
|
||||
let target_substs = Substs::build_for_def(db, trait_)
|
||||
.push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
|
||||
.fill_with_bound_vars(DebruijnIndex::ONE, 1)
|
||||
.build();
|
||||
let num_vars = target_substs.len();
|
||||
let target_trait_ref = TraitRef { trait_, substs: target_substs };
|
||||
let target_bounds = vec![GenericPredicate::Implemented(target_trait_ref)];
|
||||
|
||||
let self_substs =
|
||||
Substs::build_for_def(db, trait_).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
|
||||
let self_trait_ref = TraitRef { trait_, substs: self_substs };
|
||||
let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)];
|
||||
|
||||
let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build();
|
||||
|
||||
let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs };
|
||||
|
||||
BuiltinImplData { num_vars, trait_ref, where_clauses, assoc_ty_values: Vec::new() }
|
||||
}
|
||||
|
||||
fn super_trait_object_unsize_impl_datum(
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
data: UnsizeToSuperTraitObjectData,
|
||||
) -> BuiltinImplData {
|
||||
// impl<T1, ...> Unsize<dyn SuperTrait> for dyn Trait<T1, ...>
|
||||
|
||||
let unsize_trait = get_unsize_trait(db, krate) // get unsize trait
|
||||
// the existence of the Unsize trait has been checked before
|
||||
.expect("Unsize trait missing");
|
||||
|
||||
let self_substs = Substs::build_for_def(db, data.trait_)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
|
||||
.build();
|
||||
let self_trait_ref = TraitRef { trait_: data.trait_, substs: self_substs.clone() };
|
||||
|
||||
let num_vars = self_substs.len() - 1;
|
||||
|
||||
// we need to go from our trait to the super trait, substituting type parameters
|
||||
let path = crate::utils::find_super_trait_path(db.upcast(), data.trait_, data.super_trait);
|
||||
|
||||
let mut current_trait_ref = self_trait_ref.clone();
|
||||
for t in path.into_iter().skip(1) {
|
||||
let bounds = db.generic_predicates(current_trait_ref.trait_.into());
|
||||
let super_trait_ref = bounds
|
||||
.iter()
|
||||
.find_map(|b| match &b.value {
|
||||
GenericPredicate::Implemented(tr)
|
||||
if tr.trait_ == t
|
||||
&& tr.substs[0]
|
||||
== Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)) =>
|
||||
{
|
||||
Some(Binders { value: tr, num_binders: b.num_binders })
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.expect("trait bound for known super trait not found");
|
||||
current_trait_ref = super_trait_ref.cloned().subst(¤t_trait_ref.substs);
|
||||
}
|
||||
|
||||
// We need to renumber the variables a bit now: from ^0.0, ^0.1, ^0.2, ...
|
||||
// to ^0.0, ^1.0, ^1.1. The reason for this is that the first variable comes
|
||||
// from the dyn Trait binder, while the other variables come from the impl.
|
||||
let new_substs = Substs::builder(num_vars + 1)
|
||||
.push(Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)))
|
||||
.fill_with_bound_vars(DebruijnIndex::ONE, 0)
|
||||
.build();
|
||||
|
||||
let self_bounds =
|
||||
vec![GenericPredicate::Implemented(self_trait_ref.subst_bound_vars(&new_substs))];
|
||||
let super_bounds =
|
||||
vec![GenericPredicate::Implemented(current_trait_ref.subst_bound_vars(&new_substs))];
|
||||
|
||||
let substs = Substs::builder(2)
|
||||
.push(Ty::Dyn(self_bounds.into()))
|
||||
.push(Ty::Dyn(super_bounds.into()))
|
||||
.build();
|
||||
|
||||
let trait_ref = TraitRef { trait_: unsize_trait, substs };
|
||||
|
||||
BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() }
|
||||
}
|
||||
|
||||
fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
|
||||
let target = db.lang_item(krate, "unsize".into())?;
|
||||
match target {
|
||||
LangItemTarget::TraitId(t) => Some(t),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -271,6 +271,7 @@ fn to_chalk(self, db: &dyn HirDatabase) -> TypeName<Interner> {
|
||||
}
|
||||
TypeCtor::Never => TypeName::Never,
|
||||
|
||||
// FIXME convert these
|
||||
TypeCtor::Adt(_)
|
||||
| TypeCtor::Array
|
||||
| TypeCtor::FnPtr { .. }
|
||||
|
@ -110,38 +110,6 @@ pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) ->
|
||||
result
|
||||
}
|
||||
|
||||
/// Finds a path from a trait to one of its super traits. Returns an empty
|
||||
/// vector if there is no path.
|
||||
pub(super) fn find_super_trait_path(
|
||||
db: &dyn DefDatabase,
|
||||
trait_: TraitId,
|
||||
super_trait: TraitId,
|
||||
) -> Vec<TraitId> {
|
||||
let mut result = Vec::with_capacity(2);
|
||||
result.push(trait_);
|
||||
return if go(db, super_trait, &mut result) { result } else { Vec::new() };
|
||||
|
||||
fn go(db: &dyn DefDatabase, super_trait: TraitId, path: &mut Vec<TraitId>) -> bool {
|
||||
let trait_ = *path.last().unwrap();
|
||||
if trait_ == super_trait {
|
||||
return true;
|
||||
}
|
||||
|
||||
for tt in direct_super_traits(db, trait_) {
|
||||
if path.contains(&tt) {
|
||||
continue;
|
||||
}
|
||||
path.push(tt);
|
||||
if go(db, super_trait, path) {
|
||||
return true;
|
||||
} else {
|
||||
path.pop();
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn associated_type_by_name_including_super_traits(
|
||||
db: &dyn HirDatabase,
|
||||
trait_ref: TraitRef,
|
||||
|
Loading…
Reference in New Issue
Block a user