Provide an extended framework for type visit, for use in rust-analyzer

rust-analyzer needs to be able to visit types when treating not only `Ty`, `Const`, `Region` and `Predicate` specifically, but *all* rust-analyzer-made types specifically (excluding e.g. `TraitRef`, that is declared in rustc_type_ir). This is needed to implement garbage collection.

To support this, we introduce a second, rust-analyzer-only visit trait, named `GenericTypeVisitable`. It's simpler than `TypeVisitable` (for example, it does not have a trait for the visitor, and does not support early-returning) because this is what rust-analyzer needs, but its most distinguished feature is that the visitor is a generic of the *trait* instead of the *method*. This way, specific types can treat specific visitor types specifically and call their methods.

In rustc_type_ir we implement it for a bunch of basic types, and using a derive macro for the rest. The macro and trait are completely disabled when compiling for rustc (`feature = "nightly"`), so not even a compile time penalty will be paid.
This commit is contained in:
Chayim Refael Friedman 2025-12-10 19:09:24 +02:00
parent bad50269f8
commit bb6d9363a7
20 changed files with 381 additions and 55 deletions

View file

@ -35,6 +35,7 @@ nightly = [
"dep:rustc_span",
"rustc_ast_ir/nightly",
"rustc_index/nightly",
"rustc_type_ir_macros/nightly",
"smallvec/may_dangle",
"smallvec/union",
]

View file

