blob: ad1350d845df6d74dec31e63fba248ca7a56079c [file] [log] [blame]
use std::fmt;
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::inherent::*;
use crate::lift::Lift;
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::Interner;
/// A complete reference to a trait. These take numerous guises in syntax,
/// but perhaps the most recognizable form is in a where-clause:
/// ```ignore (illustrative)
/// T: Foo<U>
/// ```
/// This would be represented by a trait-reference where the `DefId` is the
/// `DefId` for the trait `Foo` and the args define `T` as parameter 0,
/// and `U` as parameter 1.
///
/// Trait references also appear in object types like `Foo<U>`, but in
/// that case the `Self` parameter is absent from the generic parameters.
#[derive(derivative::Derivative)]
#[derivative(
Clone(bound = ""),
Copy(bound = ""),
Hash(bound = ""),
PartialEq(bound = ""),
Eq(bound = "")
)]
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
pub struct TraitRef<I: Interner> {
pub def_id: I::DefId,
pub args: I::GenericArgs,
/// This field exists to prevent the creation of `TraitRef` without
/// calling [`TraitRef::new`].
pub(super) _use_trait_ref_new_instead: (),
}
impl<I: Interner> TraitRef<I> {
pub fn new(
interner: I,
trait_def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> Self {
let args = interner.check_and_mk_args(trait_def_id, args);
Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () }
}
pub fn from_method(interner: I, trait_id: I::DefId, args: I::GenericArgs) -> TraitRef<I> {
let generics = interner.generics_of(trait_id);
TraitRef::new(interner, trait_id, args.into_iter().take(generics.count()))
}
/// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
/// are the parameters defined on trait.
pub fn identity(interner: I, def_id: I::DefId) -> TraitRef<I> {
TraitRef::new(interner, def_id, I::GenericArgs::identity_for_item(interner, def_id))
}
pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
TraitRef::new(
interner,
self.def_id,
[self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
)
}
#[inline]
pub fn self_ty(&self) -> I::Ty {
self.args.type_at(0)
}
}
impl<I: Interner> fmt::Debug for TraitRef<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let TraitRef { def_id, args, _use_trait_ref_new_instead: () } = self;
let mut args = args.into_iter().peekable();
write!(f, "{def_id:?}")?;
if args.peek().is_some() {
write!(f, "<")?;
for (i, arg) in args.enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{arg:#?}")?;
}
write!(f, ">")?;
}
Ok(())
}
}
// FIXME(compiler-errors): Make this into a `Lift_Generic` impl.
impl<I: Interner, U: Interner> Lift<U> for TraitRef<I>
where
I::DefId: Lift<U, Lifted = U::DefId>,
I::GenericArgs: Lift<U, Lifted = U::GenericArgs>,
{
type Lifted = TraitRef<U>;
fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> {
Some(TraitRef {
def_id: self.def_id.lift_to_tcx(tcx)?,
args: self.args.lift_to_tcx(tcx)?,
_use_trait_ref_new_instead: (),
})
}
}
impl<I: Interner> TypeVisitable<I> for TraitRef<I>
where
I::GenericArgs: TypeVisitable<I>,
{
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
self.args.visit_with(visitor)
}
}
impl<I: Interner> TypeFoldable<I> for TraitRef<I>
where
I::GenericArgs: TypeFoldable<I>,
{
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(TraitRef {
def_id: self.def_id,
args: self.args.try_fold_with(folder)?,
_use_trait_ref_new_instead: (),
})
}
}