Skip to content

Commit dcbc91b

Browse files
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, without much thought, `CustomizableTypeVisitable`. 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.
1 parent bad5026 commit dcbc91b

File tree

24 files changed

+403
-59
lines changed

24 files changed

+403
-59
lines changed

compiler/rustc_type_ir/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ nightly = [
3535
"dep:rustc_span",
3636
"rustc_ast_ir/nightly",
3737
"rustc_index/nightly",
38+
"rustc_type_ir_macros/nightly",
3839
"smallvec/may_dangle",
3940
"smallvec/union",
4041
]

compiler/rustc_type_ir/src/binder.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use std::ops::{ControlFlow, Deref};
44
use derive_where::derive_where;
55
#[cfg(feature = "nightly")]
66
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
7-
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
7+
use rustc_type_ir_macros::{
8+
CustomizableTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic,
9+
};
810
use tracing::instrument;
911

1012
use crate::data_structures::SsoHashSet;
@@ -24,6 +26,7 @@ use crate::{self as ty, DebruijnIndex, Interner};
2426
/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
2527
#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, T)]
2628
#[derive_where(Copy; I: Interner, T: Copy)]
29+
#[derive(CustomizableTypeVisitable)]
2730
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
2831
pub struct Binder<I: Interner, T> {
2932
value: T,
@@ -360,6 +363,7 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
360363
#[derive_where(Clone, PartialEq, Ord, Hash, Debug; I: Interner, T)]
361364
#[derive_where(PartialOrd; I: Interner, T: Ord)]
362365
#[derive_where(Copy; I: Interner, T: Copy)]
366+
#[derive(CustomizableTypeVisitable)]
363367
#[cfg_attr(
364368
feature = "nightly",
365369
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -943,7 +947,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> {
943947
feature = "nightly",
944948
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
945949
)]
946-
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
950+
#[derive(TypeVisitable_Generic, CustomizableTypeVisitable, TypeFoldable_Generic)]
947951
pub enum BoundVarIndexKind {
948952
Bound(DebruijnIndex),
949953
Canonical,

compiler/rustc_type_ir/src/canonical.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use arrayvec::ArrayVec;
55
use derive_where::derive_where;
66
#[cfg(feature = "nightly")]
77
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
8-
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
8+
use rustc_type_ir_macros::{
9+
CustomizableTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
10+
};
911

1012
use crate::data_structures::HashMap;
1113
use crate::inherent::*;
@@ -86,6 +88,7 @@ impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
8688
/// a copy of the canonical value in some other inference context,
8789
/// with fresh inference variables replacing the canonical values.
8890
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
91+
#[derive(CustomizableTypeVisitable)]
8992
#[cfg_attr(
9093
feature = "nightly",
9194
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -219,7 +222,7 @@ impl<I: Interner> CanonicalVarKind<I> {
219222
feature = "nightly",
220223
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
221224
)]
222-
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
225+
#[derive(TypeVisitable_Generic, CustomizableTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
223226
pub struct CanonicalVarValues<I: Interner> {
224227
pub var_values: I::GenericArgs,
225228
}

compiler/rustc_type_ir/src/const_kind.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ use derive_where::derive_where;
55
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
66
#[cfg(feature = "nightly")]
77
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
8-
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
8+
use rustc_type_ir_macros::{
9+
CustomizableTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic,
10+
};
911

1012
use crate::{self as ty, BoundVarIndexKind, Interner};
1113

