@@ -16,9 +16,7 @@ use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
1616use quote:: quote;
1717use syn:: {
1818 parse:: { Parse , ParseStream , Parser as _} ,
19- parse_macro_input,
20- punctuated:: Punctuated ,
21- Expr , ExprCall , Pat , Token ,
19+ parse_macro_input, Expr , ExprCall , Pat , Token ,
2220} ;
2321
2422/// This is an implementation detail of `googletest::matches_pattern!`. It
@@ -164,22 +162,46 @@ fn parse_tuple_pattern_args(
164162 struct_name : TokenStream ,
165163 group_content : TokenStream ,
166164) -> syn:: Result < TokenStream > {
167- let parser = Punctuated :: < MaybeTupleFieldPattern , Token ! [ , ] > :: parse_terminated;
168- let fields = parser
169- . parse2 ( group_content) ?
165+ let ( patterns, non_exhaustive) =
166+ parse_list_terminated_pattern :: < MaybeTupleFieldPattern > . parse2 ( group_content) ?;
167+ let field_count = patterns. len ( ) ;
168+ let field_patterns = patterns
170169 . into_iter ( )
171170 . enumerate ( )
172171 . filter_map ( |( index, maybe_pattern) | maybe_pattern. 0 . map ( |pattern| ( index, pattern) ) )
173172 . map ( |( index, TupleFieldPattern { ref_token, matcher } ) | {
174173 let index = syn:: Index :: from ( index) ;
175174 quote ! { googletest:: matchers:: field!( #struct_name. #index, #ref_token #matcher) }
176175 } ) ;
177- Ok ( quote ! {
176+
177+ let matcher = quote ! {
178178 googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: is(
179179 stringify!( #struct_name) ,
180- all!( #( #fields ) , * )
180+ all!( #( #field_patterns ) , * )
181181 )
182- } )
182+ } ;
183+
184+ // Do an exhaustiveness check only if the pattern doesn't end with `..`.
185+ if non_exhaustive {
186+ Ok ( matcher)
187+ } else {
188+ let empty_fields = std:: iter:: repeat ( quote ! { _ } ) . take ( field_count) ;
189+ Ok ( quote ! {
190+ googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: compile_assert_and_match(
191+ |actual| {
192+ // Exhaustively check that all field names are specified.
193+ match actual {
194+ #struct_name ( #( #empty_fields) , * ) => ( ) ,
195+ // The pattern below is unreachable if the type is a struct (as opposed to
196+ // an enum). Since the macro can't know which it is, we always include it
197+ // and just tell the compiler not to complain.
198+ #[ allow( unreachable_patterns) ]
199+ _ => { } ,
200+ }
201+ } ,
202+ #matcher)
203+ } )
204+ }
183205}
184206
185207////////////////////////////////////////////////////////////////////////////////
@@ -257,6 +279,13 @@ fn parse_braced_pattern_args(
257279 } )
258280 . collect ( ) ;
259281
282+ let matcher = quote ! {
283+ googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: is(
284+ stringify!( #struct_name) ,
285+ all!( #( #field_patterns) , * )
286+ )
287+ } ;
288+
260289 // Do an exhaustiveness check only if the pattern doesn't end with `..` and has
261290 // any fields in the pattern. This latter part is required because
262291 // `matches_pattern!` also uses the brace notation for tuple structs when
@@ -268,36 +297,25 @@ fn parse_braced_pattern_args(
268297 // matches_pattern!(foo, Struct { bar(): eq(1) })
269298 // ```
270299 // and we can't emit an exhaustiveness check based on the `matches_pattern!`.
271- let maybe_assert_exhaustive = if non_exhaustive || field_names. is_empty ( ) {
272- None
300+ if non_exhaustive || field_names. is_empty ( ) {
301+ Ok ( matcher )
273302 } else {
274- // Note that `struct_name` might be an enum variant (`Enum::Foo`), which is not
275- // a valid type. So we need to infer the type, produce an instance, and match on
276- // it. Fortunately, `[_; 0]` can be trivially initialized to `[]` and can
277- // produce an instance by indexing into it without failing compilation.
278- Some ( quote ! {
279- fn __matches_pattern_ensure_exhastive_match( i: usize ) {
280- let val: [ _; 0 ] = [ ] ;
281- let _ = match val[ i] {
282- #struct_name { #( #field_names: _) , * } => ( ) ,
283- // The pattern below is unreachable if the type is a struct (as opposed to an
284- // enum). Since the macro can't know which it is, we always include it and just
285- // tell the compiler not to complain.
286- #[ allow( unreachable_patterns) ]
287- _ => ( ) ,
288- } ;
289- }
303+ Ok ( quote ! {
304+ googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: compile_assert_and_match(
305+ |actual| {
306+ // Exhaustively check that all field names are specified.
307+ match actual {
308+ #struct_name { #( #field_names: _) , * } => { } ,
309+ // The pattern below is unreachable if the type is a struct (as opposed to
310+ // an enum). Since the macro can't know which it is, we always include it
311+ // and just tell the compiler not to complain.
312+ #[ allow( unreachable_patterns) ]
313+ _ => { } ,
314+ }
315+ } ,
316+ #matcher)
290317 } )
291- } ;
292-
293- Ok ( quote ! {
294- googletest:: matchers:: __internal_unstable_do_not_depend_on_these:: is(
295- stringify!( #struct_name) , {
296- #maybe_assert_exhaustive
297- all!( #( #field_patterns) , * )
298- }
299- )
300- } )
318+ }
301319}
302320
303321////////////////////////////////////////////////////////////////////////////////
0 commit comments