Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b57fd59

Browse files
committedNov 23, 2023
Auto merge of rust-lang#117896 - eggyal:traversables-1-tidy-up, r=<try>
TypeFoldable/TypeVisitable tidy up I'm breaking rust-lang#117726 into more manageable, logical chunks. This is the first of those, and just makes some minor/tidying refactors in preparation for the chunks to follow. r? types
2 parents 38eecca + 35e3019 commit b57fd59

File tree

8 files changed

+202
-184
lines changed

8 files changed

+202
-184
lines changed
 

‎compiler/rustc_macros/src/lib.rs

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ mod lift;
2222
mod query;
2323
mod serialize;
2424
mod symbols;
25-
mod type_foldable;
26-
mod type_visitable;
25+
mod traversable;
2726

2827
// Reads the rust version (e.g. "1.75.0") from the CFG_RELEASE env var and
2928
// produces a `RustcVersion` literal containing that version (e.g.
@@ -63,25 +62,62 @@ decl_derive!([TyEncodable] => serialize::type_encodable_derive);
6362
decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive);
6463
decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive);
6564
decl_derive!(
66-
[TypeFoldable, attributes(type_foldable)] =>
65+
[TypeFoldable, attributes(type_foldable, inline_traversals)] =>
6766
/// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported).
6867
///
69-
/// The fold will produce a value of the same struct or enum variant as the input, with
70-
/// each field respectively folded using the `TypeFoldable` implementation for its type.
71-
/// However, if a field of a struct or an enum variant is annotated with
72-
/// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its
73-
/// type is not required to implement `TypeFoldable`).
74-
type_foldable::type_foldable_derive
68+
/// Folds will produce a value of the same struct or enum variant as the input, with each field
69+
/// respectively folded (in definition order) using the `TypeFoldable` implementation for its
70+
/// type. However, if a field of a struct or of an enum variant is annotated with
71+
/// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its type
72+
/// is not required to implement `TypeFoldable`). However use of this attribute is dangerous
73+
/// and should be used with extreme caution: should the type of the annotated field contain
74+
/// (now or in the future) a type that is of interest to a folder, it will not get folded (which
75+
/// may result in unexpected, hard-to-track bugs that could result in unsoundness).
76+
///
77+
/// If the annotated item has a `'tcx` lifetime parameter, then that will be used as the
78+
/// lifetime for the type context/interner; otherwise the lifetime of the type context/interner
79+
/// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of
80+
/// the annotated type are named. For example, deriving `TypeFoldable` for both `Foo<'a>` and
81+
/// `Bar<'tcx>` will respectively produce:
82+
///
83+
/// `impl<'a, 'tcx> TypeFoldable<TyCtxt<'tcx>> for Foo<'a>`
84+
///
85+
/// and
86+
///
87+
/// `impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Bar<'tcx>`
88+
///
89+
/// The annotated item may be decorated with an `#[inline_traversals]` attribute to cause the
90+
/// generated folding method to be marked `#[inline]`.
91+
traversable::traversable_derive::<traversable::Foldable>
7592
);
7693
decl_derive!(
77-
[TypeVisitable, attributes(type_visitable)] =>
94+
[TypeVisitable, attributes(type_visitable, inline_traversals)] =>
7895
/// Derives `TypeVisitable` for the annotated `struct` or `enum` (`union` is not supported).
7996
///
80-
/// Each field of the struct or enum variant will be visited in definition order, using the
81-
/// `TypeVisitable` implementation for its type. However, if a field of a struct or an enum
82-
/// variant is annotated with `#[type_visitable(ignore)]` then that field will not be
83-
/// visited (and its type is not required to implement `TypeVisitable`).
84-
type_visitable::type_visitable_derive
97+
/// Each field of the struct or enum variant will be visited (in definition order) using the
98+
/// `TypeVisitable` implementation for its type. However, if a field of a struct or of an enum
99+
/// variant is annotated with `#[type_visitable(ignore)]` then that field will not be visited
100+
/// (and its type is not required to implement `TypeVisitable`). However use of this attribute
101+
/// is dangerous and should be used with extreme caution: should the type of the annotated
102+
/// field (now or in the future) a type that is of interest to a visitor, it will not get
103+
/// visited (which may result in unexpected, hard-to-track bugs that could result in
104+
/// unsoundness).
105+
///
106+
/// If the annotated item has a `'tcx` lifetime parameter, then that will be used as the
107+
/// lifetime for the type context/interner; otherwise the lifetime of the type context/interner
108+
/// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of
109+
/// the annotated type are named. For example, deriving `TypeVisitable` for both `Foo<'a>` and
110+
/// `Bar<'tcx>` will respectively produce:
111+
///
112+
/// `impl<'a, 'tcx> TypeVisitable<TyCtxt<'tcx>> for Foo<'a>`
113+
///
114+
/// and
115+
///
116+
/// `impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Bar<'tcx>`
117+
///
118+
/// The annotated item may be decorated with an `#[inline_traversals]` attribute to cause the
119+
/// generated folding method to be marked `#[inline]`.
120+
traversable::traversable_derive::<traversable::Visitable>
85121
);
86122
decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
87123
decl_derive!(
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use proc_macro2::TokenStream;
2+
use quote::{quote, ToTokens};
3+
use syn::parse_quote;
4+
5+
pub struct Foldable;
6+
pub struct Visitable;
7+
8+
/// An abstraction over traversable traits.
9+
pub trait Traversable {
10+
/// The trait that this `Traversable` represents.
11+
fn traversable() -> TokenStream;
12+
13+
/// The `match` arms for a traversal of this type.
14+
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream;
15+
16+
/// The body of an implementation given the match `arms`.
17+
fn impl_body(arms: impl ToTokens, attrs: impl ToTokens) -> TokenStream;
18+
}
19+
20+
impl Traversable for Foldable {
21+
fn traversable() -> TokenStream {
22+
quote! { ::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>> }
23+
}
24+
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream {
25+
structure.each_variant(|vi| {
26+
let bindings = vi.bindings();
27+
vi.construct(|_, index| {
28+
let bind = &bindings[index];
29+
30+
let mut fixed = false;
31+
32+
// retain value of fields with #[type_foldable(identity)]
33+
bind.ast().attrs.iter().for_each(|x| {
34+
if !x.path().is_ident("type_foldable") {
35+
return;
36+
}
37+
let _ = x.parse_nested_meta(|nested| {
38+
if nested.path.is_ident("identity") {
39+
fixed = true;
40+
}
41+
Ok(())
42+
});
43+
});
44+
45+
if fixed {
46+
bind.to_token_stream()
47+
} else {
48+
quote! {
49+
::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)?
50+
}
51+
}
52+
})
53+
})
54+
}
55+
fn impl_body(arms: impl ToTokens, attrs: impl ToTokens) -> TokenStream {
56+
quote! {
57+
#attrs
58+
fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(
59+
self,
60+
__folder: &mut __F
61+
) -> ::core::result::Result<Self, __F::Error> {
62+
::core::result::Result::Ok(match self { #arms })
63+
}
64+
}
65+
}
66+
}
67+
68+
impl Traversable for Visitable {
69+
fn traversable() -> TokenStream {
70+
quote! { ::rustc_middle::ty::visit::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>> }
71+
}
72+
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream {
73+
// ignore fields with #[type_visitable(ignore)]
74+
structure.filter(|bi| {
75+
let mut ignored = false;
76+
77+
bi.ast().attrs.iter().for_each(|attr| {
78+
if !attr.path().is_ident("type_visitable") {
79+
return;
80+
}
81+
let _ = attr.parse_nested_meta(|nested| {
82+
if nested.path.is_ident("ignore") {
83+
ignored = true;
84+
}
85+
Ok(())
86+
});
87+
});
88+
89+
!ignored
90+
});
91+
92+
structure.each(|bind| {
93+
quote! {
94+
::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?;
95+
}
96+
})
97+
}
98+
fn impl_body(arms: impl ToTokens, attrs: impl ToTokens) -> TokenStream {
99+
quote! {
100+
#attrs
101+
fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(
102+
&self,
103+
__visitor: &mut __V
104+
) -> ::std::ops::ControlFlow<__V::BreakTy> {
105+
match self { #arms }
106+
::std::ops::ControlFlow::Continue(())
107+
}
108+
}
109+
}
110+
}
111+
112+
pub fn traversable_derive<T: Traversable>(
113+
mut structure: synstructure::Structure<'_>,
114+
) -> TokenStream {
115+
if let syn::Data::Union(_) = structure.ast().data {
116+
panic!("cannot derive on union")
117+
}
118+
119+
structure.add_bounds(synstructure::AddBounds::Generics);
120+
structure.bind_with(|_| synstructure::BindStyle::Move);
121+
122+
if !structure.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
123+
structure.add_impl_generic(parse_quote! { 'tcx });
124+
}
125+
126+
let arms = T::arms(&mut structure);
127+
let attrs = structure
128+
.ast()
129+
.attrs
130+
.iter()
131+
.any(|attr| attr.path().is_ident("inline_traversals"))
132+
.then_some(quote! { #[inline] });
133+
134+
structure.bound_impl(T::traversable(), T::impl_body(arms, attrs))
135+
}

‎compiler/rustc_macros/src/type_foldable.rs

Lines changed: 0 additions & 56 deletions
This file was deleted.

‎compiler/rustc_macros/src/type_visitable.rs

Lines changed: 0 additions & 52 deletions
This file was deleted.

‎compiler/rustc_middle/src/mir/query.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -406,14 +406,16 @@ pub enum ClosureOutlivesSubject<'tcx> {
406406
/// This abstraction is necessary because the type may include `ReVar` regions,
407407
/// which is what we use internally within NLL code, and they can't be used in
408408
/// a query response.
409-
///
410-
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
411-
/// type is not recognized as a binder for late-bound region.
412409
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
413410
pub struct ClosureOutlivesSubjectTy<'tcx> {
414411
inner: Ty<'tcx>,
415412
}
416413

414+
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
415+
/// type is not recognized as a binder for late-bound region.
416+
impl<'tcx, I> !ty::TypeFoldable<I> for ClosureOutlivesSubjectTy<'tcx> {}
417+
impl<'tcx, I> !ty::TypeVisitable<I> for ClosureOutlivesSubjectTy<'tcx> {}
418+
417419
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
418420
/// All regions of `ty` must be of kind `ReVar` and must represent
419421
/// universal regions *external* to the closure.

‎compiler/rustc_middle/src/traits/solve.rs

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
use std::ops::ControlFlow;
2-
31
use rustc_data_structures::intern::Interned;
42

53
use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
64
use crate::traits::query::NoSolution;
75
use crate::traits::{Canonical, DefiningAnchor};
86
use crate::ty::{
9-
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
10-
TypeVisitor,
7+
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor,
118
};
129
use rustc_span::def_id::DefId;
1310

@@ -110,7 +107,7 @@ pub struct QueryInput<'tcx, T> {
110107
}
111108

112109
/// Additional constraints returned on success.
113-
#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
110+
#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)]
114111
pub struct PredefinedOpaquesData<'tcx> {
115112
pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
116113
}
@@ -167,21 +164,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
167164
self,
168165
folder: &mut F,
169166
) -> Result<Self, F::Error> {
170-
Ok(FallibleTypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData {
171-
region_constraints: self.region_constraints.clone().try_fold_with(folder)?,
172-
opaque_types: self
173-
.opaque_types
174-
.iter()
175-
.map(|opaque| opaque.try_fold_with(folder))
176-
.collect::<Result<_, F::Error>>()?,
177-
}))
178-
}
179-
180-
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
181-
TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData {
182-
region_constraints: self.region_constraints.clone().fold_with(folder),
183-
opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
184-
})
167+
Ok(folder.interner().mk_external_constraints((*self).clone().try_fold_with(folder)?))
185168
}
186169
}
187170

