summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_type_ir
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_type_ir')
-rw-r--r--compiler/rustc_type_ir/src/fold.rs239
-rw-r--r--compiler/rustc_type_ir/src/lib.rs142
-rw-r--r--compiler/rustc_type_ir/src/macros.rs176
-rw-r--r--compiler/rustc_type_ir/src/structural_impls.rs175
-rw-r--r--compiler/rustc_type_ir/src/sty.rs156
-rw-r--r--compiler/rustc_type_ir/src/visit.rs115
6 files changed, 892 insertions, 111 deletions
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
new file mode 100644
index 000000000..ee4ef57c3
--- /dev/null
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -0,0 +1,239 @@
+//! 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::{visit::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 interner(&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 interner(&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 interner(&self) -> I {
+ TypeFolder::interner(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))
+ }
+}
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 44004cb0b..5a991e03d 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -1,6 +1,9 @@
+#![feature(associated_type_defaults)]
#![feature(fmt_helpers_for_derive)]
#![feature(min_specialization)]
+#![feature(never_type)]
#![feature(rustc_attrs)]
+#![feature(unwrap_infallible)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
@@ -18,8 +21,14 @@ use std::hash::Hash;
use std::mem::discriminant;
pub mod codec;
+pub mod fold;
pub mod sty;
pub mod ty_info;
+pub mod visit;
+
+#[macro_use]
+mod macros;
+mod structural_impls;
pub use codec::*;
pub use sty::*;
@@ -28,68 +37,69 @@ pub use ty_info::*;
/// Needed so we can use #[derive(HashStable_Generic)]
pub trait HashStableContext {}
-pub trait Interner {
- type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type DefId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type Ty: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type Const: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type Region: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type TypeAndMut: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type Mutability: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type Movability: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type PolyFnSig: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type ListBinderExistentialPredicate: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type BinderListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type ListTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type AliasTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type ParamTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type BoundTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type PlaceholderType: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type InferTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type ErrorGuaranteed: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+pub trait Interner: Sized {
+ type AdtDef: Clone + Debug + Hash + Ord;
+ type SubstsRef: Clone + Debug + Hash + Ord;
+ type DefId: Clone + Debug + Hash + Ord;
+ type Binder<T>;
+ type Ty: Clone + Debug + Hash + Ord;
+ type Const: Clone + Debug + Hash + Ord;
+ type Region: Clone + Debug + Hash + Ord;
+ type Predicate;
+ type TypeAndMut: Clone + Debug + Hash + Ord;
+ type Mutability: Clone + Debug + Hash + Ord;
+ type Movability: Clone + Debug + Hash + Ord;
+ type PolyFnSig: Clone + Debug + Hash + Ord;
+ type ListBinderExistentialPredicate: Clone + Debug + Hash + Ord;
+ type BinderListTy: Clone + Debug + Hash + Ord;
+ type ListTy: Clone + Debug + Hash + Ord;
+ type AliasTy: Clone + Debug + Hash + Ord;
+ type ParamTy: Clone + Debug + Hash + Ord;
+ type BoundTy: Clone + Debug + Hash + Ord;
+ type PlaceholderType: Clone + Debug + Hash + Ord;
+ type InferTy: Clone + Debug + Hash + Ord;
+ type ErrorGuaranteed: Clone + Debug + Hash + Ord;
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
- type AllocId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+ type AllocId: Clone + Debug + Hash + Ord;
- type EarlyBoundRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type BoundRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type FreeRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type RegionVid: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type PlaceholderRegion: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+ type EarlyBoundRegion: Clone + Debug + Hash + Ord;
+ type BoundRegion: Clone + Debug + Hash + Ord;
+ type FreeRegion: Clone + Debug + Hash + Ord;
+ type RegionVid: Clone + Debug + Hash + Ord;
+ type PlaceholderRegion: Clone + Debug + Hash + Ord;
}
-pub trait InternAs<T: ?Sized, R> {
+/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
+/// that produces `T` items. You could combine them with
+/// `f(&iter.collect::<Vec<_>>())`, but this requires allocating memory for the
+/// `Vec`.
+///
+/// This trait allows for faster implementations, intended for cases where the
+/// number of items produced by the iterator is small. There is a blanket impl
+/// for `T` items, but there is also a fallible impl for `Result<T, E>` items.
+pub trait CollectAndApply<T, R>: Sized {
type Output;
- fn intern_with<F>(self, f: F) -> Self::Output
+
+ /// Produce a result of type `Self::Output` from `iter`. The result will
+ /// typically be produced by applying `f` on the elements produced by
+ /// `iter`, though this may not happen in some impls, e.g. if an error
+ /// occured during iteration.
+ fn collect_and_apply<I, F>(iter: I, f: F) -> Self::Output
where
+ I: Iterator<Item = Self>,
F: FnOnce(&[T]) -> R;
}
-impl<I, T, R, E> InternAs<T, R> for I
-where
- E: InternIteratorElement<T, R>,
- I: Iterator<Item = E>,
-{
- type Output = E::Output;
- fn intern_with<F>(self, f: F) -> Self::Output
+/// The blanket impl that always collects all elements and applies `f`.
+impl<T, R> CollectAndApply<T, R> for T {
+ type Output = R;
+
+ /// Equivalent to `f(&iter.collect::<Vec<_>>())`.
+ fn collect_and_apply<I, F>(mut iter: I, f: F) -> R
where
+ I: Iterator<Item = T>,
F: FnOnce(&[T]) -> R,
{
- E::intern_with(self, f)
- }
-}
-
-pub trait InternIteratorElement<T, R>: Sized {
- type Output;
- fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output;
-}
-
-impl<T, R> InternIteratorElement<T, R> for T {
- type Output = R;
- fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
- mut iter: I,
- f: F,
- ) -> Self::Output {
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
@@ -116,23 +126,17 @@ impl<T, R> InternIteratorElement<T, R> for T {
}
}
-impl<'a, T, R> InternIteratorElement<T, R> for &'a T
-where
- T: Clone + 'a,
-{
- type Output = R;
- fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
- // This code isn't hot.
- f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
- }
-}
-
-impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
+/// A fallible impl that will fail, without calling `f`, if there are any
+/// errors during collection.
+impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
type Output = Result<R, E>;
- fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
- mut iter: I,
- f: F,
- ) -> Self::Output {
+
+ /// Equivalent to `Ok(f(&iter.collect::<Result<Vec<_>>>()?))`.
+ fn collect_and_apply<I, F>(mut iter: I, f: F) -> Result<R, E>
+ where
+ I: Iterator<Item = Result<T, E>>,
+ F: FnOnce(&[T]) -> R,
+ {
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
@@ -220,7 +224,8 @@ bitflags! {
// which is different from how types/const are freshened.
| TypeFlags::HAS_TY_FRESH.bits
| TypeFlags::HAS_CT_FRESH.bits
- | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
+ | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits
+ | TypeFlags::HAS_RE_ERASED.bits;
/// Does this have `Projection`?
const HAS_TY_PROJECTION = 1 << 10;
@@ -265,6 +270,9 @@ bitflags! {
/// Does this value have `InferConst::Fresh`?
const HAS_CT_FRESH = 1 << 21;
+
+ /// Does this have `Generator` or `GeneratorWitness`?
+ const HAS_TY_GENERATOR = 1 << 22;
}
}
diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs
new file mode 100644
index 000000000..6c1810397
--- /dev/null
+++ b/compiler/rustc_type_ir/src/macros.rs
@@ -0,0 +1,176 @@
+/// Used for types that are `Copy` and which **do not care arena
+/// allocated data** (i.e., don't need to be folded).
+macro_rules! TrivialTypeTraversalImpls {
+ ($($ty:ty,)+) => {
+ $(
+ impl<I: $crate::Interner> $crate::fold::TypeFoldable<I> for $ty {
+ fn try_fold_with<F: $crate::fold::FallibleTypeFolder<I>>(
+ self,
+ _: &mut F,
+ ) -> ::std::result::Result<Self, F::Error> {
+ Ok(self)
+ }
+
+ #[inline]
+ fn fold_with<F: $crate::fold::TypeFolder<I>>(
+ self,
+ _: &mut F,
+ ) -> Self {
+ self
+ }
+ }
+
+ impl<I: $crate::Interner> $crate::visit::TypeVisitable<I> for $ty {
+ #[inline]
+ fn visit_with<F: $crate::visit::TypeVisitor<I>>(
+ &self,
+ _: &mut F)
+ -> ::std::ops::ControlFlow<F::BreakTy>
+ {
+ ::std::ops::ControlFlow::Continue(())
+ }
+ }
+ )+
+ };
+}
+
+macro_rules! EnumTypeTraversalImpl {
+ (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
+ $($variants:tt)*
+ } $(where $($wc:tt)*)*) => {
+ impl<$($p),*> $crate::fold::TypeFoldable<$tcx> for $s
+ $(where $($wc)*)*
+ {
+ fn try_fold_with<V: $crate::fold::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::visit::TypeVisitable<$tcx> for $s
+ $(where $($wc)*)*
+ {
+ fn visit_with<V: $crate::visit::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::fold::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::fold::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::visit::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::visit::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_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs
new file mode 100644
index 000000000..3ebe24104
--- /dev/null
+++ b/compiler/rustc_type_ir/src/structural_impls.rs
@@ -0,0 +1,175 @@
+//! This module contains implementations of the `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::fold::{FallibleTypeFolder, TypeFoldable};
+use crate::visit::{TypeVisitable, TypeVisitor};
+use crate::Interner;
+use rustc_data_structures::functor::IdFunctor;
+use rustc_index::vec::{Idx, IndexVec};
+
+use std::ops::ControlFlow;
+use std::rc::Rc;
+use std::sync::Arc;
+
+///////////////////////////////////////////////////////////////////////////
+// Atomic structs
+//
+// For things that don't carry any arena-allocated data (and are
+// copy...), just add them to this list.
+
+TrivialTypeTraversalImpls! {
+ (),
+ bool,
+ usize,
+ u16,
+ u32,
+ u64,
+ String,
+ crate::DebruijnIndex,
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Traversal implementations.
+
+impl<I: Interner, T: TypeFoldable<I>, U: TypeFoldable<I>> TypeFoldable<I> for (T, U) {
+ fn try_fold_with<F: 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: TypeVisitable<I>, U: TypeVisitable<I>> TypeVisitable<I> for (T, U) {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.0.visit_with(visitor)?;
+ self.1.visit_with(visitor)
+ }
+}
+
+impl<I: Interner, A: TypeFoldable<I>, B: TypeFoldable<I>, C: TypeFoldable<I>> TypeFoldable<I>
+ for (A, B, C)
+{
+ fn try_fold_with<F: 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: TypeVisitable<I>, B: TypeVisitable<I>, C: TypeVisitable<I>> TypeVisitable<I>
+ for (A, B, C)
+{
+ fn visit_with<V: 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: TypeFoldable<I>
+}
+EnumTypeTraversalImpl! {
+ impl<I, T> TypeVisitable<I> for Option<T> {
+ (Some)(a),
+ (None),
+ } where I: Interner, T: TypeVisitable<I>
+}
+
+EnumTypeTraversalImpl! {
+ impl<I, T, E> TypeFoldable<I> for Result<T, E> {
+ (Ok)(a),
+ (Err)(a),
+ } where I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>,
+}
+EnumTypeTraversalImpl! {
+ impl<I, T, E> TypeVisitable<I> for Result<T, E> {
+ (Ok)(a),
+ (Err)(a),
+ } where I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>,
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Rc<T> {
+ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|value| value.try_fold_with(folder))
+ }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Rc<T> {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ (**self).visit_with(visitor)
+ }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Arc<T> {
+ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|value| value.try_fold_with(folder))
+ }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Arc<T> {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ (**self).visit_with(visitor)
+ }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<T> {
+ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|value| value.try_fold_with(folder))
+ }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ (**self).visit_with(visitor)
+ }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
+ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.try_fold_with(folder))
+ }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> {
+ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.try_fold_with(folder))
+ }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
+
+impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> {
+ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|x| x.try_fold_with(folder))
+ }
+}
+
+impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix, T> {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ self.iter().try_for_each(|t| t.visit_with(visitor))
+ }
+}
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 5f29588ae..ebe2b76ae 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -26,11 +26,9 @@ pub enum DynKind {
Dyn,
/// A sized `dyn* Trait` object
///
- /// These objects are represented as a `(data, vtable)` pair where `data` is a ptr-sized value
- /// (often a pointer to the real object, but not necessarily) and `vtable` is a pointer to
- /// the vtable for `dyn* Trait`. The representation is essentially the same as `&dyn Trait`
- /// or similar, but the drop function included in the vtable is responsible for freeing the
- /// underlying storage if needed. This allows a `dyn*` object to be treated agnostically with
+ /// These objects are represented as a `(data, vtable)` pair where `data` is a value of some
+ /// ptr-sized and ptr-aligned dynamically determined type `T` and `vtable` is a pointer to the
+ /// vtable of `impl T for Trait`. This allows a `dyn*` object to be treated agnostically with
/// respect to whether it points to a `Box<T>`, `Rc<T>`, etc.
DynStar,
}
@@ -160,6 +158,32 @@ pub enum TyKind<I: Interner> {
/// ```
GeneratorWitness(I::BinderListTy),
+ /// A type representing the types stored inside a generator.
+ /// This should only appear as part of the `GeneratorSubsts`.
+ ///
+ /// Unlike upvars, the witness can reference lifetimes from
+ /// inside of the generator itself. To deal with them in
+ /// the type of the generator, we convert them to higher ranked
+ /// lifetimes bound by the witness itself.
+ ///
+ /// This variant is only using when `drop_tracking_mir` is set.
+ /// This contains the `DefId` and the `SubstRef` of the generator.
+ /// The actual witness types are computed on MIR by the `mir_generator_witnesses` query.
+ ///
+ /// Looking at the following example, the witness for this generator
+ /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
+ ///
+ /// ```ignore UNSOLVED (ask @compiler-errors, should this error? can we just swap the yields?)
+ /// #![feature(generators)]
+ /// |a| {
+ /// let x = &vec![3];
+ /// yield a;
+ /// yield x[0];
+ /// }
+ /// # ;
+ /// ```
+ GeneratorWitnessMIR(I::DefId, I::SubstsRef),
+
/// The never type `!`.
Never,
@@ -241,6 +265,7 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
Placeholder(_) => 23,
Infer(_) => 24,
Error(_) => 25,
+ GeneratorWitnessMIR(_, _) => 26,
}
}
@@ -266,6 +291,7 @@ impl<I: Interner> Clone for TyKind<I> {
Closure(d, s) => Closure(d.clone(), s.clone()),
Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()),
GeneratorWitness(g) => GeneratorWitness(g.clone()),
+ GeneratorWitnessMIR(d, s) => GeneratorWitnessMIR(d.clone(), s.clone()),
Never => Never,
Tuple(t) => Tuple(t.clone()),
Alias(k, p) => Alias(*k, p.clone()),
@@ -282,43 +308,51 @@ impl<I: Interner> Clone for TyKind<I> {
impl<I: Interner> PartialEq for TyKind<I> {
#[inline]
fn eq(&self, other: &TyKind<I>) -> bool {
- tykind_discriminant(self) == tykind_discriminant(other)
- && match (self, other) {
- (Int(a_i), Int(b_i)) => a_i == b_i,
- (Uint(a_u), Uint(b_u)) => a_u == b_u,
- (Float(a_f), Float(b_f)) => a_f == b_f,
- (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
- (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
- (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
- (Slice(a_t), Slice(b_t)) => a_t == b_t,
- (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t,
- (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
- (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
- (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
- (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
- a_p == b_p && a_r == b_r && a_repr == b_repr
- }
- (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
- (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
- a_d == b_d && a_s == b_s && a_m == b_m
- }
- (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
- (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
- (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
- (Param(a_p), Param(b_p)) => a_p == b_p,
- (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
- (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
- (Infer(a_t), Infer(b_t)) => a_t == b_t,
- (Error(a_e), Error(b_e)) => a_e == b_e,
- (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
- _ => {
- debug_assert!(
- false,
- "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
- );
- true
- }
+ // You might expect this `match` to be preceded with this:
+ //
+ // tykind_discriminant(self) == tykind_discriminant(other) &&
+ //
+ // but the data patterns in practice are such that a comparison
+ // succeeds 99%+ of the time, and it's faster to omit it.
+ match (self, other) {
+ (Int(a_i), Int(b_i)) => a_i == b_i,
+ (Uint(a_u), Uint(b_u)) => a_u == b_u,
+ (Float(a_f), Float(b_f)) => a_f == b_f,
+ (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
+ (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
+ (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
+ (Slice(a_t), Slice(b_t)) => a_t == b_t,
+ (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t,
+ (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
+ (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
+ (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
+ (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
+ a_p == b_p && a_r == b_r && a_repr == b_repr
+ }
+ (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
+ (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
+ a_d == b_d && a_s == b_s && a_m == b_m
+ }
+ (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
+ (GeneratorWitnessMIR(a_d, a_s), GeneratorWitnessMIR(b_d, b_s)) => {
+ a_d == b_d && a_s == b_s
}
+ (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
+ (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
+ (Param(a_p), Param(b_p)) => a_p == b_p,
+ (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
+ (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
+ (Infer(a_t), Infer(b_t)) => a_t == b_t,
+ (Error(a_e), Error(b_e)) => a_e == b_e,
+ (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
+ _ => {
+ debug_assert!(
+ tykind_discriminant(self) != tykind_discriminant(other),
+ "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
+ );
+ false
+ }
+ }
}
}
@@ -360,6 +394,13 @@ impl<I: Interner> Ord for TyKind<I> {
a_d.cmp(b_d).then_with(|| a_s.cmp(b_s).then_with(|| a_m.cmp(b_m)))
}
(GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g),
+ (
+ GeneratorWitnessMIR(a_d, a_s),
+ GeneratorWitnessMIR(b_d, b_s),
+ ) => match Ord::cmp(a_d, b_d) {
+ Ordering::Equal => Ord::cmp(a_s, b_s),
+ cmp => cmp,
+ },
(Tuple(a_t), Tuple(b_t)) => a_t.cmp(b_t),
(Alias(a_i, a_p), Alias(b_i, b_p)) => a_i.cmp(b_i).then_with(|| a_p.cmp(b_p)),
(Param(a_p), Param(b_p)) => a_p.cmp(b_p),
@@ -369,7 +410,7 @@ impl<I: Interner> Ord for TyKind<I> {
(Error(a_e), Error(b_e)) => a_e.cmp(b_e),
(Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => Ordering::Equal,
_ => {
- debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}");
+ debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}");
Ordering::Equal
}
}
@@ -421,6 +462,10 @@ impl<I: Interner> hash::Hash for TyKind<I> {
m.hash(state)
}
GeneratorWitness(g) => g.hash(state),
+ GeneratorWitnessMIR(d, s) => {
+ d.hash(state);
+ s.hash(state);
+ }
Tuple(t) => t.hash(state),
Alias(i, p) => {
i.hash(state);
@@ -461,6 +506,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s),
Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m),
GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g),
+ GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s),
Never => f.write_str("Never"),
Tuple(t) => f.debug_tuple_field1_finish("Tuple", t),
Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a),
@@ -559,6 +605,10 @@ where
GeneratorWitness(b) => e.emit_enum_variant(disc, |e| {
b.encode(e);
}),
+ GeneratorWitnessMIR(def_id, substs) => e.emit_enum_variant(disc, |e| {
+ def_id.encode(e);
+ substs.encode(e);
+ }),
Never => e.emit_enum_variant(disc, |_| {}),
Tuple(substs) => e.emit_enum_variant(disc, |e| {
substs.encode(e);
@@ -641,6 +691,7 @@ where
23 => Placeholder(Decodable::decode(d)),
24 => Infer(Decodable::decode(d)),
25 => Error(Decodable::decode(d)),
+ 26 => GeneratorWitnessMIR(Decodable::decode(d), Decodable::decode(d)),
_ => panic!(
"{}",
format!(
@@ -742,6 +793,10 @@ where
GeneratorWitness(b) => {
b.hash_stable(__hcx, __hasher);
}
+ GeneratorWitnessMIR(def_id, substs) => {
+ def_id.hash_stable(__hcx, __hasher);
+ substs.hash_stable(__hcx, __hasher);
+ }
Never => {}
Tuple(substs) => {
substs.hash_stable(__hcx, __hasher);
@@ -903,6 +958,9 @@ pub enum RegionKind<I: Interner> {
/// Erased region, used by trait selection, in MIR and during codegen.
ReErased,
+
+ /// A region that resulted from some other error. Used exclusively for diagnostics.
+ ReError(I::ErrorGuaranteed),
}
// This is manually implemented for `RegionKind` because `std::mem::discriminant`
@@ -917,6 +975,7 @@ const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize {
ReVar(_) => 4,
RePlaceholder(_) => 5,
ReErased => 6,
+ ReError(_) => 7,
}
}
@@ -928,6 +987,7 @@ where
I::FreeRegion: Copy,
I::RegionVid: Copy,
I::PlaceholderRegion: Copy,
+ I::ErrorGuaranteed: Copy,
{
}
@@ -942,6 +1002,7 @@ impl<I: Interner> Clone for RegionKind<I> {
ReVar(r) => ReVar(r.clone()),
RePlaceholder(r) => RePlaceholder(r.clone()),
ReErased => ReErased,
+ ReError(r) => ReError(r.clone()),
}
}
}
@@ -959,10 +1020,11 @@ impl<I: Interner> PartialEq for RegionKind<I> {
(ReVar(a_r), ReVar(b_r)) => a_r == b_r,
(RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r,
(ReErased, ReErased) => true,
+ (ReError(_), ReError(_)) => true,
_ => {
debug_assert!(
false,
- "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
+ "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
);
true
}
@@ -1020,6 +1082,7 @@ impl<I: Interner> hash::Hash for RegionKind<I> {
ReVar(r) => r.hash(state),
RePlaceholder(r) => r.hash(state),
ReErased => (),
+ ReError(_) => (),
}
}
}
@@ -1043,6 +1106,8 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"),
ReErased => f.write_str("ReErased"),
+
+ ReError(_) => f.write_str("ReError"),
}
}
}
@@ -1077,6 +1142,7 @@ where
a.encode(e);
}),
ReErased => e.emit_enum_variant(disc, |_| {}),
+ ReError(_) => e.emit_enum_variant(disc, |_| {}),
}
}
}
@@ -1089,6 +1155,7 @@ where
I::FreeRegion: Decodable<D>,
I::RegionVid: Decodable<D>,
I::PlaceholderRegion: Decodable<D>,
+ I::ErrorGuaranteed: Decodable<D>,
{
fn decode(d: &mut D) -> Self {
match Decoder::read_usize(d) {
@@ -1099,6 +1166,7 @@ where
4 => ReVar(Decodable::decode(d)),
5 => RePlaceholder(Decodable::decode(d)),
6 => ReErased,
+ 7 => ReError(Decodable::decode(d)),
_ => panic!(
"{}",
format!(
@@ -1127,7 +1195,7 @@ where
) {
std::mem::discriminant(self).hash_stable(hcx, hasher);
match self {
- ReErased | ReStatic => {
+ ReErased | ReStatic | ReError(_) => {
// No variant fields to hash for these ...
}
ReLateBound(d, r) => {
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
new file mode 100644
index 000000000..62239fd20
--- /dev/null
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -0,0 +1,115 @@
+//! 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::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)
+ }
+}