blob: 21d6f5efa7b51c5f3c60d7ea84a9c5f741967c75 [file] [log] [blame]
use super::{builder::ClauseBuilder, generalize};
use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait};
use chalk_ir::{Floundered, Substitution, Ty};
mod clone;
mod copy;
mod fn_family;
mod sized;
mod unsize;
/// For well known traits we have special hard-coded impls, either as an
/// optimization or to enforce special rules for correctness.
pub fn add_builtin_program_clauses<I: Interner>(
db: &dyn RustIrDatabase<I>,
builder: &mut ClauseBuilder<'_, I>,
well_known: WellKnownTrait,
trait_ref: &TraitRef<I>,
) -> Result<(), Floundered> {
// If `trait_ref` contains bound vars, we want to universally quantify them.
// `Generalize` collects them for us.
let generalized = generalize::Generalize::apply(db.interner(), trait_ref);
builder.push_binders(&generalized, |builder, trait_ref| {
let self_ty = trait_ref.self_type_parameter(db.interner());
let ty = self_ty.data(db.interner());
if let Some(force_impl) = db.force_impl_for(well_known, ty) {
if force_impl {
builder.push_fact(trait_ref.clone());
}
return Ok(());
}
match well_known {
WellKnownTrait::Sized => sized::add_sized_program_clauses(db, builder, &trait_ref, ty),
WellKnownTrait::Copy => copy::add_copy_program_clauses(db, builder, &trait_ref, ty),
WellKnownTrait::Clone => clone::add_clone_program_clauses(db, builder, &trait_ref, ty),
WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn => {
fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)?
}
WellKnownTrait::Unsize => {
unsize::add_unsize_program_clauses(db, builder, &trait_ref, ty)
}
// Drop impls are provided explicitly
WellKnownTrait::Drop => (),
}
Ok(())
})
}
/// Like `add_builtin_program_clauses`, but for `DomainGoal::Normalize` involving
/// a projection (e.g. `<fn(u8) as FnOnce<(u8,)>>::Output`)
pub fn add_builtin_assoc_program_clauses<I: Interner>(
db: &dyn RustIrDatabase<I>,
builder: &mut ClauseBuilder<'_, I>,
well_known: WellKnownTrait,
self_ty: Ty<I>,
) -> Result<(), Floundered> {
match well_known {
WellKnownTrait::FnOnce => {
// If `self_ty` contains bound vars, we want to universally quantify them.
// `Generalize` collects them for us.
let generalized = generalize::Generalize::apply(db.interner(), &self_ty);
builder.push_binders(&generalized, |builder, self_ty| {
fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)?;
Ok(())
})
}
_ => Ok(()),
}
}
/// Given a trait ref `T0: Trait` and a list of types `U0..Un`, pushes a clause of the form
/// `Implemented(T0: Trait) :- Implemented(U0: Trait) .. Implemented(Un: Trait)`
pub fn needs_impl_for_tys<I: Interner>(
db: &dyn RustIrDatabase<I>,
builder: &mut ClauseBuilder<'_, I>,
trait_ref: &TraitRef<I>,
tys: impl Iterator<Item = Ty<I>>,
) {
// The trait must take one parameter (a type)
debug_assert_eq!(
db.trait_datum(trait_ref.trait_id)
.binders
.len(db.interner()),
1,
);
builder.push_clause(
trait_ref.clone(),
tys.map(|ty| TraitRef {
trait_id: trait_ref.trait_id,
substitution: Substitution::from1(db.interner(), ty),
}),
);
}