Skip to content

Commit d30f83a

Browse files
authored
Rollup merge of #149856 - ChayimFriedman2:no-copy-solver-v3, r=jackh726
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. r? types This is a replacement to other efforts to support non-`Copy` type in the solver, replacing them with a GC in r-a, as decided by ``@rust-lang/rust-analyzer.`` The code is tiny in comparison, and I believe T-types will have no problem maintaining it, which mostly means adding the derive on new things when they are added and things break on the r-a side.
2 parents 4f2188f + bb6d936 commit d30f83a

File tree

20 files changed

+381
-55
lines changed

20 files changed

+381
-55
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: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::ops::{ControlFlow, Deref};
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::{TypeFoldable_Generic, TypeVisitable_Generic};
8+
use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
99
use tracing::instrument;
1010

1111
use crate::data_structures::SsoHashSet;
@@ -25,6 +25,7 @@ use crate::{self as ty, DebruijnIndex, Interner, UniverseIndex};
2525
/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
2626
#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, T)]
2727
#[derive_where(Copy; I: Interner, T: Copy)]
28+
#[derive(GenericTypeVisitable)]
2829
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
2930
pub struct Binder<I: Interner, T> {
3031
value: T,
@@ -361,6 +362,7 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
361362
#[derive_where(Clone, PartialEq, Ord, Hash, Debug; I: Interner, T)]
362363
#[derive_where(PartialOrd; I: Interner, T: Ord)]
363364
#[derive_where(Copy; I: Interner, T: Copy)]
365+
#[derive(GenericTypeVisitable)]
364366
#[cfg_attr(
365367
feature = "nightly",
366368
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
@@ -944,7 +946,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> {
944946
feature = "nightly",
945947
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
946948
)]
947-
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
949+
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)]
948950
pub enum BoundVarIndexKind {
949951
Bound(DebruijnIndex),
950952
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+
GenericTypeVisitable, 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(GenericTypeVisitable)]
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, GenericTypeVisitable, 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+
GenericTypeVisitable, 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(GenericTypeVisitable)]
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, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
7073
#[cfg_attr(
7174
feature = "nightly",
7275
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)

compiler/rustc_type_ir/src/error.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use derive_where::derive_where;
2-
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
2+
use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic};
33

44
use crate::solve::NoSolution;
55
use crate::{self as ty, Interner};
66

