diff options
Diffstat (limited to 'compiler/rustc_middle/src')
| -rw-r--r-- | compiler/rustc_middle/src/lib.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/macros.rs | 174 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/fold.rs | 242 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/structural_impls.rs | 245 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/visit.rs | 119 |
5 files changed, 27 insertions, 755 deletions
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index ea57f7079f9..e6cd38c0f15 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -48,12 +48,10 @@ #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(control_flow_enum)] -#![feature(associated_type_defaults)] #![feature(trusted_step)] #![feature(try_blocks)] #![feature(try_reserve_kind)] #![feature(nonzero_ops)] -#![feature(unwrap_infallible)] #![feature(decl_macro)] #![feature(drain_filter)] #![feature(intra_doc_pointers)] diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index e096be16677..57d66ac6a03 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -100,35 +100,11 @@ macro_rules! TrivialTypeTraversalImpls { }; ($($ty:ty,)+) => { - $( - impl<I: $crate::ty::Interner> $crate::ty::fold::ir::TypeFoldable<I> for $ty { - fn try_fold_with<F: $crate::ty::fold::ir::FallibleTypeFolder<I>>( - self, - _: &mut F, - ) -> ::std::result::Result<Self, F::Error> { - Ok(self) - } - - #[inline] - fn fold_with<F: $crate::ty::fold::ir::TypeFolder<I>>( - self, - _: &mut F, - ) -> Self { - self - } - } - - impl<I: $crate::ty::Interner> $crate::ty::visit::ir::TypeVisitable<I> for $ty { - #[inline] - fn visit_with<F: $crate::ty::visit::ir::TypeVisitor<I>>( - &self, - _: &mut F) - -> ::std::ops::ControlFlow<F::BreakTy> - { - ::std::ops::ControlFlow::Continue(()) - } + TrivialTypeTraversalImpls! { + for<'tcx> { + $($ty,)+ } - )+ + } }; } @@ -139,145 +115,3 @@ macro_rules! TrivialTypeTraversalAndLiftImpls { CloneLiftImpls! { $($t)* } } } - -#[macro_export] -macro_rules! EnumTypeTraversalImpl { - (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path { - $($variants:tt)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::ty::fold::ir::TypeFoldable<$tcx> for $s - $(where $($wc)*)* - { - fn try_fold_with<V: $crate::ty::fold::ir::FallibleTypeFolder<$tcx>>( - self, - folder: &mut V, - ) -> ::std::result::Result<Self, V::Error> { - EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output()) - } - } - }; - - (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path { - $($variants:tt)* - } $(where $($wc:tt)*)*) => { - impl<$($p),*> $crate::ty::visit::ir::TypeVisitable<$tcx> for $s - $(where $($wc)*)* - { - fn visit_with<V: $crate::ty::visit::ir::TypeVisitor<$tcx>>( - &self, - visitor: &mut V, - ) -> ::std::ops::ControlFlow<V::BreakTy> { - EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) - } - } - }; - - (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => { - Ok(match $this { - $($output)* - }) - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant ( $($variant_arg),* ) => { - $variant ( - $($crate::ty::fold::ir::TypeFoldable::try_fold_with($variant_arg, $folder)?),* - ) - } - $($output)* - ) - ) - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant { $($variant_arg),* } => { - $variant { - $($variant_arg: $crate::ty::fold::ir::TypeFoldable::fold_with( - $variant_arg, $folder - )?),* } - } - $($output)* - ) - ) - }; - - (@FoldVariants($this:expr, $folder:expr) - input( ($variant:path), $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @FoldVariants($this, $folder) - input($($input)*) - output( - $variant => { $variant } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => { - match $this { - $($output)* - } - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant ( $($variant_arg),* ) => { - $($crate::ty::visit::ir::TypeVisitable::visit_with( - $variant_arg, $visitor - )?;)* - ::std::ops::ControlFlow::Continue(()) - } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant { $($variant_arg),* } => { - $($crate::ty::visit::ir::TypeVisitable::visit_with( - $variant_arg, $visitor - )?;)* - ::std::ops::ControlFlow::Continue(()) - } - $($output)* - ) - ) - }; - - (@VisitVariants($this:expr, $visitor:expr) - input( ($variant:path), $($input:tt)*) - output( $($output:tt)*) ) => { - EnumTypeTraversalImpl!( - @VisitVariants($this, $visitor) - input($($input)*) - output( - $variant => { ::std::ops::ControlFlow::Continue(()) } - $($output)* - ) - ) - }; -} diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index f973c91f10d..84bd3de0f14 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,47 +1,3 @@ -//! A folding traversal mechanism for complex data structures that contain type -//! information. -//! -//! This is a modifying traversal. It consumes the data structure, producing a -//! (possibly) modified version of it. Both fallible and infallible versions are -//! available. The name is potentially confusing, because this traversal is more -//! like `Iterator::map` than `Iterator::fold`. -//! -//! This traversal has limited flexibility. Only a small number of "types of -//! interest" within the complex data structures can receive custom -//! modification. These are the ones containing the most important type-related -//! information, such as `Ty`, `Predicate`, `Region`, and `Const`. -//! -//! There are three groups of traits involved in each traversal. -//! - `TypeFoldable`. This is implemented once for many types, including: -//! - Types of interest, for which the methods delegate to the folder. -//! - All other types, including generic containers like `Vec` and `Option`. -//! It defines a "skeleton" of how they should be folded. -//! - `TypeSuperFoldable`. This is implemented only for each type of interest, -//! and defines the folding "skeleton" for these types. -//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each -//! folder. This defines how types of interest are folded. -//! -//! This means each fold is a mixture of (a) generic folding operations, and (b) -//! custom fold operations that are specific to the folder. -//! - The `TypeFoldable` impls handle most of the traversal, and call into -//! `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest. -//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable` -//! impl, because some of the types of interest are recursive and can contain -//! other types of interest. -//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable` -//! impl, because each folder might provide custom handling only for some types -//! of interest, or only for some variants of each type of interest, and then -//! use default traversal for the remaining cases. -//! -//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U: -//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so: -//! ```text -//! s.fold_with(folder) calls -//! - ty.fold_with(folder) calls -//! - folder.fold_ty(ty) may call -//! - ty.super_fold_with(folder) -//! - u.fold_with(folder) -//! ``` use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; @@ -54,201 +10,9 @@ pub trait TypeFolder<'tcx> = ir::TypeFolder<TyCtxt<'tcx>>; pub trait FallibleTypeFolder<'tcx> = ir::FallibleTypeFolder<TyCtxt<'tcx>>; pub mod ir { - use crate::ty::{ir::TypeVisitable, Interner}; - - /// This trait is implemented for every type that can be folded, - /// providing the skeleton of the traversal. - /// - /// To implement this conveniently, use the derive macro located in - /// `rustc_macros`. - pub trait TypeFoldable<I: Interner>: TypeVisitable<I> { - /// The entry point for folding. To fold a value `t` with a folder `f` - /// call: `t.try_fold_with(f)`. - /// - /// For most types, this just traverses the value, calling `try_fold_with` - /// on each field/element. - /// - /// For types of interest (such as `Ty`), the implementation of method - /// calls a folder method specifically for that type (such as - /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable` - /// to `TypeFolder`. - fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error>; - - /// A convenient alternative to `try_fold_with` for use with infallible - /// folders. Do not override this method, to ensure coherence with - /// `try_fold_with`. - fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self { - self.try_fold_with(folder).into_ok() - } - } - - // This trait is implemented for types of interest. - pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> { - /// Provides a default fold for a type of interest. This should only be - /// called within `TypeFolder` methods, when a non-custom traversal is - /// desired for the value of the type of interest passed to that method. - /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call - /// `ty.try_super_fold_with(self)`, but any other folding should be done - /// with `xyz.try_fold_with(self)`. - fn try_super_fold_with<F: FallibleTypeFolder<I>>( - self, - folder: &mut F, - ) -> Result<Self, F::Error>; - - /// A convenient alternative to `try_super_fold_with` for use with - /// infallible folders. Do not override this method, to ensure coherence - /// with `try_super_fold_with`. - fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self { - self.try_super_fold_with(folder).into_ok() - } - } - - /// This trait is implemented for every infallible folding traversal. There is - /// a fold method defined for every type of interest. Each such method has a - /// default that does an "identity" fold. Implementations of these methods - /// often fall back to a `super_fold_with` method if the primary argument - /// doesn't satisfy a particular condition. - /// - /// A blanket implementation of [`FallibleTypeFolder`] will defer to - /// the infallible methods of this trait to ensure that the two APIs - /// are coherent. - pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = !> { - fn tcx(&self) -> I; - - fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T> - where - T: TypeFoldable<I>, - I::Binder<T>: TypeSuperFoldable<I>, - { - t.super_fold_with(self) - } - - fn fold_ty(&mut self, t: I::Ty) -> I::Ty - where - I::Ty: TypeSuperFoldable<I>, - { - t.super_fold_with(self) - } - - fn fold_region(&mut self, r: I::Region) -> I::Region - where - I::Region: TypeSuperFoldable<I>, - { - r.super_fold_with(self) - } - - fn fold_const(&mut self, c: I::Const) -> I::Const - where - I::Const: TypeSuperFoldable<I>, - { - c.super_fold_with(self) - } - - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate - where - I::Predicate: TypeSuperFoldable<I>, - { - p.super_fold_with(self) - } - } - - /// This trait is implemented for every folding traversal. There is a fold - /// method defined for every type of interest. Each such method has a default - /// that does an "identity" fold. - /// - /// A blanket implementation of this trait (that defers to the relevant - /// method of [`TypeFolder`]) is provided for all infallible folders in - /// order to ensure the two APIs are coherent. - pub trait FallibleTypeFolder<I: Interner>: Sized { - type Error; - - fn tcx<'a>(&'a self) -> I; - - fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Self::Error> - where - T: TypeFoldable<I>, - I::Binder<T>: TypeSuperFoldable<I>, - { - t.try_super_fold_with(self) - } - - fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error> - where - I::Ty: TypeSuperFoldable<I>, - { - t.try_super_fold_with(self) - } - - fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> - where - I::Region: TypeSuperFoldable<I>, - { - r.try_super_fold_with(self) - } - - fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error> - where - I::Const: TypeSuperFoldable<I>, - { - c.try_super_fold_with(self) - } - - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> - where - I::Predicate: TypeSuperFoldable<I>, - { - p.try_super_fold_with(self) - } - } - - // This blanket implementation of the fallible trait for infallible folders - // delegates to infallible methods to ensure coherence. - impl<I: Interner, F> FallibleTypeFolder<I> for F - where - F: TypeFolder<I>, - { - type Error = !; - - fn tcx<'a>(&'a self) -> I { - TypeFolder::tcx(self) - } - - fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, !> - where - T: TypeFoldable<I>, - I::Binder<T>: TypeSuperFoldable<I>, - { - Ok(self.fold_binder(t)) - } - - fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, !> - where - I::Ty: TypeSuperFoldable<I>, - { - Ok(self.fold_ty(t)) - } - - fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !> - where - I::Region: TypeSuperFoldable<I>, - { - Ok(self.fold_region(r)) - } - - fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, !> - where - I::Const: TypeSuperFoldable<I>, - { - Ok(self.fold_const(c)) - } - - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, !> - where - I::Predicate: TypeSuperFoldable<I>, - { - Ok(self.fold_predicate(p)) - } - } + pub use rustc_type_ir::fold::{ + FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, + }; } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 351753911e5..cb5f40170ff 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -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) diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 714d28e3806..8a93b59900e 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -1,43 +1,3 @@ -//! A visiting traversal mechanism for complex data structures that contain type -//! information. -//! -//! This is a read-only traversal of the data structure. -//! -//! This traversal has limited flexibility. Only a small number of "types of -//! interest" within the complex data structures can receive custom -//! visitation. These are the ones containing the most important type-related -//! information, such as `Ty`, `Predicate`, `Region`, and `Const`. -//! -//! There are three groups of traits involved in each traversal. -//! - `TypeVisitable`. This is implemented once for many types, including: -//! - Types of interest, for which the methods delegate to the visitor. -//! - All other types, including generic containers like `Vec` and `Option`. -//! It defines a "skeleton" of how they should be visited. -//! - `TypeSuperVisitable`. This is implemented only for each type of interest, -//! and defines the visiting "skeleton" for these types. -//! - `TypeVisitor`. This is implemented for each visitor. This defines how -//! types of interest are visited. -//! -//! This means each visit is a mixture of (a) generic visiting operations, and (b) -//! custom visit operations that are specific to the visitor. -//! - The `TypeVisitable` impls handle most of the traversal, and call into -//! `TypeVisitor` when they encounter a type of interest. -//! - A `TypeVisitor` may call into another `TypeVisitable` impl, because some of -//! the types of interest are recursive and can contain other types of interest. -//! - A `TypeVisitor` may also call into a `TypeSuperVisitable` impl, because each -//! visitor might provide custom handling only for some types of interest, or -//! only for some variants of each type of interest, and then use default -//! traversal for the remaining cases. -//! -//! For example, if you have `struct S(Ty, U)` where `S: TypeVisitable` and `U: -//! TypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so: -//! ```text -//! s.visit_with(visitor) calls -//! - ty.visit_with(visitor) calls -//! - visitor.visit_ty(ty) may call -//! - ty.super_visit_with(visitor) -//! - u.visit_with(visitor) -//! ``` use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags}; use rustc_errors::ErrorGuaranteed; @@ -50,84 +10,7 @@ pub trait TypeSuperVisitable<'tcx> = ir::TypeSuperVisitable<TyCtxt<'tcx>>; pub trait TypeVisitor<'tcx> = ir::TypeVisitor<TyCtxt<'tcx>>; pub mod ir { - use crate::ty::Interner; - - use std::fmt; - use std::ops::ControlFlow; - - /// This trait is implemented for every type that can be visited, - /// providing the skeleton of the traversal. - /// - /// To implement this conveniently, use the derive macro located in - /// `rustc_macros`. - pub trait TypeVisitable<I: Interner>: fmt::Debug + Clone { - /// The entry point for visiting. To visit a value `t` with a visitor `v` - /// call: `t.visit_with(v)`. - /// - /// For most types, this just traverses the value, calling `visit_with` on - /// each field/element. - /// - /// For types of interest (such as `Ty`), the implementation of this method - /// that calls a visitor method specifically for that type (such as - /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to - /// `TypeVisitor`. - fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; - } - - pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> { - /// Provides a default visit for a type of interest. This should only be - /// called within `TypeVisitor` methods, when a non-custom traversal is - /// desired for the value of the type of interest passed to that method. - /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call - /// `ty.super_visit_with(self)`, but any other visiting should be done - /// with `xyz.visit_with(self)`. - fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; - } - - /// This trait is implemented for every visiting traversal. There is a visit - /// method defined for every type of interest. Each such method has a default - /// that recurses into the type's fields in a non-custom fashion. - pub trait TypeVisitor<I: Interner>: Sized { - type BreakTy = !; - - fn visit_binder<T: TypeVisitable<I>>( - &mut self, - t: &I::Binder<T>, - ) -> ControlFlow<Self::BreakTy> - where - I::Binder<T>: TypeSuperVisitable<I>, - { - t.super_visit_with(self) - } - - fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> - where - I::Ty: TypeSuperVisitable<I>, - { - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> - where - I::Region: TypeSuperVisitable<I>, - { - r.super_visit_with(self) - } - - fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> - where - I::Const: TypeSuperVisitable<I>, - { - c.super_visit_with(self) - } - - fn visit_predicate(&mut self, p: I::Predicate) -> ControlFlow<Self::BreakTy> - where - I::Predicate: TypeSuperVisitable<I>, - { - p.super_visit_with(self) - } - } + pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; } pub trait TypeVisitableExt<'tcx>: ir::TypeVisitable<TyCtxt<'tcx>> { |