@ -4,7 +4,7 @@ use std::ops::{ControlFlow, Deref};
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
use tracing::instrument;
use crate::data_structures::SsoHashSet;
@ -24,6 +24,7 @@ use crate::{self as ty, DebruijnIndex, Interner};
/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, T)]
#[derive_where(Copy; I: Interner, T: Copy)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
pub struct Binder<I: Interner, T> {
value: T,
@ -360,6 +361,7 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
#[derive_where(Clone, PartialEq, Ord, Hash, Debug; I: Interner, T)]
#[derive_where(PartialOrd; I: Interner, T: Ord)]
#[derive_where(Copy; I: Interner, T: Copy)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@ -943,7 +945,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> {
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
pub enum BoundVarIndexKind {
Bound(DebruijnIndex),
Canonical,

View file

@ -5,7 +5,9 @@ use arrayvec::ArrayVec;
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{
GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
};
use crate::data_structures::HashMap;
use crate::inherent::*;
@ -86,6 +88,7 @@ impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
/// a copy of the canonical value in some other inference context,
/// with fresh inference variables replacing the canonical values.
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -219,7 +222,7 @@ impl<I: Interner> CanonicalVarKind<I> {
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct CanonicalVarValues<I: Interner> {
pub var_values: I::GenericArgs,
}

View file

@ -5,12 +5,15 @@ use derive_where::derive_where;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{
GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
};
use crate::{self as ty, BoundVarIndexKind, Interner};
/// Represents a constant in Rust.
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@ -66,7 +69,7 @@ impl<I: Interner> fmt::Debug for ConstKind<I> {
/// An unevaluated (potentially generic) constant used in the type-system.
#[derive_where(Clone, Copy, Debug, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)

View file

@ -1,11 +1,11 @@
use derive_where::derive_where;
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::solve::NoSolution;
use crate::{self as ty, Interner};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(TypeFoldable_Generic, TypeVisitable_Generic)]
#[derive(TypeFoldable_Generic, TypeVisitable_Generic, GenericTypeVisitable)]
pub struct ExpectedFound<T> {
pub expected: T,
pub found: T,
@ -19,7 +19,7 @@ impl<T> ExpectedFound<T> {
// Data structures used in type unification
#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable)]
#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
pub enum TypeError<I: Interner> {
Mismatch,

View file

@ -1,10 +1,12 @@
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::GenericTypeVisitable;
use crate::Interner;
#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -18,6 +20,7 @@ pub enum GenericArgKind<I: Interner> {
impl<I: Interner> Eq for GenericArgKind<I> {}
#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)

View file

@ -0,0 +1,251 @@
//! 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 traits involved in each traversal.
//! - `GenericTypeVisitable`. 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 recursive types of
//! interest, and defines the visiting "skeleton" for these types. (This
//! excludes `Region` because it is non-recursive, i.e. it never contains
//! other types of interest.)
//! - `CustomizableTypeVisitor`. 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 `GenericTypeVisitable` impls handle most of the traversal, and call into
//! `CustomizableTypeVisitor` when they encounter a type of interest.
//! - A `CustomizableTypeVisitor` may call into another `GenericTypeVisitable` impl, because some of
//! the types of interest are recursive and can contain other types of interest.
//! - A `CustomizableTypeVisitor` 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: GenericTypeVisitable` and `U:
//! GenericTypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
//! ```text
//! s.generic_visit_with(visitor) calls
//! - ty.generic_visit_with(visitor) calls
//! - visitor.visit_ty(ty) may call
//! - ty.super_generic_visit_with(visitor)
//! - u.generic_visit_with(visitor)
//! ```
use std::sync::Arc;
use rustc_index::{Idx, IndexVec};
use smallvec::SmallVec;
use thin_vec::ThinVec;
/// 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 GenericTypeVisitable<V> {
/// The entry point for visiting. To visit a value `t` with a visitor `v`
/// call: `t.generic_visit_with(v)`.
///
/// For most types, this just traverses the value, calling `generic_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 `GenericTypeVisitable` to
/// `CustomizableTypeVisitor`.
fn generic_visit_with(&self, visitor: &mut V);
}
///////////////////////////////////////////////////////////////////////////
// Traversal implementations.
impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for &T {
fn generic_visit_with(&self, visitor: &mut V) {
T::generic_visit_with(*self, visitor)
}
}
impl<V, T: GenericTypeVisitable<V>, U: GenericTypeVisitable<V>> GenericTypeVisitable<V> for (T, U) {
fn generic_visit_with(&self, visitor: &mut V) {
self.0.generic_visit_with(visitor);
self.1.generic_visit_with(visitor);
}
}
impl<V, A: GenericTypeVisitable<V>, B: GenericTypeVisitable<V>, C: GenericTypeVisitable<V>>
GenericTypeVisitable<V> for (A, B, C)
{
fn generic_visit_with(&self, visitor: &mut V) {
self.0.generic_visit_with(visitor);
self.1.generic_visit_with(visitor);
self.2.generic_visit_with(visitor);
}
}
impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for Option<T> {
fn generic_visit_with(&self, visitor: &mut V) {
match self {
Some(v) => v.generic_visit_with(visitor),
None => {}
}
}
}
impl<V, T: GenericTypeVisitable<V>, E: GenericTypeVisitable<V>> GenericTypeVisitable<V>
for Result<T, E>
{
fn generic_visit_with(&self, visitor: &mut V) {
match self {
Ok(v) => v.generic_visit_with(visitor),
Err(e) => e.generic_visit_with(visitor),
}
}
}
impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for Arc<T> {
fn generic_visit_with(&self, visitor: &mut V) {
(**self).generic_visit_with(visitor)
}
}
impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for Box<T> {
fn generic_visit_with(&self, visitor: &mut V) {
(**self).generic_visit_with(visitor)
}
}
impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for Vec<T> {
fn generic_visit_with(&self, visitor: &mut V) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
}
}
impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for ThinVec<T> {
fn generic_visit_with(&self, visitor: &mut V) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
}
}
impl<V, T: GenericTypeVisitable<V>, const N: usize> GenericTypeVisitable<V> for SmallVec<[T; N]> {
fn generic_visit_with(&self, visitor: &mut V) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
}
}
impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for [T] {
fn generic_visit_with(&self, visitor: &mut V) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
}
}
impl<V, T: GenericTypeVisitable<V>, Ix: Idx> GenericTypeVisitable<V> for IndexVec<Ix, T> {
fn generic_visit_with(&self, visitor: &mut V) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
}
}
impl<S, V> GenericTypeVisitable<V> for std::hash::BuildHasherDefault<S> {
fn generic_visit_with(&self, _visitor: &mut V) {}
}
#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
impl<
Visitor,
Key: GenericTypeVisitable<Visitor>,
Value: GenericTypeVisitable<Visitor>,
S: GenericTypeVisitable<Visitor>,
> GenericTypeVisitable<Visitor> for std::collections::HashMap<Key, Value, S>
{
fn generic_visit_with(&self, visitor: &mut Visitor) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
self.hasher().generic_visit_with(visitor);
}
}
#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
impl<V, T: GenericTypeVisitable<V>, S: GenericTypeVisitable<V>> GenericTypeVisitable<V>
for std::collections::HashSet<T, S>
{
fn generic_visit_with(&self, visitor: &mut V) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
self.hasher().generic_visit_with(visitor);
}
}
impl<
Visitor,
Key: GenericTypeVisitable<Visitor>,
Value: GenericTypeVisitable<Visitor>,
S: GenericTypeVisitable<Visitor>,
> GenericTypeVisitable<Visitor> for indexmap::IndexMap<Key, Value, S>
{
fn generic_visit_with(&self, visitor: &mut Visitor) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
self.hasher().generic_visit_with(visitor);
}
}
impl<V, T: GenericTypeVisitable<V>, S: GenericTypeVisitable<V>> GenericTypeVisitable<V>
for indexmap::IndexSet<T, S>
{
fn generic_visit_with(&self, visitor: &mut V) {
self.iter().for_each(|it| it.generic_visit_with(visitor));
self.hasher().generic_visit_with(visitor);
}
}
macro_rules! trivial_impls {
( $($ty:ty),* $(,)? ) => {
$(
impl<V>
GenericTypeVisitable<V> for $ty
{
fn generic_visit_with(&self, _visitor: &mut V) {}
}
)*
};
}
trivial_impls!(
(),
rustc_ast_ir::Mutability,
bool,
i8,
i16,
i32,
i64,
i128,
isize,
u8,
u16,
u32,
u64,
u128,
usize,
crate::PredicatePolarity,
crate::BoundConstness,
crate::AliasRelationDirection,
crate::DebruijnIndex,
crate::solve::Certainty,
crate::UniverseIndex,
crate::BoundVar,
crate::InferTy,
crate::IntTy,
crate::UintTy,
crate::FloatTy,
crate::InferConst,
crate::RegionVid,
rustc_hash::FxBuildHasher,
crate::TypeFlags,
crate::solve::GoalSource,
);

