@@ -167,43 +167,70 @@ fn parse_tuple_pattern_args(
167167 let ( patterns, dot_dot) =
168168 parse_list_terminated_pattern :: < MaybeTupleFieldPattern > . parse2 ( group_content) ?;
169169 let field_count = patterns. len ( ) ;
170- let field_patterns = patterns
170+ let field_patterns: Vec < _ > = patterns
171171 . into_iter ( )
172172 . enumerate ( )
173173 . filter_map ( |( index, maybe_pattern) | maybe_pattern. 0 . map ( |pattern| ( index, pattern) ) )
174174 . map ( |( index, TupleFieldPattern { ref_token, matcher } ) | {
175175 let index = syn:: Index :: from ( index) ;
176176 quote ! { googletest:: matchers:: field!( #struct_name. #index, #ref_token #matcher) }
177- } ) ;
177+ } )
178+ . collect ( ) ;
178179
179- let matcher = quote ! {
180- googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: is(
181- stringify!( #struct_name) ,
182- all!( #( #field_patterns) , * )
183- )
184- } ;
180+ if field_patterns. is_empty ( ) {
181+ // It is possible that the logic above didn't generate any field matchers
182+ // (e.g., for patterns like `Some(_)`).
183+ // In this case we verify that the enum has the correct case, but don't
184+ // verify the payload.
185+ #[ allow( clippy:: manual_repeat_n) ]
186+ // `repeat_n` is not available on the Rust MSRV that we support in OSS
187+ let ignored_fields = std:: iter:: repeat ( quote ! { _ } )
188+ . take ( field_count)
189+ . chain ( dot_dot. map ( ToTokens :: into_token_stream) ) ;
190+ let full_pattern = quote ! { #struct_name ( #( #ignored_fields) , * ) } ;
185191
186- // Do a match to ensure:
187- // - Fields are exhaustively listed unless the pattern ended with `..`.
188- // - `UNDEFINED_SYMBOL(..)` fails to compile.
189- let empty_fields = std:: iter:: repeat ( quote ! { _ } )
190- . take ( field_count)
191- . chain ( dot_dot. map ( ToTokens :: into_token_stream) ) ;
192- Ok ( quote ! {
193- googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: compile_assert_and_match(
194- |actual| {
195- // Exhaustively check that all field names are specified.
196- match actual {
197- #struct_name ( #( #empty_fields) , * ) => ( ) ,
198- // The pattern below is unreachable if the type is a struct (as opposed to
199- // an enum). Since the macro can't know which it is, we always include it
200- // and just tell the compiler not to complain.
201- #[ allow( unreachable_patterns) ]
202- _ => { } ,
203- }
204- } ,
205- #matcher)
206- } )
192+ Ok ( quote ! {
193+ googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: pattern_only(
194+ |actual| { matches!( actual, #full_pattern) } ,
195+ concat!( "is " , stringify!( #full_pattern) ) ,
196+ concat!( "is not " , stringify!( #full_pattern) )
197+ )
198+ } )
199+ } else {
200+ // We have created at least one field matcher. Each field matcher will verify
201+ // not only its part of the payload, but also that the enum has the
202+ // correct case.
203+ let matcher = quote ! {
204+ googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: is(
205+ stringify!( #struct_name) ,
206+ all!( #( #field_patterns) , * )
207+ )
208+ } ;
209+
210+ // Do a match to ensure:
211+ // - Fields are exhaustively listed unless the pattern ended with `..`.
212+ // - `UNDEFINED_SYMBOL(..)` fails to compile.
213+ #[ allow( clippy:: manual_repeat_n) ]
214+ // `repeat_n` is not available on the Rust MSRV that we support in OSS
215+ let empty_fields = std:: iter:: repeat ( quote ! { _ } )
216+ . take ( field_count)
217+ . chain ( dot_dot. map ( ToTokens :: into_token_stream) ) ;
218+ Ok ( quote ! {
219+ googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: compile_assert_and_match(
220+ |actual| {
221+ // Exhaustively check that all field names are specified.
222+ match actual {
223+ #struct_name ( #( #empty_fields) , * ) => ( ) ,
224+ // The pattern below is unreachable if the type is a struct (as opposed to
225+ // an enum). Since the macro can't know which it is, we always include it
226+ // and just tell the compiler not to complain.
227+ #[ allow( unreachable_patterns) ]
228+ _ => { } ,
229+ }
230+ } ,
231+ #matcher)
232+ } )
233+ }
207234}
208235
209236////////////////////////////////////////////////////////////////////////////////
0 commit comments