@@ -190,9 +173,7 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
190173
&self,
191174
visitor: &mut V,
192175
) -> std::ops::ControlFlow<V::BreakTy> {
193-
self.region_constraints.visit_with(visitor)?;
194-
self.opaque_types.visit_with(visitor)?;
195-
ControlFlow::Continue(())
176+
(**self).visit_with(visitor)
196177
}
197178
}
198179

@@ -206,21 +187,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
206187
self,
207188
folder: &mut F,
208189
) -> Result<Self, F::Error> {
209-
Ok(FallibleTypeFolder::interner(folder).mk_predefined_opaques_in_body(
210-
PredefinedOpaquesData {
211-
opaque_types: self
212-
.opaque_types
213-
.iter()
214-
.map(|opaque| opaque.try_fold_with(folder))
215-
.collect::<Result<_, F::Error>>()?,
216-
},
217-
))
218-
}
219-
220-
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
221-
TypeFolder::interner(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData {
222-
opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
223-
})
190+
Ok(folder.interner().mk_predefined_opaques_in_body((*self).clone().try_fold_with(folder)?))
224191
}
225192
}
226193

@@ -229,7 +196,7 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
229196
&self,
230197
visitor: &mut V,
231198
) -> std::ops::ControlFlow<V::BreakTy> {
232-
self.opaque_types.visit_with(visitor)
199+
(**self).visit_with(visitor)
233200
}
234201
}
235202

