1
- use quote:: quote;
2
- use syn:: parse_quote;
1
+ use quote:: { ToTokens , quote} ;
3
2
use syn:: visit_mut:: VisitMut ;
3
+ use syn:: { Attribute , parse_quote} ;
4
4
use synstructure:: decl_derive;
5
5
6
6
decl_derive ! (
7
- [ TypeFoldable_Generic ] => type_foldable_derive
7
+ [ TypeVisitable_Generic , attributes ( type_visitable ) ] => type_visitable_derive
8
8
) ;
9
9
decl_derive ! (
10
- [ TypeVisitable_Generic ] => type_visitable_derive
10
+ [ TypeFoldable_Generic , attributes ( type_foldable ) ] => type_foldable_derive
11
11
) ;
12
12
decl_derive ! (
13
13
[ Lift_Generic ] => lift_derive
14
14
) ;
15
15
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
+
16
71
fn type_foldable_derive ( mut s : synstructure:: Structure < ' _ > ) -> proc_macro2:: TokenStream {
17
72
if let syn:: Data :: Union ( _) = s. ast ( ) . data {
18
73
panic ! ( "cannot derive on union" )
@@ -29,12 +84,23 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
29
84
let bindings = vi. bindings ( ) ;
30
85
vi. construct ( |_, index| {
31
86
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
+ }
34
95
}
35
96
} )
36
97
} ) ;
37
98
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 ) ;
38
104
s. bound_impl ( quote ! ( :: rustc_type_ir:: fold:: TypeFoldable <I >) , quote ! {
39
105
fn try_fold_with<__F: :: rustc_type_ir:: fold:: FallibleTypeFolder <I >>(
40
106
self ,
@@ -113,39 +179,3 @@ fn lift(mut ty: syn::Type) -> syn::Type {
113
179
114
180
ty
115
181
}
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