1
Fork 0

Move folding and visiting traits into type library

This commit is contained in:
Alan Egerton 2023-02-10 16:14:18 +00:00
parent 9fa6bb2aa0
commit 459e142413
No known key found for this signature in database
GPG key ID: 7D4C2F6C22122532
10 changed files with 805 additions and 755 deletions

View file

@ -1,20 +1,19 @@
//! This module contains implements of the `Lift` and `TypeFoldable`
//! traits for various types in the Rust compiler. Most are written by
//! hand, though we've recently added some macros and proc-macros to help with the tedium.
//! This module contains implementations of the `Lift`, `TypeFoldable` and
//! `TypeVisitable` traits for various types in the Rust compiler. Most are
//! written by hand, though we've recently added some macros and proc-macros
//! to help with the tedium.
use crate::mir::interpret;
use crate::mir::{Field, ProjectionKind};
use crate::ty::fold::{ir::TypeSuperFoldable, FallibleTypeFolder, TypeFoldable};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::visit::{ir::TypeSuperVisitable, TypeVisitable, TypeVisitor};
use crate::ty::{self, ir, AliasTy, InferConst, Interner, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_data_structures::functor::IdFunctor;
use crate::ty::{self, ir, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_hir::def::Namespace;
use rustc_index::vec::{Idx, IndexVec};
use rustc_target::abi::TyAndLayout;
use std::fmt;
use std::mem::ManuallyDrop;
use std::ops::ControlFlow;
use std::rc::Rc;
use std::sync::Arc;
@ -195,17 +194,27 @@ impl<'tcx> fmt::Debug for AliasTy<'tcx> {
// Atomic structs
//
// For things that don't carry any arena-allocated data (and are
// copy...), just add them to this list.
// copy...), just add them to one of these lists as appropriat.
TrivialTypeTraversalAndLiftImpls! {
// For things for which the type library provides traversal implementations
// for all Interners, we only need to provide a Lift implementation:
CloneLiftImpls! {
(),
bool,
usize,
::rustc_target::abi::VariantIdx,
u16,
u32,
u64,
String,
rustc_type_ir::DebruijnIndex,
}
// For things about which the type library does not know, or does not
// provide any traversal implementations, we need to provide both a Lift
// implementation and traversal implementations (the latter only for
// TyCtxt<'_> interners).
TrivialTypeTraversalAndLiftImpls! {
::rustc_target::abi::VariantIdx,
crate::middle::region::Scope,
crate::ty::FloatTy,
::rustc_ast::InlineAsmOptions,
@ -257,7 +266,6 @@ TrivialTypeTraversalAndLiftImpls! {
Field,
interpret::Scalar,
rustc_target::abi::Size,
rustc_type_ir::DebruijnIndex,
ty::BoundVar,
ty::Placeholder<ty::BoundVar>,
}
@ -360,7 +368,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
}
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
// Traversal implementations.
/// AdtDefs are basically the same as a DefId.
impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> {
@ -375,209 +383,6 @@ impl<'tcx> ir::TypeVisitable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> {
}
}
impl<I: Interner, T: ir::TypeFoldable<I>, U: ir::TypeFoldable<I>> ir::TypeFoldable<I> for (T, U) {
fn try_fold_with<F: ir::FallibleTypeFolder<I>>(
self,
folder: &mut F,
) -> Result<(T, U), F::Error> {
Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
}
}
impl<I: Interner, T: ir::TypeVisitable<I>, U: ir::TypeVisitable<I>> ir::TypeVisitable<I>
for (T, U)
{
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.0.visit_with(visitor)?;
self.1.visit_with(visitor)
}
}
impl<I: Interner, A: ir::TypeFoldable<I>, B: ir::TypeFoldable<I>, C: ir::TypeFoldable<I>>
ir::TypeFoldable<I> for (A, B, C)
{
fn try_fold_with<F: ir::FallibleTypeFolder<I>>(
self,
folder: &mut F,
) -> Result<(A, B, C), F::Error> {
Ok((
self.0.try_fold_with(folder)?,
self.1.try_fold_with(folder)?,
self.2.try_fold_with(folder)?,
))
}
}
impl<I: Interner, A: ir::TypeVisitable<I>, B: ir::TypeVisitable<I>, C: ir::TypeVisitable<I>>
ir::TypeVisitable<I> for (A, B, C)
{
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.0.visit_with(visitor)?;
self.1.visit_with(visitor)?;
self.2.visit_with(visitor)
}
}
EnumTypeTraversalImpl! {
impl<I, T> TypeFoldable<I> for Option<T> {
(Some)(a),
(None),
} where I: Interner, T: ir::TypeFoldable<I>
}
EnumTypeTraversalImpl! {
impl<I, T> TypeVisitable<I> for Option<T> {
(Some)(a),
(None),
} where I: Interner, T: ir::TypeVisitable<I>
}
EnumTypeTraversalImpl! {
impl<I, T, E> TypeFoldable<I> for Result<T, E> {
(Ok)(a),
(Err)(a),
} where I: Interner, T: ir::TypeFoldable<I>, E: ir::TypeFoldable<I>,
}
EnumTypeTraversalImpl! {
impl<I, T, E> TypeVisitable<I> for Result<T, E> {
(Ok)(a),
(Err)(a),
} where I: Interner, T: ir::TypeVisitable<I>, E: ir::TypeVisitable<I>,
}
impl<I: Interner, T: ir::TypeFoldable<I>> ir::TypeFoldable<I> for Rc<T> {
fn try_fold_with<F: ir::FallibleTypeFolder<I>>(
mut self,
folder: &mut F,
) -> Result<Self, F::Error> {
// We merely want to replace the contained `T`, if at all possible,
// so that we don't needlessly allocate a new `Rc` or indeed clone
// the contained type.
unsafe {
// First step is to ensure that we have a unique reference to
// the contained type, which `Rc::make_mut` will accomplish (by
// allocating a new `Rc` and cloning the `T` only if required).
// This is done *before* casting to `Rc<ManuallyDrop<T>>` so that
// panicking during `make_mut` does not leak the `T`.
Rc::make_mut(&mut self);
// Casting to `Rc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
// is `repr(transparent)`.
let ptr = Rc::into_raw(self).cast::<ManuallyDrop<T>>();
let mut unique = Rc::from_raw(ptr);
// Call to `Rc::make_mut` above guarantees that `unique` is the
// sole reference to the contained value, so we can avoid doing
// a checked `get_mut` here.
let slot = Rc::get_mut_unchecked(&mut unique);
// Semantically move the contained type out from `unique`, fold
// it, then move the folded value back into `unique`. Should
// folding fail, `ManuallyDrop` ensures that the "moved-out"
// value is not re-dropped.
let owned = ManuallyDrop::take(slot);
let folded = owned.try_fold_with(folder)?;
*slot = ManuallyDrop::new(folded);
// Cast back to `Rc<T>`.
Ok(Rc::from_raw(Rc::into_raw(unique).cast()))
}
}
}
impl<I: Interner, T: ir::TypeVisitable<I>> ir::TypeVisitable<I> for Rc<T> {
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
(**self).visit_with(visitor)
}
}
impl<I: Interner, T: ir::TypeFoldable<I>> ir::TypeFoldable<I> for Arc<T> {
fn try_fold_with<F: ir::FallibleTypeFolder<I>>(
mut self,
folder: &mut F,
) -> Result<Self, F::Error> {
// We merely want to replace the contained `T`, if at all possible,
// so that we don't needlessly allocate a new `Arc` or indeed clone
// the contained type.
unsafe {
// First step is to ensure that we have a unique reference to
// the contained type, which `Arc::make_mut` will accomplish (by
// allocating a new `Arc` and cloning the `T` only if required).
// This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
// panicking during `make_mut` does not leak the `T`.
Arc::make_mut(&mut self);
// Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
// is `repr(transparent)`.
let ptr = Arc::into_raw(self).cast::<ManuallyDrop<T>>();
let mut unique = Arc::from_raw(ptr);
// Call to `Arc::make_mut` above guarantees that `unique` is the
// sole reference to the contained value, so we can avoid doing
// a checked `get_mut` here.
let slot = Arc::get_mut_unchecked(&mut unique);
// Semantically move the contained type out from `unique`, fold
// it, then move the folded value back into `unique`. Should
// folding fail, `ManuallyDrop` ensures that the "moved-out"
// value is not re-dropped.
let owned = ManuallyDrop::take(slot);
let folded = owned.try_fold_with(folder)?;
*slot = ManuallyDrop::new(folded);
// Cast back to `Arc<T>`.
Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
}
}
}
impl<I: Interner, T: ir::TypeVisitable<I>> ir::TypeVisitable<I> for Arc<T> {
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
(**self).visit_with(visitor)
}
}
impl<I: Interner, T: ir::TypeFoldable<I>> ir::TypeFoldable<I> for Box<T> {
fn try_fold_with<F: ir::FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|value| value.try_fold_with(folder))
}
}
impl<I: Interner, T: ir::TypeVisitable<I>> ir::TypeVisitable<I> for Box<T> {
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
(**self).visit_with(visitor)
}
}
impl<I: Interner, T: ir::TypeFoldable<I>> ir::TypeFoldable<I> for Vec<T> {
fn try_fold_with<F: ir::FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|t| t.try_fold_with(folder))
}
}
impl<I: Interner, T: ir::TypeVisitable<I>> ir::TypeVisitable<I> for Vec<T> {
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.iter().try_for_each(|t| t.visit_with(visitor))
}
}
impl<I: Interner, T: ir::TypeVisitable<I>> ir::TypeVisitable<I> for &[T] {
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.iter().try_for_each(|t| t.visit_with(visitor))
}
}
impl<I: Interner, T: ir::TypeFoldable<I>> ir::TypeFoldable<I> for Box<[T]> {
fn try_fold_with<F: ir::FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|t| t.try_fold_with(folder))
}
}
impl<I: Interner, T: ir::TypeVisitable<I>> ir::TypeVisitable<I> for Box<[T]> {
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.iter().try_for_each(|t| t.visit_with(visitor))
}
}
impl<'tcx, T: TypeFoldable<'tcx>> ir::TypeFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.try_fold_binder(self)
@ -790,18 +595,6 @@ impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Predicate<'tcx>
}
}
impl<I: Interner, T: ir::TypeFoldable<I>, Ix: Idx> ir::TypeFoldable<I> for IndexVec<Ix, T> {
fn try_fold_with<F: ir::FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|x| x.try_fold_with(folder))
}
}
impl<I: Interner, T: ir::TypeVisitable<I>, Ix: Idx> ir::TypeVisitable<I> for IndexVec<Ix, T> {
fn visit_with<V: ir::TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.iter().try_for_each(|t| t.visit_with(visitor))
}
}
impl<'tcx> ir::TypeFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.try_fold_const(self)