Skip to content

Commit

Permalink
Make matches_pattern support _ at the top level in tuple structs.
Browse files Browse the repository at this point in the history
This change is not backward-compatible since:
* Some things that previously fell back to `match` pattern matching now use `match_pattern!`'s specialized matching, which requires the matched object to implement `Debug`.

Toward #447

PiperOrigin-RevId: 700889703
  • Loading branch information
marcianx authored and copybara-github committed Nov 28, 2024
1 parent 16e975d commit 0f21a82
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 29 deletions.
21 changes: 12 additions & 9 deletions googletest/tests/matches_pattern_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,18 @@ fn matches_tuple_struct_with_two_fields_and_trailing_comma() -> Result<()> {
)
}

#[test]
fn matches_tuple_struct_with_interleaved_underscore() -> Result<()> {
#[derive(Debug)]
struct NonCopy;
#[derive(Debug)]
struct AStruct(u32, NonCopy, u32);
let actual = AStruct(1, NonCopy, 3);

verify_that!(actual, matches_pattern!(&AStruct(eq(1), _, eq(3))))?;
verify_that!(actual, matches_pattern!(AStruct(eq(&1), _, eq(&3))))
}

#[test]
fn matches_enum_without_field() -> Result<()> {
#[derive(Debug)]
Expand Down Expand Up @@ -501,15 +513,6 @@ fn matches_match_pattern_struct() -> Result<()> {
verify_that!(actual, matches_pattern!(AStruct { .. }))
}

#[test]
fn matches_match_pattern_tuple() -> Result<()> {
#[allow(dead_code)]
#[derive(Debug)]
struct AStruct(u32);
let actual = AStruct(123);
verify_that!(actual, matches_pattern!(AStruct(_)))
}

#[test]
fn generates_correct_failure_output_when_enum_variant_without_field_is_not_matched() -> Result<()> {
#[derive(Debug)]
Expand Down
37 changes: 17 additions & 20 deletions googletest_macro/src/matches_pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use syn::{
parse::{Parse, ParseStream, Parser as _},
parse_macro_input,
punctuated::Punctuated,
Expr, ExprCall, ExprInfer, Pat, Token,
Expr, ExprCall, Pat, Token,
};

/// This is an implementation detail of `googletest::matches_pattern!`. It
Expand Down Expand Up @@ -147,21 +147,15 @@ struct TupleFieldPattern {
matcher: Expr,
}

impl Parse for TupleFieldPattern {
struct MaybeTupleFieldPattern(Option<TupleFieldPattern>);

impl Parse for MaybeTupleFieldPattern {
fn parse(input: ParseStream) -> syn::Result<Self> {
let ref_token = input.parse()?;
let matcher = input.parse()?;
match matcher {
// `_` is an expr in const generics contexts, but is not supported in regular
// `Expr` use like in the `matches_pattern` custom syntax. So fail in that case.
// That should allow `into_match_expr` above to fall back to `into_match_pattern_expr`
// and still attempt to parse `matcher` as a pattern.
Expr::Infer(ExprInfer { underscore_token, .. }) => compile_err(
underscore_token.spans[0],
"unexpected `_` for `matches_pattern!` tuple field matcher",
),
_ => Ok(TupleFieldPattern { ref_token, matcher }),
}
let pattern = match input.parse::<Option<Token![_]>>()? {
Some(_) => None,
None => Some(TupleFieldPattern { ref_token: input.parse()?, matcher: input.parse()? }),
};
Ok(MaybeTupleFieldPattern(pattern))
}
}

Expand All @@ -170,13 +164,16 @@ fn parse_tuple_pattern_args(
struct_name: TokenStream,
group_content: TokenStream,
) -> syn::Result<TokenStream> {
let parser = Punctuated::<TupleFieldPattern, Token![,]>::parse_terminated;
let fields = parser.parse2(group_content)?.into_iter().enumerate().map(
|(index, TupleFieldPattern { ref_token, matcher })| {
let parser = Punctuated::<MaybeTupleFieldPattern, Token![,]>::parse_terminated;
let fields = parser
.parse2(group_content)?
.into_iter()
.enumerate()
.filter_map(|(index, maybe_pattern)| maybe_pattern.0.map(|pattern| (index, pattern)))
.map(|(index, TupleFieldPattern { ref_token, matcher })| {
let index = syn::Index::from(index);
quote! { googletest::matchers::field!(#struct_name.#index, #ref_token #matcher) }
},
);
});
Ok(quote! {
googletest::matchers::__internal_unstable_do_not_depend_on_these::is(
stringify!(#struct_name),
Expand Down

0 comments on commit 0f21a82

Please sign in to comment.