View file

@ -44,6 +44,8 @@ mod const_kind;
mod flags;
mod fold;
mod generic_arg;
#[cfg(not(feature = "nightly"))]
mod generic_visit;
mod infer_ctxt;
mod interner;
mod opaque_ty;
@ -67,6 +69,8 @@ pub use const_kind::*;
pub use flags::*;
pub use fold::*;
pub use generic_arg::*;
#[cfg(not(feature = "nightly"))]
pub use generic_visit::*;
pub use infer_ctxt::*;
pub use interner::*;
pub use opaque_ty::*;
@ -75,6 +79,7 @@ pub use predicate::*;
pub use predicate_kind::*;
pub use region_kind::*;
pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintTy};
use rustc_type_ir_macros::GenericTypeVisitable;
pub use ty_info::*;
pub use ty_kind::*;
pub use upcast::*;
@ -213,7 +218,7 @@ pub fn debug_bound_var<T: std::fmt::Write>(
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, GenericTypeVisitable)]
#[cfg_attr(feature = "nightly", derive(Decodable, Encodable, HashStable_NoContext))]
#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
pub enum Variance {

View file

@ -1,13 +1,13 @@
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::inherent::*;
use crate::{self as ty, Interner};
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)

View file

@ -1,12 +1,14 @@
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{
GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
};
use crate::Interner;
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)

