Move folding & visiting traits to ir submodules
This commit is contained in:
parent
20081880ad
commit
62846d7c99
3 changed files with 331 additions and 301 deletions
|
@ -48,161 +48,173 @@ use rustc_hir::def_id::DefId;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
/// This trait is implemented for every type that can be folded,
|
pub use ir::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||||
/// providing the skeleton of the traversal.
|
|
||||||
///
|
pub mod ir {
|
||||||
/// To implement this conveniently, use the derive macro located in
|
use crate::ty::{self, ir::TypeVisitable, Binder, Ty, TyCtxt};
|
||||||
/// `rustc_macros`.
|
|
||||||
pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> {
|
/// This trait is implemented for every type that can be folded,
|
||||||
/// The entry point for folding. To fold a value `t` with a folder `f`
|
/// providing the skeleton of the traversal.
|
||||||
/// call: `t.try_fold_with(f)`.
|
|
||||||
///
|
///
|
||||||
/// For most types, this just traverses the value, calling `try_fold_with`
|
/// To implement this conveniently, use the derive macro located in
|
||||||
/// on each field/element.
|
/// `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)`.
|
||||||
|
///
|
||||||
|
/// 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<'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
|
||||||
|
/// `try_fold_with`.
|
||||||
|
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> {
|
||||||
|
/// 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<'tcx>>(
|
||||||
|
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<'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.
|
||||||
///
|
///
|
||||||
/// For types of interest (such as `Ty`), the implementation of method
|
/// A blanket implementation of [`FallibleTypeFolder`] will defer to
|
||||||
/// calls a folder method specifically for that type (such as
|
/// the infallible methods of this trait to ensure that the two APIs
|
||||||
/// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
|
/// are coherent.
|
||||||
/// to `TypeFolder`.
|
pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
|
||||||
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
|
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||||
|
|
||||||
/// A convenient alternative to `try_fold_with` for use with infallible
|
fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
|
||||||
/// folders. Do not override this method, to ensure coherence with
|
where
|
||||||
/// `try_fold_with`.
|
T: TypeFoldable<'tcx>,
|
||||||
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
|
{
|
||||||
self.try_fold_with(folder).into_ok()
|
t.super_fold_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
|
t.super_fold_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||||
|
r.super_fold_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||||
|
c.super_fold_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||||
|
p.super_fold_with(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// This trait is implemented for types of interest.
|
/// This trait is implemented for every folding traversal. There is a fold
|
||||||
pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
|
/// method defined for every type of interest. Each such method has a default
|
||||||
/// Provides a default fold for a type of interest. This should only be
|
/// that does an "identity" fold.
|
||||||
/// called within `TypeFolder` methods, when a non-custom traversal is
|
///
|
||||||
/// desired for the value of the type of interest passed to that method.
|
/// A blanket implementation of this trait (that defers to the relevant
|
||||||
/// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
|
/// method of [`TypeFolder`]) is provided for all infallible folders in
|
||||||
/// `ty.try_super_fold_with(self)`, but any other folding should be done
|
/// order to ensure the two APIs are coherent.
|
||||||
/// with `xyz.try_fold_with(self)`.
|
pub trait FallibleTypeFolder<'tcx>: Sized {
|
||||||
fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
|
type Error;
|
||||||
self,
|
|
||||||
folder: &mut F,
|
|
||||||
) -> Result<Self, F::Error>;
|
|
||||||
|
|
||||||
/// A convenient alternative to `try_super_fold_with` for use with
|
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
|
||||||
/// infallible folders. Do not override this method, to ensure coherence
|
|
||||||
/// with `try_super_fold_with`.
|
fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
|
||||||
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
|
where
|
||||||
self.try_super_fold_with(folder).into_ok()
|
T: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
t.try_super_fold_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
||||||
|
t.try_super_fold_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_fold_region(
|
||||||
|
&mut self,
|
||||||
|
r: ty::Region<'tcx>,
|
||||||
|
) -> Result<ty::Region<'tcx>, Self::Error> {
|
||||||
|
r.try_super_fold_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
|
||||||
|
c.try_super_fold_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_fold_predicate(
|
||||||
|
&mut self,
|
||||||
|
p: ty::Predicate<'tcx>,
|
||||||
|
) -> Result<ty::Predicate<'tcx>, Self::Error> {
|
||||||
|
p.try_super_fold_with(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// This trait is implemented for every infallible folding traversal. There is
|
// This blanket implementation of the fallible trait for infallible folders
|
||||||
/// a fold method defined for every type of interest. Each such method has a
|
// delegates to infallible methods to ensure coherence.
|
||||||
/// default that does an "identity" fold. Implementations of these methods
|
impl<'tcx, F> FallibleTypeFolder<'tcx> for F
|
||||||
/// 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>
|
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
F: TypeFolder<'tcx>,
|
||||||
{
|
{
|
||||||
t.super_fold_with(self)
|
type Error = !;
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
||||||
t.super_fold_with(self)
|
TypeFolder::tcx(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !>
|
||||||
r.super_fold_with(self)
|
where
|
||||||
}
|
T: TypeFoldable<'tcx>,
|
||||||
|
{
|
||||||
|
Ok(self.fold_binder(t))
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> {
|
||||||
c.super_fold_with(self)
|
Ok(self.fold_ty(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> {
|
||||||
p.super_fold_with(self)
|
Ok(self.fold_region(r))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// This trait is implemented for every folding traversal. There is a fold
|
fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> {
|
||||||
/// method defined for every type of interest. Each such method has a default
|
Ok(self.fold_const(c))
|
||||||
/// 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>;
|
fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
|
||||||
|
Ok(self.fold_predicate(p))
|
||||||
fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
|
}
|
||||||
where
|
|
||||||
T: TypeFoldable<'tcx>,
|
|
||||||
{
|
|
||||||
t.try_super_fold_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
|
|
||||||
t.try_super_fold_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
|
|
||||||
r.try_super_fold_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
|
|
||||||
c.try_super_fold_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_predicate(
|
|
||||||
&mut self,
|
|
||||||
p: ty::Predicate<'tcx>,
|
|
||||||
) -> 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
|
|
||||||
F: TypeFolder<'tcx>,
|
|
||||||
{
|
|
||||||
type Error = !;
|
|
||||||
|
|
||||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
|
||||||
TypeFolder::tcx(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !>
|
|
||||||
where
|
|
||||||
T: TypeFoldable<'tcx>,
|
|
||||||
{
|
|
||||||
Ok(self.fold_binder(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> {
|
|
||||||
Ok(self.fold_ty(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> {
|
|
||||||
Ok(self.fold_region(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> {
|
|
||||||
Ok(self.fold_const(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
|
|
||||||
Ok(self.fold_predicate(p))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,10 @@ mod structural_impls;
|
||||||
mod sty;
|
mod sty;
|
||||||
mod typeck_results;
|
mod typeck_results;
|
||||||
|
|
||||||
|
pub mod ir {
|
||||||
|
pub use super::{fold::ir::*, visit::ir::*};
|
||||||
|
}
|
||||||
|
|
||||||
// Data types
|
// Data types
|
||||||
|
|
||||||
pub type RegisteredTools = FxHashSet<Ident>;
|
pub type RegisteredTools = FxHashSet<Ident>;
|
||||||
|
|
|
@ -39,189 +39,203 @@
|
||||||
//! - u.visit_with(visitor)
|
//! - u.visit_with(visitor)
|
||||||
//! ```
|
//! ```
|
||||||
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
|
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
|
||||||
use rustc_errors::ErrorGuaranteed;
|
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::sso::SsoHashSet;
|
use rustc_data_structures::sso::SsoHashSet;
|
||||||
use std::fmt;
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
/// This trait is implemented for every type that can be visited,
|
pub use ir::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||||
/// providing the skeleton of the traversal.
|
|
||||||
///
|
pub mod ir {
|
||||||
/// To implement this conveniently, use the derive macro located in
|
use crate::ty::{self, Binder, Ty, TypeFlags};
|
||||||
/// `rustc_macros`.
|
use rustc_errors::ErrorGuaranteed;
|
||||||
pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
|
|
||||||
/// The entry point for visiting. To visit a value `t` with a visitor `v`
|
use std::fmt;
|
||||||
/// call: `t.visit_with(v)`.
|
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.
|
||||||
///
|
///
|
||||||
/// For most types, this just traverses the value, calling `visit_with` on
|
/// To implement this conveniently, use the derive macro located in
|
||||||
/// each field/element.
|
/// `rustc_macros`.
|
||||||
///
|
pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
|
||||||
/// For types of interest (such as `Ty`), the implementation of this method
|
/// The entry point for visiting. To visit a value `t` with a visitor `v`
|
||||||
/// that calls a visitor method specifically for that type (such as
|
/// call: `t.visit_with(v)`.
|
||||||
/// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
|
///
|
||||||
/// `TypeVisitor`.
|
/// For most types, this just traverses the value, calling `visit_with` on
|
||||||
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
|
/// 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<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
|
||||||
|
|
||||||
/// Returns `true` if `self` has any late-bound regions that are either
|
/// Returns `true` if `self` has any late-bound regions that are either
|
||||||
/// bound by `binder` or bound by some binder outside of `binder`.
|
/// bound by `binder` or bound by some binder outside of `binder`.
|
||||||
/// If `binder` is `ty::INNERMOST`, this indicates whether
|
/// If `binder` is `ty::INNERMOST`, this indicates whether
|
||||||
/// there are any late-bound regions that appear free.
|
/// there are any late-bound regions that appear free.
|
||||||
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
|
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
|
||||||
self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
|
self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this type has any regions that escape `binder` (and
|
/// Returns `true` if this type has any regions that escape `binder` (and
|
||||||
/// hence are not bound by it).
|
/// hence are not bound by it).
|
||||||
fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
|
fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
|
||||||
self.has_vars_bound_at_or_above(binder.shifted_in(1))
|
self.has_vars_bound_at_or_above(binder.shifted_in(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if this type has regions that are not a part of the type.
|
/// Return `true` if this type has regions that are not a part of the type.
|
||||||
/// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
|
/// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
|
||||||
/// would return `true`. The latter can occur when traversing through the
|
/// would return `true`. The latter can occur when traversing through the
|
||||||
/// former.
|
/// former.
|
||||||
///
|
///
|
||||||
/// See [`HasEscapingVarsVisitor`] for more information.
|
/// See [`HasEscapingVarsVisitor`] for more information.
|
||||||
fn has_escaping_bound_vars(&self) -> bool {
|
fn has_escaping_bound_vars(&self) -> bool {
|
||||||
self.has_vars_bound_at_or_above(ty::INNERMOST)
|
self.has_vars_bound_at_or_above(ty::INNERMOST)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_type_flags(&self, flags: TypeFlags) -> bool {
|
fn has_type_flags(&self, flags: TypeFlags) -> bool {
|
||||||
let res =
|
let res = self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value()
|
||||||
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
|
== Some(FoundFlags);
|
||||||
trace!(?self, ?flags, ?res, "has_type_flags");
|
trace!(?self, ?flags, ?res, "has_type_flags");
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
fn has_projections(&self) -> bool {
|
fn has_projections(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
||||||
}
|
}
|
||||||
fn has_opaque_types(&self) -> bool {
|
fn has_opaque_types(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
||||||
}
|
}
|
||||||
fn has_generators(&self) -> bool {
|
fn has_generators(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_GENERATOR)
|
self.has_type_flags(TypeFlags::HAS_TY_GENERATOR)
|
||||||
}
|
}
|
||||||
fn references_error(&self) -> bool {
|
fn references_error(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::HAS_ERROR)
|
self.has_type_flags(TypeFlags::HAS_ERROR)
|
||||||
}
|
}
|
||||||
fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
|
fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
|
||||||
if self.references_error() {
|
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)
|
{
|
||||||
|
Err(reported)
|
||||||
|
} else {
|
||||||
|
bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`");
|
Ok(())
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
Ok(())
|
fn has_non_region_param(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM)
|
||||||
|
}
|
||||||
|
fn has_infer_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_RE_INFER)
|
||||||
|
}
|
||||||
|
fn has_infer_types(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_TY_INFER)
|
||||||
|
}
|
||||||
|
fn has_non_region_infer(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::NEEDS_INFER - TypeFlags::HAS_RE_INFER)
|
||||||
|
}
|
||||||
|
fn needs_infer(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::NEEDS_INFER)
|
||||||
|
}
|
||||||
|
fn has_placeholders(&self) -> bool {
|
||||||
|
self.has_type_flags(
|
||||||
|
TypeFlags::HAS_RE_PLACEHOLDER
|
||||||
|
| TypeFlags::HAS_TY_PLACEHOLDER
|
||||||
|
| TypeFlags::HAS_CT_PLACEHOLDER,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn needs_subst(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::NEEDS_SUBST)
|
||||||
|
}
|
||||||
|
/// "Free" regions in this context means that it has any region
|
||||||
|
/// that is not (a) erased or (b) late-bound.
|
||||||
|
fn has_free_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_erased_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_RE_ERASED)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if there are any un-erased free regions.
|
||||||
|
fn has_erasable_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates whether this value references only 'global'
|
||||||
|
/// generic parameters that are the same regardless of what fn we are
|
||||||
|
/// in. This is used for caching.
|
||||||
|
fn is_global(&self) -> bool {
|
||||||
|
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True if there are any late-bound regions
|
||||||
|
fn has_late_bound_regions(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
|
||||||
|
}
|
||||||
|
/// True if there are any late-bound non-region variables
|
||||||
|
fn has_non_region_late_bound(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_LATE_BOUND - TypeFlags::HAS_RE_LATE_BOUND)
|
||||||
|
}
|
||||||
|
/// True if there are any late-bound variables
|
||||||
|
fn has_late_bound_vars(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_LATE_BOUND)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicates whether this value still has parameters/placeholders/inference variables
|
||||||
|
/// which could be replaced later, in a way that would change the results of `impl`
|
||||||
|
/// specialization.
|
||||||
|
fn still_further_specializable(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn has_non_region_param(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM)
|
pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
|
||||||
}
|
/// Provides a default visit for a type of interest. This should only be
|
||||||
fn has_infer_regions(&self) -> bool {
|
/// called within `TypeVisitor` methods, when a non-custom traversal is
|
||||||
self.has_type_flags(TypeFlags::HAS_RE_INFER)
|
/// 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
|
||||||
fn has_infer_types(&self) -> bool {
|
/// `ty.super_visit_with(self)`, but any other visiting should be done
|
||||||
self.has_type_flags(TypeFlags::HAS_TY_INFER)
|
/// with `xyz.visit_with(self)`.
|
||||||
}
|
fn super_visit_with<V: TypeVisitor<'tcx>>(
|
||||||
fn has_non_region_infer(&self) -> bool {
|
&self,
|
||||||
self.has_type_flags(TypeFlags::NEEDS_INFER - TypeFlags::HAS_RE_INFER)
|
visitor: &mut V,
|
||||||
}
|
) -> ControlFlow<V::BreakTy>;
|
||||||
fn needs_infer(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::NEEDS_INFER)
|
|
||||||
}
|
|
||||||
fn has_placeholders(&self) -> bool {
|
|
||||||
self.has_type_flags(
|
|
||||||
TypeFlags::HAS_RE_PLACEHOLDER
|
|
||||||
| TypeFlags::HAS_TY_PLACEHOLDER
|
|
||||||
| TypeFlags::HAS_CT_PLACEHOLDER,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
fn needs_subst(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::NEEDS_SUBST)
|
|
||||||
}
|
|
||||||
/// "Free" regions in this context means that it has any region
|
|
||||||
/// that is not (a) erased or (b) late-bound.
|
|
||||||
fn has_free_regions(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_erased_regions(&self) -> bool {
|
/// This trait is implemented for every visiting traversal. There is a visit
|
||||||
self.has_type_flags(TypeFlags::HAS_RE_ERASED)
|
/// 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 = !;
|
||||||
|
|
||||||
/// True if there are any un-erased free regions.
|
fn visit_binder<T: TypeVisitable<'tcx>>(
|
||||||
fn has_erasable_regions(&self) -> bool {
|
&mut self,
|
||||||
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
|
t: &Binder<'tcx, T>,
|
||||||
}
|
) -> ControlFlow<Self::BreakTy> {
|
||||||
|
t.super_visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Indicates whether this value references only 'global'
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
/// generic parameters that are the same regardless of what fn we are
|
t.super_visit_with(self)
|
||||||
/// in. This is used for caching.
|
}
|
||||||
fn is_global(&self) -> bool {
|
|
||||||
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// True if there are any late-bound regions
|
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
fn has_late_bound_regions(&self) -> bool {
|
r.super_visit_with(self)
|
||||||
self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
|
}
|
||||||
}
|
|
||||||
/// True if there are any late-bound non-region variables
|
|
||||||
fn has_non_region_late_bound(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_LATE_BOUND - TypeFlags::HAS_RE_LATE_BOUND)
|
|
||||||
}
|
|
||||||
/// True if there are any late-bound variables
|
|
||||||
fn has_late_bound_vars(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::HAS_LATE_BOUND)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates whether this value still has parameters/placeholders/inference variables
|
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
/// which could be replaced later, in a way that would change the results of `impl`
|
c.super_visit_with(self)
|
||||||
/// specialization.
|
}
|
||||||
fn still_further_specializable(&self) -> bool {
|
|
||||||
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
|
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
/// Provides a default visit for a type of interest. This should only be
|
p.super_visit_with(self)
|
||||||
/// 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>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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>>(
|
|
||||||
&mut self,
|
|
||||||
t: &Binder<'tcx, T>,
|
|
||||||
) -> ControlFlow<Self::BreakTy> {
|
|
||||||
t.super_visit_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
t.super_visit_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
r.super_visit_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
c.super_visit_with(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|
||||||
p.super_visit_with(self)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue