From f1ca210cc4772f198af91886e3849dac68114f97 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 11 Jul 2024 16:07:12 -0700 Subject: [PATCH 1/2] Add regression test for issue 309 --- tests/test_display.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_display.rs b/tests/test_display.rs index c05d157..7a9057c 100644 --- a/tests/test_display.rs +++ b/tests/test_display.rs @@ -234,6 +234,18 @@ fn test_field() { assert("0", Error(Inner { data: 0 })); } +#[test] +fn test_nested_tuple_field() { + #[derive(Debug)] + struct Inner(usize); + + #[derive(Error, Debug)] + #[error("{}", .0.0)] + struct Error(Inner); + + assert("0", Error(Inner(0))); +} + #[test] fn test_macro_rules() { // Regression test for https://github.com/dtolnay/thiserror/issues/86 From 40a7779b1793f2dce5f85abe8c03486cdb5eb640 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 11 Jul 2024 16:09:19 -0700 Subject: [PATCH 2/2] Support .0.0 nested tuple index --- impl/src/attr.rs | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/impl/src/attr.rs b/impl/src/attr.rs index 395edb1..e0ac02b 100644 --- a/impl/src/attr.rs +++ b/impl/src/attr.rs @@ -1,11 +1,11 @@ -use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree}; +use proc_macro2::{Delimiter, Group, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; use quote::{format_ident, quote, ToTokens}; use std::collections::BTreeSet as Set; use syn::parse::discouraged::Speculative; use syn::parse::ParseStream; use syn::{ - braced, bracketed, parenthesized, token, Attribute, Error, Ident, Index, LitInt, LitStr, Meta, - Result, Token, + braced, bracketed, parenthesized, token, Attribute, Error, Ident, Index, LitFloat, LitInt, + LitStr, Meta, Result, Token, }; pub struct Attrs<'a> { @@ -145,14 +145,42 @@ fn parse_token_expr(input: ParseStream, mut begin_expr: bool) -> Result()?; begin_expr = false; continue; - } - if input.peek2(LitInt) { + } else if input.peek2(LitInt) { input.parse::()?; let int: Index = input.parse()?; - let ident = format_ident!("_{}", int.index, span = int.span); - tokens.push(TokenTree::Ident(ident)); + 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::()?; + let float: LitFloat = ahead.parse()?; + let repr = float.to_string(); + let mut indices = repr.split('.').map(syn::parse_str::); + if let (Some(Ok(first)), Some(Ok(second)), None) = + (indices.next(), indices.next(), indices.next()) + { + input.advance_to(&ahead); + tokens.push({ + let ident = format_ident!("_{}", first, span = float.span()); + TokenTree::Ident(ident) + }); + tokens.push({ + let mut punct = Punct::new('.', Spacing::Alone); + punct.set_span(float.span()); + TokenTree::Punct(punct) + }); + tokens.push({ + let mut literal = Literal::u32_unsuffixed(second.index); + literal.set_span(float.span()); + TokenTree::Literal(literal) + }); + begin_expr = false; + continue; + } } }