77
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8-
#[derive(TypeFoldable_Generic, TypeVisitable_Generic)]
8+
#[derive(TypeFoldable_Generic, TypeVisitable_Generic, GenericTypeVisitable)]
99
pub struct ExpectedFound<T> {
1010
pub expected: T,
1111
pub found: T,
@@ -19,7 +19,7 @@ impl<T> ExpectedFound<T> {
1919

2020
// Data structures used in type unification
2121
#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
22-
#[derive(TypeVisitable_Generic)]
22+
#[derive(TypeVisitable_Generic, GenericTypeVisitable)]
2323
#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
2424
pub enum TypeError<I: Interner> {
2525
Mismatch,

compiler/rustc_type_ir/src/generic_arg.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use derive_where::derive_where;
22
#[cfg(feature = "nightly")]
33
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
4+
use rustc_type_ir_macros::GenericTypeVisitable;
45

56
use crate::Interner;
67

78
#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
9+
#[derive(GenericTypeVisitable)]
810
#[cfg_attr(
911
feature = "nightly",
1012
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
@@ -18,6 +20,7 @@ pub enum GenericArgKind<I: Interner> {
1820
impl<I: Interner> Eq for GenericArgKind<I> {}
1921

2022
#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)]
23+
#[derive(GenericTypeVisitable)]
2124
#[cfg_attr(
2225
feature = "nightly",
2326
derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
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+
//! - `GenericTypeVisitable`. 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 `GenericTypeVisitable` 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 `GenericTypeVisitable` 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: GenericTypeVisitable` and `U:
35+
//! GenericTypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
36+
//! ```text
37+
//! s.generic_visit_with(visitor) calls
38+
//! - ty.generic_visit_with(visitor) calls
39+
//! - visitor.visit_ty(ty) may call
40+
//! - ty.super_generic_visit_with(visitor)
41+
//! - u.generic_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 GenericTypeVisitable<V> {
56+
/// The entry point for visiting. To visit a value `t` with a visitor `v`
57+
/// call: `t.generic_visit_with(v)`.
58+
///
59+
/// For most types, this just traverses the value, calling `generic_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 `GenericTypeVisitable` to
65+
/// `CustomizableTypeVisitor`.
66+
fn generic_visit_with(&self, visitor: &mut V);
67+
}
68+
69+
///////////////////////////////////////////////////////////////////////////
70+
// Traversal implementations.
71+
72+
impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for &T {
73+
fn generic_visit_with(&self, visitor: &mut V) {
74+
T::generic_visit_with(*self, visitor)
75+
}
76+
}
77+
78+
impl<V, T: GenericTypeVisitable<V>, U: GenericTypeVisitable<V>> GenericTypeVisitable<V> for (T, U) {
79+
fn generic_visit_with(&self, visitor: &mut V) {
80+
self.0.generic_visit_with(visitor);
81+
self.1.generic_visit_with(visitor);
82+
}
83+
}
84+
85+
impl<V, A: GenericTypeVisitable<V>, B: GenericTypeVisitable<V>, C: GenericTypeVisitable<V>>
86+
GenericTypeVisitable<V> for (A, B, C)
87+
{
88+
fn generic_visit_with(&self, visitor: &mut V) {
89+
self.0.generic_visit_with(visitor);
90+
self.1.generic_visit_with(visitor);
91+
self.2.generic_visit_with(visitor);
92+
}
93+
}
94+
95+
impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for Option<T> {
96+
fn generic_visit_with(&self, visitor: &mut V) {
97+
match self {
98+
Some(v) => v.generic_visit_with(visitor),
99+
None => {}
100+
}
101+
}
102+
}
103+
104+
impl<V, T: GenericTypeVisitable<V>, E: GenericTypeVisitable<V>> GenericTypeVisitable<V>
105+
for Result<T, E>
106+
{
107+
fn generic_visit_with(&self, visitor: &mut V) {
108+
match self {
109+
Ok(v) => v.generic_visit_with(visitor),
110+
Err(e) => e.generic_visit_with(visitor),
111+
}
112+
}
113+
}
114+
115+
impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for Arc<T> {
116+
fn generic_visit_with(&self, visitor: &mut V) {
117+
(**self).generic_visit_with(visitor)
118+
}
119+
}
120+
121+
impl<V, T: ?Sized + GenericTypeVisitable<V>> GenericTypeVisitable<V> for Box<T> {
122+
fn generic_visit_with(&self, visitor: &mut V) {
123+
(**self).generic_visit_with(visitor)
124+
}
125+
}
126+
127+
impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for Vec<T> {
128+
fn generic_visit_with(&self, visitor: &mut V) {
129+
self.iter().for_each(|it| it.generic_visit_with(visitor));
130+
}
131+
}
132+
133+
impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for ThinVec<T> {
134+
fn generic_visit_with(&self, visitor: &mut V) {
135+
self.iter().for_each(|it| it.generic_visit_with(visitor));
136+
}
137+
}
138+
139+
impl<V, T: GenericTypeVisitable<V>, const N: usize> GenericTypeVisitable<V> for SmallVec<[T; N]> {
140+
fn generic_visit_with(&self, visitor: &mut V) {
141+
self.iter().for_each(|it| it.generic_visit_with(visitor));
142+
}
143+
}
144+
145+
impl<V, T: GenericTypeVisitable<V>> GenericTypeVisitable<V> for [T] {
146+
fn generic_visit_with(&self, visitor: &mut V) {
147+
self.iter().for_each(|it| it.generic_visit_with(visitor));
148+
}
149+
}
150+
151+
impl<V, T: GenericTypeVisitable<V>, Ix: Idx> GenericTypeVisitable<V> for IndexVec<Ix, T> {
152+
fn generic_visit_with(&self, visitor: &mut V) {
153+
self.iter().for_each(|it| it.generic_visit_with(visitor));
154+
}
155+
}
156+
157+
impl<S, V> GenericTypeVisitable<V> for std::hash::BuildHasherDefault<S> {
158+
fn generic_visit_with(&self, _visitor: &mut V) {}
159+
}
160+
161+
#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
162+
impl<
163+
Visitor,
164+
Key: GenericTypeVisitable<Visitor>,
165+
Value: GenericTypeVisitable<Visitor>,
166+
S: GenericTypeVisitable<Visitor>,
167+
> GenericTypeVisitable<Visitor> for std::collections::HashMap<Key, Value, S>
168+
{
169+
fn generic_visit_with(&self, visitor: &mut Visitor) {
170+
self.iter().for_each(|it| it.generic_visit_with(visitor));
171+
self.hasher().generic_visit_with(visitor);
172+
}
173+
}
174+
175+
#[expect(rustc::default_hash_types, rustc::potential_query_instability)]
176+
impl<V, T: GenericTypeVisitable<V>, S: GenericTypeVisitable<V>> GenericTypeVisitable<V>
177+
for std::collections::HashSet<T, S>
178+
{
179+
fn generic_visit_with(&self, visitor: &mut V) {
180+
self.iter().for_each(|it| it.generic_visit_with(visitor));
181+
self.hasher().generic_visit_with(visitor);
182+
}
183+
}
184+
185+
impl<
186+
Visitor,
187+
Key: GenericTypeVisitable<Visitor>,
188+
Value: GenericTypeVisitable<Visitor>,
189+
S: GenericTypeVisitable<Visitor>,
190+
> GenericTypeVisitable<Visitor> for indexmap::IndexMap<Key, Value, S>
191+
{
192+
fn generic_visit_with(&self, visitor: &mut Visitor) {
193+
self.iter().for_each(|it| it.generic_visit_with(visitor));
194+
self.hasher().generic_visit_with(visitor);
195+
}
196+
}
197+
198+
impl<V, T: GenericTypeVisitable<V>, S: GenericTypeVisitable<V>> GenericTypeVisitable<V>
199+
for indexmap::IndexSet<T, S>
200+
{
201+
fn generic_visit_with(&self, visitor: &mut V) {
202+
self.iter().for_each(|it| it.generic_visit_with(visitor));
203+
self.hasher().generic_visit_with(visitor);
204+
}
205+
}
206+
207+
macro_rules! trivial_impls {
208+
( $($ty:ty),* $(,)? ) => {
209+
$(
210+
impl<V>
211+
GenericTypeVisitable<V> for $ty
212+
{
213+
fn generic_visit_with(&self, _visitor: &mut V) {}
214+
}
215+
)*
216+
};
217+
}
218+
219+
trivial_impls!(
220+
(),
221+
rustc_ast_ir::Mutability,
222+
bool,
223+
i8,
224+
i16,
225+
i32,
226+
i64,
227+
i128,
228+
isize,
229+
u8,
230+
u16,
231+
u32,
232+
u64,
233+
u128,
234+
usize,
235+
crate::PredicatePolarity,
236+
crate::BoundConstness,
237+
crate::AliasRelationDirection,
238+
crate::DebruijnIndex,
239+
crate::solve::Certainty,
240+
crate::UniverseIndex,
241+
crate::BoundVar,
242+
crate::InferTy,
243+
crate::IntTy,
244+
crate::UintTy,
245+
crate::FloatTy,
246+
crate::InferConst,
247+
crate::RegionVid,
248+
rustc_hash::FxBuildHasher,
249+
crate::TypeFlags,
250+
crate::solve::GoalSource,
251+
);

0 commit comments

Comments
 (0)