-
Notifications
You must be signed in to change notification settings - Fork 13.4k
TypeFoldable/TypeVisitable tidy up #117896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
d0c9ba3
Derive traversable impls for GenericArgKind
eggyal 674b677
Simplify traversable impls in solver wrapper types
eggyal 3c332fe
Unimpl TypeSuperVisitable for UnevaluatedConst
eggyal e26386f
Enforce ClosureOutlivesSubjectTy not traversable
eggyal d6fcafe
Improve docs of traversable derivation macros
eggyal dce79e4
Unify traversable derive macro implementations
eggyal 35e3019
Inline visiting of GenericArgs
eggyal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -23,8 +23,7 @@ mod newtype; | |||||
mod query; | ||||||
mod serialize; | ||||||
mod symbols; | ||||||
mod type_foldable; | ||||||
mod type_visitable; | ||||||
mod traversable; | ||||||
|
||||||
#[proc_macro] | ||||||
pub fn current_rustc_version(input: TokenStream) -> TokenStream { | ||||||
|
@@ -75,25 +74,62 @@ decl_derive!([TyEncodable] => serialize::type_encodable_derive); | |||||
decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive); | ||||||
decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); | ||||||
decl_derive!( | ||||||
[TypeFoldable, attributes(type_foldable)] => | ||||||
[TypeFoldable, attributes(type_foldable, inline_traversals)] => | ||||||
/// Derives `TypeFoldable` for the annotated `struct` or `enum` (`union` is not supported). | ||||||
/// | ||||||
/// The fold will produce a value of the same struct or enum variant as the input, with | ||||||
/// each field respectively folded using the `TypeFoldable` implementation for its type. | ||||||
/// However, if a field of a struct or an enum variant is annotated with | ||||||
/// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its | ||||||
/// type is not required to implement `TypeFoldable`). | ||||||
type_foldable::type_foldable_derive | ||||||
/// Folds will produce a value of the same struct or enum variant as the input, with each field | ||||||
/// respectively folded (in definition order) using the `TypeFoldable` implementation for its | ||||||
/// type. However, if a field of a struct or of an enum variant is annotated with | ||||||
/// `#[type_foldable(identity)]` then that field will retain its incumbent value (and its type | ||||||
/// is not required to implement `TypeFoldable`). However use of this attribute is dangerous | ||||||
/// and should be used with extreme caution: should the type of the annotated field contain | ||||||
/// (now or in the future) a type that is of interest to a folder, it will not get folded (which | ||||||
/// may result in unexpected, hard-to-track bugs that could result in unsoundness). | ||||||
/// | ||||||
/// If the annotated item has a `'tcx` lifetime parameter, then that will be used as the | ||||||
/// lifetime for the type context/interner; otherwise the lifetime of the type context/interner | ||||||
/// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of | ||||||
/// the annotated type are named. For example, deriving `TypeFoldable` for both `Foo<'a>` and | ||||||
/// `Bar<'tcx>` will respectively produce: | ||||||
/// | ||||||
/// `impl<'a, 'tcx> TypeFoldable<TyCtxt<'tcx>> for Foo<'a>` | ||||||
/// | ||||||
/// and | ||||||
/// | ||||||
/// `impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Bar<'tcx>` | ||||||
/// | ||||||
/// The annotated item may be decorated with an `#[inline_traversals]` attribute to cause the | ||||||
/// generated folding method to be marked `#[inline]`. | ||||||
traversable::traversable_derive::<traversable::Foldable> | ||||||
); | ||||||
decl_derive!( | ||||||
[TypeVisitable, attributes(type_visitable)] => | ||||||
[TypeVisitable, attributes(type_visitable, inline_traversals)] => | ||||||
/// Derives `TypeVisitable` for the annotated `struct` or `enum` (`union` is not supported). | ||||||
/// | ||||||
/// Each field of the struct or enum variant will be visited in definition order, using the | ||||||
/// `TypeVisitable` implementation for its type. However, if a field of a struct or an enum | ||||||
/// variant is annotated with `#[type_visitable(ignore)]` then that field will not be | ||||||
/// visited (and its type is not required to implement `TypeVisitable`). | ||||||
type_visitable::type_visitable_derive | ||||||
/// Each field of the struct or enum variant will be visited (in definition order) using the | ||||||
/// `TypeVisitable` implementation for its type. However, if a field of a struct or of an enum | ||||||
/// variant is annotated with `#[type_visitable(ignore)]` then that field will not be visited | ||||||
/// (and its type is not required to implement `TypeVisitable`). However use of this attribute | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
/// is dangerous and should be used with extreme caution: should the type of the annotated | ||||||
/// field (now or in the future) a type that is of interest to a visitor, it will not get | ||||||
/// visited (which may result in unexpected, hard-to-track bugs that could result in | ||||||
/// unsoundness). | ||||||
/// | ||||||
/// If the annotated item has a `'tcx` lifetime parameter, then that will be used as the | ||||||
/// lifetime for the type context/interner; otherwise the lifetime of the type context/interner | ||||||
/// will be unrelated to the annotated type. It therefore matters how any lifetime parameters of | ||||||
/// the annotated type are named. For example, deriving `TypeVisitable` for both `Foo<'a>` and | ||||||
/// `Bar<'tcx>` will respectively produce: | ||||||
/// | ||||||
/// `impl<'a, 'tcx> TypeVisitable<TyCtxt<'tcx>> for Foo<'a>` | ||||||
/// | ||||||
/// and | ||||||
/// | ||||||
/// `impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Bar<'tcx>` | ||||||
/// | ||||||
/// The annotated item may be decorated with an `#[inline_traversals]` attribute to cause the | ||||||
/// generated folding method to be marked `#[inline]`. | ||||||
traversable::traversable_derive::<traversable::Visitable> | ||||||
); | ||||||
decl_derive!([Lift, attributes(lift)] => lift::lift_derive); | ||||||
decl_derive!( | ||||||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
use proc_macro2::TokenStream; | ||
use quote::{quote, ToTokens}; | ||
use syn::parse_quote; | ||
|
||
pub struct Foldable; | ||
pub struct Visitable; | ||
|
||
/// An abstraction over traversable traits. | ||
pub trait Traversable { | ||
/// The trait that this `Traversable` represents. | ||
fn traversable() -> TokenStream; | ||
|
||
/// The `match` arms for a traversal of this type. | ||
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream; | ||
|
||
/// The body of an implementation given the match `arms`. | ||
fn impl_body(arms: impl ToTokens, attrs: impl ToTokens) -> TokenStream; | ||
} | ||
|
||
impl Traversable for Foldable { | ||
fn traversable() -> TokenStream { | ||
quote! { ::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>> } | ||
} | ||
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream { | ||
structure.each_variant(|vi| { | ||
let bindings = vi.bindings(); | ||
vi.construct(|_, index| { | ||
let bind = &bindings[index]; | ||
|
||
let mut fixed = false; | ||
|
||
// retain value of fields with #[type_foldable(identity)] | ||
bind.ast().attrs.iter().for_each(|x| { | ||
if !x.path().is_ident("type_foldable") { | ||
return; | ||
} | ||
let _ = x.parse_nested_meta(|nested| { | ||
if nested.path.is_ident("identity") { | ||
fixed = true; | ||
} | ||
Ok(()) | ||
}); | ||
}); | ||
|
||
if fixed { | ||
bind.to_token_stream() | ||
} else { | ||
quote! { | ||
::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)? | ||
} | ||
} | ||
}) | ||
}) | ||
} | ||
fn impl_body(arms: impl ToTokens, attrs: impl ToTokens) -> TokenStream { | ||
quote! { | ||
#attrs | ||
fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( | ||
self, | ||
__folder: &mut __F | ||
) -> ::core::result::Result<Self, __F::Error> { | ||
::core::result::Result::Ok(match self { #arms }) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl Traversable for Visitable { | ||
fn traversable() -> TokenStream { | ||
quote! { ::rustc_middle::ty::visit::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>> } | ||
} | ||
fn arms(structure: &mut synstructure::Structure<'_>) -> TokenStream { | ||
// ignore fields with #[type_visitable(ignore)] | ||
structure.filter(|bi| { | ||
let mut ignored = false; | ||
|
||
bi.ast().attrs.iter().for_each(|attr| { | ||
if !attr.path().is_ident("type_visitable") { | ||
return; | ||
} | ||
let _ = attr.parse_nested_meta(|nested| { | ||
if nested.path.is_ident("ignore") { | ||
ignored = true; | ||
} | ||
Ok(()) | ||
}); | ||
}); | ||
|
||
!ignored | ||
}); | ||
|
||
structure.each(|bind| { | ||
quote! { | ||
::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?; | ||
} | ||
}) | ||
} | ||
fn impl_body(arms: impl ToTokens, attrs: impl ToTokens) -> TokenStream { | ||
quote! { | ||
#attrs | ||
fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>( | ||
&self, | ||
__visitor: &mut __V | ||
) -> ::std::ops::ControlFlow<__V::BreakTy> { | ||
match self { #arms } | ||
::std::ops::ControlFlow::Continue(()) | ||
} | ||
} | ||
} | ||
} | ||
|
||
pub fn traversable_derive<T: Traversable>( | ||
mut structure: synstructure::Structure<'_>, | ||
) -> TokenStream { | ||
if let syn::Data::Union(_) = structure.ast().data { | ||
panic!("cannot derive on union") | ||
} | ||
|
||
structure.add_bounds(synstructure::AddBounds::Generics); | ||
structure.bind_with(|_| synstructure::BindStyle::Move); | ||
|
||
if !structure.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | ||
structure.add_impl_generic(parse_quote! { 'tcx }); | ||
} | ||
|
||
let arms = T::arms(&mut structure); | ||
let attrs = structure | ||
.ast() | ||
.attrs | ||
.iter() | ||
.any(|attr| attr.path().is_ident("inline_traversals")) | ||
.then_some(quote! { #[inline] }); | ||
|
||
structure.bound_impl(T::traversable(), T::impl_body(arms, attrs)) | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.