diff --git a/impl/src/attr.rs b/impl/src/attr.rs index 7ad83e0..cd2d5f6 100644 --- a/impl/src/attr.rs +++ b/impl/src/attr.rs @@ -4,8 +4,8 @@ use std::collections::BTreeSet as Set; use syn::parse::discouraged::Speculative; use syn::parse::{End, ParseStream}; use syn::{ - braced, bracketed, parenthesized, token, Attribute, Error, ExprPath, Ident, Index, LitFloat, - LitInt, LitStr, Meta, Result, Token, + braced, bracketed, parenthesized, token, Attribute, Error, Expr, ExprPath, Ident, Index, + LitFloat, LitInt, LitStr, Meta, Result, Token, }; pub struct Attrs<'a> { @@ -205,18 +205,22 @@ fn parse_token_expr(input: ParseStream, mut begin_expr: bool) -> Result()?; - begin_expr = false; - continue; + if !is_expr_prefix(&tokens) { + input.parse::()?; + begin_expr = false; + continue; + } } else if input.peek2(LitInt) { - input.parse::()?; - let int: Index = input.parse()?; - tokens.push({ - let ident = format_ident!("_{}", int.index, span = int.span); - TokenTree::Ident(ident) - }); - begin_expr = false; - continue; + if !is_expr_prefix(&tokens) { + input.parse::()?; + let int: Index = input.parse()?; + tokens.push({ + let ident = format_ident!("_{}", int.index, span = int.span); + TokenTree::Ident(ident) + }); + begin_expr = false; + continue; + } } else if input.peek2(LitFloat) { let ahead = input.fork(); ahead.parse::()?; @@ -299,6 +303,22 @@ fn parse_token_expr(input: ParseStream, mut begin_expr: bool) -> Result bool { + let mut start = 0; + loop { + if syn::parse2::(TokenStream::from_iter(tokens[start..].iter().cloned())).is_ok() { + return true; + } + let Some(offset) = tokens[start..] + .iter() + .position(|token| matches!(token, TokenTree::Punct(punct) if punct.as_char() == ',')) + else { + return false; + }; + start += offset + 1; + } +} + impl ToTokens for Display<'_> { fn to_tokens(&self, tokens: &mut TokenStream) { if self.infinite_recursive { diff --git a/tests/test_issue332.rs b/tests/test_issue332.rs new file mode 100644 index 0000000..d8b8f31 --- /dev/null +++ b/tests/test_issue332.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +#[error("{}", None::.is_some())] +struct Error; + +#[test] +fn generic_unit_variant_format_arg_compiles() { + let error = Error; + assert_eq!(error.to_string(), "false"); +}