1
Fork 0

Move folding & visiting traits to ir submodules

This commit is contained in:
Alan Egerton 2023-02-09 12:56:33 +00:00
parent 20081880ad
commit 62846d7c99
No known key found for this signature in database
GPG key ID: 7D4C2F6C22122532
3 changed files with 331 additions and 301 deletions

View file

@ -48,12 +48,17 @@ use rustc_hir::def_id::DefId;
use std::collections::BTreeMap;
/// 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<'tcx>: TypeVisitable<'tcx> {
pub use ir::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
pub mod ir {
use crate::ty::{self, ir::TypeVisitable, Binder, Ty, TyCtxt};
/// 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<'tcx>: TypeVisitable<'tcx> {
/// The entry point for folding. To fold a value `t` with a folder `f`
/// call: `t.try_fold_with(f)`.
///
@ -64,7 +69,10 @@ pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> {
/// 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<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
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
@ -72,10 +80,10 @@ pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
self.try_fold_with(folder).into_ok()
}
}
}
// This trait is implemented for types of interest.
pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
// This trait is implemented for types of interest.
pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
/// 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.
@ -93,18 +101,18 @@ pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(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<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
/// 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<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
fn tcx(&self) -> TyCtxt<'tcx>;
fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
@ -129,16 +137,16 @@ pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
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<'tcx>: Sized {
/// 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<'tcx>: Sized {
type Error;
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
@ -154,7 +162,10 @@ pub trait FallibleTypeFolder<'tcx>: Sized {
t.try_super_fold_with(self)
}
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
fn try_fold_region(
&mut self,
r: ty::Region<'tcx>,
) -> Result<ty::Region<'tcx>, Self::Error> {
r.try_super_fold_with(self)
}
@ -168,14 +179,14 @@ pub trait FallibleTypeFolder<'tcx>: Sized {
) -> Result<ty::Predicate<'tcx>, Self::Error> {
p.try_super_fold_with(self)
}
}
}
// This blanket implementation of the fallible trait for infallible folders
// delegates to infallible methods to ensure coherence.
impl<'tcx, F> FallibleTypeFolder<'tcx> for F
where
// This blanket implementation of the fallible trait for infallible folders
// delegates to infallible methods to ensure coherence.
impl<'tcx, F> FallibleTypeFolder<'tcx> for F
where
F: TypeFolder<'tcx>,
{
{
type Error = !;
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
@ -204,6 +215,7 @@ where
fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
Ok(self.fold_predicate(p))
}
}
}
///////////////////////////////////////////////////////////////////////////

View file

@ -146,6 +146,10 @@ mod structural_impls;
mod sty;
mod typeck_results;
pub mod ir {
pub use super::{fold::ir::*, visit::ir::*};
}
// Data types
pub type RegisteredTools = FxHashSet<Ident>;

View file

@ -39,19 +39,28 @@
//! - u.visit_with(visitor)
//! ```
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
use rustc_errors::ErrorGuaranteed;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sso::SsoHashSet;
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<'tcx>: fmt::Debug + Clone {
pub use ir::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
pub mod ir {
use crate::ty::{self, Binder, Ty, TypeFlags};
use rustc_errors::ErrorGuaranteed;
use std::fmt;
use std::ops::ControlFlow;
use super::{FoundFlags, HasEscapingVarsVisitor, HasTypeFlagsVisitor};
/// 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<'tcx>: fmt::Debug + Clone {
/// The entry point for visiting. To visit a value `t` with a visitor `v`
/// call: `t.visit_with(v)`.
///
@ -89,8 +98,8 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
}
fn has_type_flags(&self, flags: TypeFlags) -> bool {
let res =
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
let res = self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value()
== Some(FoundFlags);
trace!(?self, ?flags, ?res, "has_type_flags");
res
}
@ -108,7 +117,8 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
}
fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
if self.references_error() {
if let Some(reported) = ty::tls::with(|tcx| tcx.sess.is_compilation_going_to_fail()) {
if let Some(reported) = ty::tls::with(|tcx| tcx.sess.is_compilation_going_to_fail())
{
Err(reported)
} else {
bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`");
@ -183,22 +193,25 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
fn still_further_specializable(&self) -> bool {
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
}
}
}
pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
/// 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<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
}
fn super_visit_with<V: TypeVisitor<'tcx>>(
&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<'tcx>: Sized {
/// 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<'tcx>: Sized {
type BreakTy = !;
fn visit_binder<T: TypeVisitable<'tcx>>(
@ -223,6 +236,7 @@ pub trait TypeVisitor<'tcx>: Sized {
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
p.super_visit_with(self)
}
}
}
///////////////////////////////////////////////////////////////////////////