1214
/// Represents a constant in Rust.
1315
#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
16+
#[derive(CustomizableTypeVisitable)]
1417
#[cfg_attr(
1518
feature = "nightly",
1619
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -66,7 +69,7 @@ impl<I: Interner> fmt::Debug for ConstKind<I> {
6669

6770
/// An unevaluated (potentially generic) constant used in the type-system.
6871
#[derive_where(Clone, Copy, Debug, Hash, PartialEq; I: Interner)]
69-
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
72+
#[derive(TypeVisitable_Generic, CustomizableTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
7073
#[cfg_attr(
7174
feature = "nightly",
7275
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
//! A visiting traversal mechanism for complex data structures that contain type
2+
//! information.
3+
//!
4+
//! This is a read-only traversal of the data structure.
5+
//!
6+
//! This traversal has limited flexibility. Only a small number of "types of
7+
//! interest" within the complex data structures can receive custom
8+
//! visitation. These are the ones containing the most important type-related
9+
//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
10+
//!
11+
//! There are three traits involved in each traversal.
12+
//! - `CustomizableTypeVisitable`. This is implemented once for many types, including:
13+
//! - Types of interest, for which the methods delegate to the visitor.
14+
//! - All other types, including generic containers like `Vec` and `Option`.
15+
//! It defines a "skeleton" of how they should be visited.
16+
//! - `TypeSuperVisitable`. This is implemented only for recursive types of
17+
//! interest, and defines the visiting "skeleton" for these types. (This
18+
//! excludes `Region` because it is non-recursive, i.e. it never contains
19+
//! other types of interest.)
20+
//! - `CustomizableTypeVisitor`. This is implemented for each visitor. This defines how
21+
//! types of interest are visited.
22+
//!
23+
//! This means each visit is a mixture of (a) generic visiting operations, and (b)
24+
//! custom visit operations that are specific to the visitor.
25+
//! - The `CustomizableTypeVisitable` impls handle most of the traversal, and call into
26+
//! `CustomizableTypeVisitor` when they encounter a type of interest.
27+
//! - A `CustomizableTypeVisitor` may call into another `CustomizableTypeVisitable` impl, because some of
28+
//! the types of interest are recursive and can contain other types of interest.
29+
//! - A `CustomizableTypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
30+
//! visitor might provide custom handling only for some types of interest, or
31+
//! only for some variants of each type of interest, and then use default
32+
//! traversal for the remaining cases.
33+
//!
34+
//! For example, if you have `struct S(Ty, U)` where `S: CustomizableTypeVisitable` and `U:
35+
//! CustomizableTypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
36+
//! ```text
37+
//! s.customizable_visit_with(visitor) calls
38+
//! - ty.customizable_visit_with(visitor) calls
39+
//! - visitor.visit_ty(ty) may call
40+
//! - ty.super_customizable_visit_with(visitor)
41+
//! - u.customizable_visit_with(visitor)
42+
//! ```
43+
44+
use std::sync::Arc;
45+
46+
use rustc_index::{Idx, IndexVec};
47+
use smallvec::SmallVec;
48+
use thin_vec::ThinVec;
49+
50+
/// This trait is implemented for every type that can be visited,
51+
/// providing the skeleton of the traversal.
52+
///
53+
/// To implement this conveniently, use the derive macro located in
54+
/// `rustc_macros`.
55+
pub trait CustomizableTypeVisitable<V> {
56+
/// The entry point for visiting. To visit a value `t` with a visitor `v`
57+
/// call: `t.customizable_visit_with(v)`.
58+
///
59+
/// For most types, this just traverses the value, calling `customizable_visit_with` on
60+
/// each field/element.
61+
///
62+
/// For types of interest (such as `Ty`), the implementation of this method
63+
/// that calls a visitor method specifically for that type (such as
64+
/// `V::visit_ty`). This is where control transfers from `CustomizableTypeVisitable` to
65+
/// `CustomizableTypeVisitor`.
66+
fn customizable_visit_with(&self, visitor: &mut V);
67+
}
68+
69+
///////////////////////////////////////////////////////////////////////////
70+
// Traversal implementations.
71+
72+
impl<V, T: ?Sized + CustomizableTypeVisitable<V>> CustomizableTypeVisitable<V> for &T {
73+
fn customizable_visit_with(&self, visitor: &mut V) {
74+
T::customizable_visit_with(*self, visitor)
75+
}
76+
}
77+
78+
impl<V, T: CustomizableTypeVisitable<V>, U: CustomizableTypeVisitable<V>>
79+
CustomizableTypeVisitable<V> for (T, U)
80+
{
81+
fn customizable_visit_with(&self, visitor: &mut V) {
82+
self.0.customizable_visit_with(visitor);
83+
self.1.customizable_visit_with(visitor);
84+
}
85+
}
86+
87+
impl<
88+
V,
89+
A: CustomizableTypeVisitable<V>,
90+
B: CustomizableTypeVisitable<V>,
91+
C: CustomizableTypeVisitable<V>,
92+
> CustomizableTypeVisitable<V> for (A, B, C)
93+
{
94+
fn customizable_visit_with(&self, visitor: &mut V) {
95+
self.0.customizable_visit_with(visitor);
96+
self.1.customizable_visit_with(visitor);
97+
self.2.customizable_visit_with(visitor);
98+
}
99+
}
100+
101+
impl<V, T: CustomizableTypeVisitable<V>> CustomizableTypeVisitable<V> for Option<T> {
102+
fn customizable_visit_with(&self, visitor: &mut V) {
103+
match self {
104+
Some(v) => v.customizable_visit_with(visitor),
105+
None => {}
106+
}
107+
}
108+
}
109+
110+
impl<V, T: CustomizableTypeVisitable<V>, E: CustomizableTypeVisitable<V>>
111+
CustomizableTypeVisitable<V> for Result<T, E>
112+
{
113+
fn customizable_visit_with(&self, visitor: &mut V) {
114+
match self {
115+
Ok(v) => v.customizable_visit_with(visitor),
116+
Err(e) => e.customizable_visit_with(visitor),
117+
}
118+
}
119+
}
120+
121+
impl<V, T: ?Sized + CustomizableTypeVisitable<V>> CustomizableTypeVisitable<V> for Arc<T> {
122+
fn customizable_visit_with(&self, visitor: &mut V) {
123+
(**self).customizable_visit_with(visitor)
124+
}
125+
}
126+
127+
impl<V, T: ?Sized + CustomizableTypeVisitable<V>> CustomizableTypeVisitable<V> for Box<T> {
128+
fn customizable_visit_with(&self, visitor: &mut V) {
129+
(**self).customizable_visit_with(visitor)
130+
}
131+
}
132+
133+
impl<V, T: CustomizableTypeVisitable<V>> CustomizableTypeVisitable<V> for Vec<T> {
134+
fn customizable_visit_with(&self, visitor: &mut V) {
135+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
136+
}
137+
}
138+
139+
impl<V, T: CustomizableTypeVisitable<V>> CustomizableTypeVisitable<V> for ThinVec<T> {
140+
fn customizable_visit_with(&self, visitor: &mut V) {
141+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
142+
}
143+
}
144+
145+
impl<V, T: CustomizableTypeVisitable<V>, const N: usize> CustomizableTypeVisitable<V>
146+
for SmallVec<[T; N]>
147+
{
148+
fn customizable_visit_with(&self, visitor: &mut V) {
149+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
150+
}
151+
}
152+
153+
impl<V, T: CustomizableTypeVisitable<V>> CustomizableTypeVisitable<V> for [T] {
154+
fn customizable_visit_with(&self, visitor: &mut V) {
155+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
156+
}
157+
}
158+
159+
impl<V, T: CustomizableTypeVisitable<V>, Ix: Idx> CustomizableTypeVisitable<V> for IndexVec<Ix, T> {
160+
fn customizable_visit_with(&self, visitor: &mut V) {
161+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
162+
}
163+
}
164+
165+
impl<S, V> CustomizableTypeVisitable<V> for std::hash::BuildHasherDefault<S> {
166+
fn customizable_visit_with(&self, _visitor: &mut V) {}
167+
}
168+
169+
#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
170+
impl<
171+
Visitor,
172+
Key: CustomizableTypeVisitable<Visitor>,
173+
Value: CustomizableTypeVisitable<Visitor>,
174+
S: CustomizableTypeVisitable<Visitor>,
175+
> CustomizableTypeVisitable<Visitor> for std::collections::HashMap<Key, Value, S>
176+
{
177+
fn customizable_visit_with(&self, visitor: &mut Visitor) {
178+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
179+
self.hasher().customizable_visit_with(visitor);
180+
}
181+
}
182+
183+
#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
184+
impl<V, T: CustomizableTypeVisitable<V>, S: CustomizableTypeVisitable<V>>
185+
CustomizableTypeVisitable<V> for std::collections::HashSet<T, S>
186+
{
187+
fn customizable_visit_with(&self, visitor: &mut V) {
188+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
189+
self.hasher().customizable_visit_with(visitor);
190+
}
191+
}
192+
193+
impl<
194+
Visitor,
195+
Key: CustomizableTypeVisitable<Visitor>,
196+
Value: CustomizableTypeVisitable<Visitor>,
197+
S: CustomizableTypeVisitable<Visitor>,
198+
> CustomizableTypeVisitable<Visitor> for indexmap::IndexMap<Key, Value, S>
199+
{
200+
fn customizable_visit_with(&self, visitor: &mut Visitor) {
201+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
202+
self.hasher().customizable_visit_with(visitor);
203+
}
204+
}
205+
206+
impl<V, T: CustomizableTypeVisitable<V>, S: CustomizableTypeVisitable<V>>
207+
CustomizableTypeVisitable<V> for indexmap::IndexSet<T, S>
208+
{
209+
fn customizable_visit_with(&self, visitor: &mut V) {
210+
self.iter().for_each(|it| it.customizable_visit_with(visitor));
211+
self.hasher().customizable_visit_with(visitor);
212+
}
213+
}
214+
215+
macro_rules! trivial_impls {
216+
( $($ty:ty),* $(,)? ) => {
217+
$(
218+
impl<V>
219+
CustomizableTypeVisitable<V> for $ty
220+
{
221+
fn customizable_visit_with(&self, _visitor: &mut V) {}
222+
}
223+
)*
224+
};
225+
}
226+
227+
trivial_impls!(
228+
(),
229+
rustc_ast_ir::Mutability,
230+
bool,
231+
i8,
232+
i16,
233+
i32,
234+
i64,
235+
i128,
236+
isize,
237+
u8,
238+
u16,
239+
u32,
240+
u64,
241+
u128,
242+
usize,
243+
crate::PredicatePolarity,
244+
crate::BoundConstness,
245+
crate::AliasRelationDirection,
246+
crate::DebruijnIndex,
247+
crate::solve::Certainty,
248+
crate::UniverseIndex,
249+
crate::BoundVar,
250+
crate::InferTy,
251+
crate::IntTy,
252+
crate::UintTy,
253+
crate::FloatTy,
254+
crate::InferConst,
255+
crate::RegionVid,
256+
rustc_hash::FxBuildHasher,
257+
crate::TypeFlags,
258+
crate::solve::GoalSource,
259+
);

compiler/rustc_type_ir/src/error.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use derive_where::derive_where;
2-
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
2+
use rustc_type_ir_macros::{
3+
CustomizableTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic,
4+
};
35

46
use crate::solve::NoSolution;
57
use crate::{self as ty, Interner};
68

79
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8-
#[derive(TypeFoldable_Generic, TypeVisitable_Generic)]
10+
#[derive(TypeFoldable_Generic, TypeVisitable_Generic, CustomizableTypeVisitable)]
911
pub struct ExpectedFound<T> {
1012
pub expected: T,
1113
pub found: T,
@@ -19,7 +21,7 @@ impl<T> ExpectedFound<T> {
1921

2022
// Data structures used in type unification
2123
#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
22-
#[derive(TypeVisitable_Generic)]
24+
#[derive(TypeVisitable_Generic, CustomizableTypeVisitable)]
2325
#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
2426
pub enum TypeError<I: Interner> {
2527
Mismatch,

0 commit comments

Comments
 (0)