Skip to main content

rustc_type_ir/
generic_visit.rs

1//! Special visiting used by rust-analyzer only.
2//!
3//! It is different from `TypeVisitable` in two ways:
4//!
5//!  - The visitor is a generic of the trait and not the method, allowing types to attach
6//!    special behavior to visitors (as long as they know it; we don't use this capability
7//!    in rustc crates, but rust-analyzer needs it).
8//!  - It **must visit** every field. This is why we don't have an attribute like `#[type_visitable(ignore)]`
9//!    for this visit. The reason for this is soundness: rust-analyzer uses this visit to
10//!    garbage collect types, so a missing field can mean a use after free
11
12use std::sync::Arc;
13
14use rustc_index::{Idx, IndexVec};
15use smallvec::SmallVec;
16use thin_vec::ThinVec;
17
18use crate::Interner;
19
20/// This trait is implemented for every type that can be visited,
21/// providing the skeleton of the traversal.
22///
23/// ## Safety
24///
25/// A manual implementation **must visit** every field.
26///
27/// Therefore, it is advised to instead derive this using the derive
28/// macro located in `rustc_macros`.
29#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "GenericTypeVisitable")]
30pub unsafe trait GenericTypeVisitable<V> {
31    fn generic_visit_with(&self, visitor: &mut V);
32}
33
34///////////////////////////////////////////////////////////////////////////
35// Traversal implementations.
36
37unsafe impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for &T {
38    fn generic_visit_with(&self, visitor: &mut V) {
39        T::generic_visit_with(*self, visitor)
40    }
41}
42
43unsafe impl<V, T: GenericTypeVisitable<V>, U: GenericTypeVisitable<V>> GenericTypeVisitable<V>
44    for (T, U)
45{
46    fn generic_visit_with(&self, visitor: &mut V) {
47        self.0.generic_visit_with(visitor);
48        self.1.generic_visit_with(visitor);
49    }
50}
51
52unsafe impl<V, A: GenericTypeVisitable<V>, B: GenericTypeVisitable<V>, C: GenericTypeVisitable<V>>
53    GenericTypeVisitable<V> for (A, B, C)
54{
55    fn generic_visit_with(&self, visitor: &mut V) {
56        self.0.generic_visit_with(visitor);
57        self.1.generic_visit_with(visitor);
58        self.2.generic_visit_with(visitor);
59    }
60}
61
62unsafe impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for Option<T> {
63    fn generic_visit_with(&self, visitor: &mut V) {
64        match self {
65            Some(v) => v.generic_visit_with(visitor),
66            None => {}
67        }
68    }
69}
70
71unsafe impl<V, T: GenericTypeVisitable<V>, E: GenericTypeVisitable<V>> GenericTypeVisitable<V>
72    for Result<T, E>
73{
74    fn generic_visit_with(&self, visitor: &mut V) {
75        match self {
76            Ok(v) => v.generic_visit_with(visitor),
77            Err(e) => e.generic_visit_with(visitor),
78        }
79    }
80}
81
82unsafe impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for Arc<T> {
83    fn generic_visit_with(&self, visitor: &mut V) {
84        (**self).generic_visit_with(visitor)
85    }
86}
87
88unsafe impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for Box<T> {
89    fn generic_visit_with(&self, visitor: &mut V) {
90        (**self).generic_visit_with(visitor)
91    }
92}
93
94unsafe impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for Vec<T> {
95    fn generic_visit_with(&self, visitor: &mut V) {
96        self.iter().for_each(|it| it.generic_visit_with(visitor));
97    }
98}
99
100unsafe impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for ThinVec<T> {
101    fn generic_visit_with(&self, visitor: &mut V) {
102        self.iter().for_each(|it| it.generic_visit_with(visitor));
103    }
104}
105
106unsafe impl<V, T: GenericTypeVisitable<V>, const N: usize> GenericTypeVisitable<V>
107    for SmallVec<[T; N]>
108{
109    fn generic_visit_with(&self, visitor: &mut V) {
110        self.iter().for_each(|it| it.generic_visit_with(visitor));
111    }
112}
113
114unsafe impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for [T] {
115    fn generic_visit_with(&self, visitor: &mut V) {
116        self.iter().for_each(|it| it.generic_visit_with(visitor));
117    }
118}
119
120unsafe impl<V, T: GenericTypeVisitable<V>, const N: usize> GenericTypeVisitable<V> for [T; N] {
121    fn generic_visit_with(&self, visitor: &mut V) {
122        self.iter().for_each(|it| it.generic_visit_with(visitor));
123    }
124}
125
126unsafe impl<V, T: GenericTypeVisitable<V>, Ix: Idx> GenericTypeVisitable<V> for IndexVec<Ix, T> {
127    fn generic_visit_with(&self, visitor: &mut V) {
128        self.iter().for_each(|it| it.generic_visit_with(visitor));
129    }
130}
131
132unsafe impl<S, V> GenericTypeVisitable<V> for std::hash::BuildHasherDefault<S> {
133    fn generic_visit_with(&self, _visitor: &mut V) {}
134}
135
136#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
137unsafe impl<
138    Visitor,
139    Key: GenericTypeVisitable<Visitor>,
140    Value: GenericTypeVisitable<Visitor>,
141    S: GenericTypeVisitable<Visitor>,
142> GenericTypeVisitable<Visitor> for std::collections::HashMap<Key, Value, S>
143{
144    fn generic_visit_with(&self, visitor: &mut Visitor) {
145        self.iter().for_each(|it| it.generic_visit_with(visitor));
146        self.hasher().generic_visit_with(visitor);
147    }
148}
149
150#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
151unsafe impl<V, T: GenericTypeVisitable<V>, S: GenericTypeVisitable<V>> GenericTypeVisitable<V>
152    for std::collections::HashSet<T, S>
153{
154    fn generic_visit_with(&self, visitor: &mut V) {
155        self.iter().for_each(|it| it.generic_visit_with(visitor));
156        self.hasher().generic_visit_with(visitor);
157    }
158}
159
160unsafe impl<
161    Visitor,
162    Key: GenericTypeVisitable<Visitor>,
163    Value: GenericTypeVisitable<Visitor>,
164    S: GenericTypeVisitable<Visitor>,
165> GenericTypeVisitable<Visitor> for indexmap::IndexMap<Key, Value, S>
166{
167    fn generic_visit_with(&self, visitor: &mut Visitor) {
168        self.iter().for_each(|it| it.generic_visit_with(visitor));
169        self.hasher().generic_visit_with(visitor);
170    }
171}
172
173unsafe impl<V, T: GenericTypeVisitable<V>, S: GenericTypeVisitable<V>> GenericTypeVisitable<V>
174    for indexmap::IndexSet<T, S>
175{
176    fn generic_visit_with(&self, visitor: &mut V) {
177        self.iter().for_each(|it| it.generic_visit_with(visitor));
178        self.hasher().generic_visit_with(visitor);
179    }
180}
181
182unsafe impl<T: ?Sized, V> GenericTypeVisitable<V> for std::marker::PhantomData<T> {
183    fn generic_visit_with(&self, _visitor: &mut V) {}
184}
185
186// SAFETY: `FnSigKind` is a packed representation, therefore visiting its fields doesn't make sense
187unsafe impl<I: Interner, V> GenericTypeVisitable<V> for crate::FnSigKind<I> {
188    fn generic_visit_with(&self, _visitor: &mut V) {}
189}