‎compiler/rustc_middle/src/ty/generic_args.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ const REGION_TAG: usize = 0b01;
4747
const CONST_TAG: usize = 0b10;
4848

4949
#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)]
50+
#[derive(Clone, TypeFoldable, TypeVisitable)]
51+
#[inline_traversals]
5052
pub enum GenericArgKind<'tcx> {
5153
Lifetime(ty::Region<'tcx>),
5254
Type(Ty<'tcx>),
@@ -210,21 +212,14 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for GenericArg<'tcx> {
210212
self,
211213
folder: &mut F,
212214
) -> Result<Self, F::Error> {
213-
match self.unpack() {
214-
GenericArgKind::Lifetime(lt) => lt.try_fold_with(folder).map(Into::into),
215-
GenericArgKind::Type(ty) => ty.try_fold_with(folder).map(Into::into),
216-
GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
217-
}
215+
self.unpack().try_fold_with(folder).map(GenericArgKind::pack)
218216
}
219217
}
220218

221219
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for GenericArg<'tcx> {
220+
#[inline]
222221
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
223-
match self.unpack() {
224-
GenericArgKind::Lifetime(lt) => lt.visit_with(visitor),
225-
GenericArgKind::Type(ty) => ty.visit_with(visitor),
226-
GenericArgKind::Const(ct) => ct.visit_with(visitor),
227-
}
222+
self.unpack().visit_with(visitor)
228223
}
229224
}
230225

‎compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -801,15 +801,6 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst {
801801
}
802802
}
803803

804-
impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
805-
fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
806-
&self,
807-
visitor: &mut V,
808-
) -> ControlFlow<V::BreakTy> {
809-
self.args.visit_with(visitor)
810-
}
811-
}
812-
813804
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for TyAndLayout<'tcx, Ty<'tcx>> {
814805
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
815806
visitor.visit_ty(self.ty)

0 commit comments

Comments
 (0)
This repository has been archived.