1- use quote:: quote;
2- use syn:: parse_quote;
1+ use quote:: { ToTokens , quote} ;
32use syn:: visit_mut:: VisitMut ;
3+ use syn:: { Attribute , parse_quote} ;
44use synstructure:: decl_derive;
55
66decl_derive ! (
7- [ TypeFoldable_Generic ] => type_foldable_derive
7+ [ TypeVisitable_Generic , attributes ( type_visitable ) ] => type_visitable_derive
88) ;
99decl_derive ! (
10- [ TypeVisitable_Generic ] => type_visitable_derive
10+ [ TypeFoldable_Generic , attributes ( type_foldable ) ] => type_foldable_derive
1111) ;
1212decl_derive ! (
1313 [ Lift_Generic ] => lift_derive
1414) ;
1515
16+ fn has_ignore_attr ( attrs : & [ Attribute ] , name : & ' static str , meta : & ' static str ) -> bool {
17+ let mut ignored = false ;
18+ attrs. iter ( ) . for_each ( |attr| {
19+ if !attr. path ( ) . is_ident ( name) {
20+ return ;
21+ }
22+ let _ = attr. parse_nested_meta ( |nested| {
23+ if nested. path . is_ident ( meta) {
24+ ignored = true ;
25+ }
26+ Ok ( ( ) )
27+ } ) ;
28+ } ) ;
29+
30+ ignored
31+ }
32+
33+ fn type_visitable_derive ( mut s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
34+ if let syn:: Data :: Union ( _) = s. ast ( ) . data {
35+ panic ! ( "cannot derive on union" )
36+ }
37+
38+ if !s. ast ( ) . generics . type_params ( ) . any ( |ty| ty. ident == "I" ) {
39+ s. add_impl_generic ( parse_quote ! { I } ) ;
40+ }
41+
42+ s. filter ( |bi| !has_ignore_attr ( & bi. ast ( ) . attrs , "type_visitable" , "ignore" ) ) ;
43+
44+ s. add_where_predicate ( parse_quote ! { I : Interner } ) ;
45+ s. add_bounds ( synstructure:: AddBounds :: Fields ) ;
46+ let body_visit = s. each ( |bind| {
47+ quote ! {
48+ match :: rustc_ast_ir:: visit:: VisitorResult :: branch(
49+ :: rustc_type_ir:: visit:: TypeVisitable :: visit_with( #bind, __visitor)
50+ ) {
51+ :: core:: ops:: ControlFlow :: Continue ( ( ) ) => { } ,
52+ :: core:: ops:: ControlFlow :: Break ( r) => {
53+ return :: rustc_ast_ir:: visit:: VisitorResult :: from_residual( r) ;
54+ } ,
55+ }
56+ }
57+ } ) ;
58+ s. bind_with ( |_| synstructure:: BindStyle :: Move ) ;
59+
60+ s. bound_impl ( quote ! ( :: rustc_type_ir:: visit:: TypeVisitable <I >) , quote ! {
61+ fn visit_with<__V: :: rustc_type_ir:: visit:: TypeVisitor <I >>(
62+ & self ,
63+ __visitor: & mut __V
64+ ) -> __V:: Result {
65+ match * self { #body_visit }
66+ <__V:: Result as :: rustc_ast_ir:: visit:: VisitorResult >:: output( )
67+ }
68+ } )
69+ }
70+
1671fn type_foldable_derive ( mut s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
1772 if let syn:: Data :: Union ( _) = s. ast ( ) . data {
1873 panic ! ( "cannot derive on union" )
@@ -29,12 +84,23 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
2984 let bindings = vi. bindings ( ) ;
3085 vi. construct ( |_, index| {
3186 let bind = & bindings[ index] ;
32- quote ! {
33- :: rustc_type_ir:: fold:: TypeFoldable :: try_fold_with( #bind, __folder) ?
87+
88+ // retain value of fields with #[type_foldable(identity)]
89+ if has_ignore_attr ( & bind. ast ( ) . attrs , "type_foldable" , "identity" ) {
90+ bind. to_token_stream ( )
91+ } else {
92+ quote ! {
93+ :: rustc_type_ir:: fold:: TypeFoldable :: try_fold_with( #bind, __folder) ?
94+ }
3495 }
3596 } )
3697 } ) ;
3798
99+ // We filter fields which get ignored and don't require them to implement
100+ // `TypeFoldable`. We do so after generating `body_fold` as we still need
101+ // to generate code for them.
102+ s. filter ( |bi| !has_ignore_attr ( & bi. ast ( ) . attrs , "type_foldable" , "identity" ) ) ;
103+ s. add_bounds ( synstructure:: AddBounds :: Fields ) ;
38104 s. bound_impl ( quote ! ( :: rustc_type_ir:: fold:: TypeFoldable <I >) , quote ! {
39105 fn try_fold_with<__F: :: rustc_type_ir:: fold:: FallibleTypeFolder <I >>(
40106 self ,
@@ -113,39 +179,3 @@ fn lift(mut ty: syn::Type) -> syn::Type {
113179
114180 ty
115181}
116-
117- fn type_visitable_derive ( mut s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
118- if let syn:: Data :: Union ( _) = s. ast ( ) . data {
119- panic ! ( "cannot derive on union" )
120- }
121-
122- if !s. ast ( ) . generics . type_params ( ) . any ( |ty| ty. ident == "I" ) {
123- s. add_impl_generic ( parse_quote ! { I } ) ;
124- }
125-
126- s. add_where_predicate ( parse_quote ! { I : Interner } ) ;
127- s. add_bounds ( synstructure:: AddBounds :: Fields ) ;
128- let body_visit = s. each ( |bind| {
129- quote ! {
130- match :: rustc_ast_ir:: visit:: VisitorResult :: branch(
131- :: rustc_type_ir:: visit:: TypeVisitable :: visit_with( #bind, __visitor)
132- ) {
133- :: core:: ops:: ControlFlow :: Continue ( ( ) ) => { } ,
134- :: core:: ops:: ControlFlow :: Break ( r) => {
135- return :: rustc_ast_ir:: visit:: VisitorResult :: from_residual( r) ;
136- } ,
137- }
138- }
139- } ) ;
140- s. bind_with ( |_| synstructure:: BindStyle :: Move ) ;
141-
142- s. bound_impl ( quote ! ( :: rustc_type_ir:: visit:: TypeVisitable <I >) , quote ! {
143- fn visit_with<__V: :: rustc_type_ir:: visit:: TypeVisitor <I >>(
144- & self ,
145- __visitor: & mut __V
146- ) -> __V:: Result {
147- match * self { #body_visit }
148- <__V:: Result as :: rustc_ast_ir:: visit:: VisitorResult >:: output( )
149- }
150- } )
151- }
0 commit comments