View file

@ -6,7 +6,9 @@ use derive_where::derive_where;
use rustc_macros::{
Decodable, Decodable_NoContext, Encodable, Encodable_NoContext, HashStable_NoContext,
};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{
GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
};
use crate::inherent::*;
use crate::lift::Lift;
@ -17,7 +19,7 @@ use crate::{self as ty, Interner};
/// `A: 'region`
#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, A)]
#[derive_where(Copy; I: Interner, A: Copy)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -52,7 +54,7 @@ where
/// Trait references also appear in object types like `Foo<U>`, but in
/// that case the `Self` parameter is absent from the generic parameters.
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -129,7 +131,7 @@ impl<I: Interner> ty::Binder<I, TraitRef<I>> {
}
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -274,7 +276,7 @@ impl fmt::Display for PredicatePolarity {
}
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -325,7 +327,7 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
/// The generic parameters don't include the erased `Self`, only trait
/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -394,7 +396,7 @@ impl<I: Interner> ty::Binder<I, ExistentialTraitRef<I>> {
/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -552,7 +554,7 @@ impl From<ty::AliasTyKind> for AliasTermKind {
/// * For an inherent projection, this would be `Ty::N<...>`.
/// * For an opaque type, there is no explicit syntax.
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -764,7 +766,7 @@ impl<I: Interner> From<ty::UnevaluatedConst<I>> for AliasTerm<I> {
/// Form #2 eventually yields one of these `ProjectionPredicate`
/// instances to normalize the LHS.
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -827,7 +829,7 @@ impl<I: Interner> fmt::Debug for ProjectionPredicate<I> {
/// Used by the new solver to normalize an alias. This always expects the `term` to
/// be an unconstrained inference variable which is used as the output.
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -864,7 +866,7 @@ impl<I: Interner> fmt::Debug for NormalizesTo<I> {
}
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@ -910,7 +912,7 @@ impl<I: Interner> ty::Binder<I, HostEffectPredicate<I>> {
/// whether the `a` type is the type that we should label as "expected" when
/// presenting user diagnostics.
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -925,7 +927,7 @@ impl<I: Interner> Eq for SubtypePredicate<I> {}
/// Encodes that we have to coerce *from* the `a` type to the `b` type.
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)

View file

@ -3,14 +3,14 @@ use std::fmt;
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::{self as ty, Interner};
/// A clause is something that can appear in where bounds or be inferred
/// by implied bounds.
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@ -58,7 +58,7 @@ pub enum ClauseKind<I: Interner> {
impl<I: Interner> Eq for ClauseKind<I> {}
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)

View file

@ -5,6 +5,7 @@ use derive_where::derive_where;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::GenericTypeVisitable;
use self::RegionKind::*;
use crate::{BoundVarIndexKind, Interner};
@ -126,6 +127,7 @@ rustc_index::newtype_index! {
/// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext))]
pub enum RegionKind<I: Interner> {
/// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`.

View file

@ -18,7 +18,7 @@
//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
use derive_where::derive_where;
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::solve::{CandidateSource, Certainty, Goal, GoalSource, QueryResult};
use crate::{Canonical, CanonicalVarValues, Interner};
@ -31,7 +31,7 @@ use crate::{Canonical, CanonicalVarValues, Interner};
/// inference variables from a nested `InferCtxt`.
#[derive_where(Clone, PartialEq, Hash, Debug; I: Interner, T)]
#[derive_where(Copy; I: Interner, T: Copy)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
pub struct State<I: Interner, T> {
pub var_values: CanonicalVarValues<I>,
pub data: T,
@ -87,7 +87,7 @@ pub enum ProbeStep<I: Interner> {
/// the final result of the current goal - via [ProbeKind::Root] - we also
/// store the [QueryResult].
#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
pub enum ProbeKind<I: Interner> {
/// The root inference context while proving a goal.
Root { result: QueryResult<I> },

View file

@ -5,7 +5,9 @@ use std::hash::Hash;
use derive_where::derive_where;
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{
GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
};
use crate::lang_items::SolverTraitLangItem;
use crate::search_graph::PathKind;
@ -33,7 +35,7 @@ pub struct NoSolution;
/// we're currently typechecking while the `predicate` is some trait bound.
#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, P)]
#[derive_where(Copy; I: Interner, P: Copy)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -95,7 +97,7 @@ pub enum GoalSource {
#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, Goal<I, P>)]
#[derive_where(Copy; I: Interner, Goal<I, P>: Copy)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -206,7 +208,7 @@ pub enum ParamEnvSource {
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
pub enum AliasBoundKind {
/// Alias bound from the self type of a projection
SelfBounds,
@ -235,7 +237,7 @@ pub enum BuiltinImplSource {
}
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
pub struct Response<I: Interner> {
pub certainty: Certainty,
@ -248,7 +250,7 @@ impl<I: Interner> Eq for Response<I> {}
/// Additional constraints returned on success.
#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
pub struct ExternalConstraintsData<I: Interner> {
pub region_constraints: Vec<ty::OutlivesPredicate<I, I::GenericArg>>,
@ -267,7 +269,7 @@ impl<I: Interner> ExternalConstraintsData<I> {
}
#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
pub struct NestedNormalizationGoals<I: Interner>(pub Vec<(GoalSource, Goal<I, I::Predicate>)>);

View file

@ -6,6 +6,7 @@ use std::ops::Deref;
use rustc_data_structures::fingerprint::Fingerprint;
#[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_type_ir_macros::GenericTypeVisitable;
use crate::{DebruijnIndex, TypeFlags};
@ -16,7 +17,7 @@ use crate::{DebruijnIndex, TypeFlags};
/// StableHash::ZERO for the hash, in which case the hash gets computed each time.
/// This is useful if you have values that you intern but never (can?) use for stable
/// hashing.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, GenericTypeVisitable)]
pub struct WithCachedTypeInfo<T> {
pub internee: T,

View file

@ -8,7 +8,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
#[cfg(feature = "nightly")]
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
use rustc_type_ir::data_structures::{NoError, UnifyKey, UnifyValue};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{
GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
};
use self::TyKind::*;
pub use self::closure::*;
@ -20,6 +22,7 @@ use crate::{self as ty, BoundVarIndexKind, FloatTy, IntTy, Interner, UintTy};
mod closure;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@ -56,6 +59,7 @@ impl AliasTyKind {
/// converted to this representation using `<dyn HirTyLowerer>::lower_ty`.
#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")]
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
#[derive(GenericTypeVisitable)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@ -391,7 +395,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
/// * For an inherent projection, this would be `Ty::N<...>`.
/// * For an opaque type, there is no explicit syntax.
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@ -713,7 +717,7 @@ impl fmt::Debug for InferTy {
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
pub struct TypeAndMut<I: Interner> {
pub ty: I::Ty,
pub mutbl: Mutability,
@ -726,7 +730,7 @@ impl<I: Interner> Eq for TypeAndMut<I> {}
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct FnSig<I: Interner> {
pub inputs_and_output: I::Tys,
pub c_variadic: bool,
@ -839,7 +843,7 @@ impl<I: Interner> fmt::Debug for FnSig<I> {
// impls in this crate for `Binder<I, I::Ty>`.
#[derive_where(Clone, Copy, PartialEq, Hash; I: Interner)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct UnsafeBinderInner<I: Interner>(ty::Binder<I, I::Ty>);
impl<I: Interner> Eq for UnsafeBinderInner<I> {}
@ -905,7 +909,7 @@ where
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct FnSigTys<I: Interner> {
pub inputs_and_output: I::Tys,
}
@ -959,7 +963,7 @@ impl<I: Interner> ty::Binder<I, FnSigTys<I>> {
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct FnHeader<I: Interner> {
pub c_variadic: bool,
pub safety: I::Safety,
@ -973,7 +977,7 @@ impl<I: Interner> Eq for FnHeader<I> {}
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct CoroutineWitnessTypes<I: Interner> {
pub types: I::Tys,
pub assumptions: I::RegionAssumptions,

View file

@ -1,7 +1,9 @@
use std::ops::ControlFlow;
use derive_where::derive_where;
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use rustc_type_ir_macros::{
GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
};
use crate::data_structures::DelayedMap;
use crate::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region};
@ -102,7 +104,7 @@ use crate::{self as ty, Interner};
/// * `GR`: The "return type", which is the type of value returned upon
/// completion of the coroutine.
#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct ClosureArgs<I: Interner> {
/// Lifetime and type parameters from the enclosing function,
/// concatenated with a tuple containing the types of the upvars.
@ -206,7 +208,7 @@ impl<I: Interner> ClosureArgs<I> {
}
#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct CoroutineClosureArgs<I: Interner> {
pub args: I::GenericArgs,
}
@ -354,7 +356,7 @@ impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt {
}
#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
pub struct CoroutineClosureSignature<I: Interner> {
pub tupled_inputs_ty: I::Ty,
pub resume_ty: I::Ty,
@ -549,7 +551,7 @@ impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
}
#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
pub struct GenSig<I: Interner> {
pub resume_ty: I::Ty,
pub yield_ty: I::Ty,
@ -559,7 +561,7 @@ pub struct GenSig<I: Interner> {
impl<I: Interner> Eq for GenSig<I> {}
/// Similar to `ClosureArgs`; see the above documentation for more.
#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
pub struct CoroutineArgs<I: Interner> {
pub args: I::GenericArgs,
}

View file

@ -6,6 +6,9 @@ edition = "2024"
[lib]
proc-macro = true
[features]
nightly = []
[dependencies]
# tidy-alphabetical-start
proc-macro2 = "1"

View file

@ -12,6 +12,10 @@ decl_derive!(
decl_derive!(
[Lift_Generic] => lift_derive
);
#[cfg(not(feature = "nightly"))]
decl_derive!(
[GenericTypeVisitable] => customizable_type_visitable_derive
);
fn has_ignore_attr(attrs: &[Attribute], name: &'static str, meta: &'static str) -> bool {
let mut ignored = false;
@ -211,3 +215,39 @@ fn lift(mut ty: syn::Type) -> syn::Type {
ty
}
#[cfg(not(feature = "nightly"))]
fn customizable_type_visitable_derive(
mut s: synstructure::Structure<'_>,
) -> proc_macro2::TokenStream {
if let syn::Data::Union(_) = s.ast().data {
panic!("cannot derive on union")
}
s.add_impl_generic(parse_quote!(__V));
s.add_bounds(synstructure::AddBounds::Fields);
let body_visit = s.each(|bind| {
quote! {
::rustc_type_ir::GenericTypeVisitable::<__V>::generic_visit_with(#bind, __visitor);
}
});
s.bind_with(|_| synstructure::BindStyle::Move);
s.bound_impl(
quote!(::rustc_type_ir::GenericTypeVisitable<__V>),
quote! {
fn generic_visit_with(
&self,
__visitor: &mut __V
) {
match *self { #body_visit }
}
},
)
}
#[cfg(feature = "nightly")]
#[proc_macro_derive(GenericTypeVisitable)]
pub fn customizable_type_visitable_derive(_: proc_macro::TokenStream) -> proc_macro::TokenStream {
proc_macro::TokenStream::new()
}