Repository: dtolnay/thiserror (rust)

Issue:
Parse .0 fmt arguments better
For example `#[error("{}", .0.data)]` currently works but `#[error("{}", &.0.data)]` does not. We should make the `.0` / `.var` variables work wherever possible.

Pull request:
Parse .0 fmt arguments in all valid places
Fixes #54.

Patch:
diff --git a/impl/src/attr.rs b/impl/src/attr.rs
index c7c3d99..30ecfc8 100644
--- a/impl/src/attr.rs
+++ b/impl/src/attr.rs
@@ -94,13 +94,13 @@ fn parse_error_attribute<'a>(attrs: &mut Attrs<'a>, attr: &'a Attribute) -> Resu
     })
 }
 
-fn parse_token_expr(input: ParseStream, mut last_is_comma: bool) -> Result<TokenStream> {
+fn parse_token_expr(input: ParseStream, mut begin_expr: bool) -> Result<TokenStream> {
     let mut tokens = Vec::new();
     while !input.is_empty() {
-        if last_is_comma && input.peek(Token![.]) {
+        if begin_expr && input.peek(Token![.]) {
             if input.peek2(Ident) {
                 input.parse::<Token![.]>()?;
-                last_is_comma = false;
+                begin_expr = false;
                 continue;
             }
             if input.peek2(LitInt) {
@@ -108,11 +108,34 @@ fn parse_token_expr(input: ParseStream, mut last_is_comma: bool) -> Result<Token
                 let int: Index = input.parse()?;
                 let ident = format_ident!("_{}", int.index, span = int.span);
                 tokens.push(TokenTree::Ident(ident));
-                last_is_comma = false;
+                begin_expr = false;
                 continue;
             }
         }
-        last_is_comma = input.peek(Token![,]);
+
+        begin_expr = input.peek(Token![break])
+            || input.peek(Token![continue])
+            || input.peek(Token![if])
+            || input.peek(Token![in])
+            || input.peek(Token![match])
+            || input.peek(Token![mut])
+            || input.peek(Token![return])
+            || input.peek(Token![while])
+            || input.peek(Token![+])
+            || input.peek(Token![&])
+            || input.peek(Token![!])
+            || input.peek(Token![^])
+            || input.peek(Token![,])
+            || input.peek(Token![/])
+            || input.peek(Token![=])
+            || input.peek(Token![>])
+            || input.peek(Token![<])
+            || input.peek(Token![|])
+            || input.peek(Token![%])
+            || input.peek(Token![;])
+            || input.peek(Token![*])
+            || input.peek(Token![-]);
+
         let token: TokenTree = if input.peek(token::Paren) {
             let content;
             let delimiter = parenthesized!(content in input);


Test patch:
diff --git a/tests/test_display.rs b/tests/test_display.rs
index 7d9ac59..d64b8c2 100644
--- a/tests/test_display.rs
+++ b/tests/test_display.rs
@@ -121,6 +121,19 @@ fn test_nested() {
     assert("!bool = false", Error(true));
 }
 
+#[test]
+fn test_match() {
+    #[derive(Error, Debug)]
+    #[error("{}: {0}", match .1 {
+        Some(n) => format!("error occurred with {}", n),
+        None => format!("there was an empty error"),
+    })]
+    struct Error(String, Option<usize>);
+
+    assert("error occurred with 1: ...", Error("...".to_owned(), Some(1)));
+    assert("there was an empty error: ...", Error("...".to_owned(), None));
+}
+
 #[test]
 fn test_void() {
     #[derive(Error, Debug)]