Repository: dtolnay/syn
Pull request #1293 (2023-01-16 05:11:05)

Store attributes on rest pattern of Pat::Struct


Patch:
diff --git a/src/gen/clone.rs b/src/gen/clone.rs
index 0d4423f3..d30cb857 100644
--- a/src/gen/clone.rs
+++ b/src/gen/clone.rs
@@ -1619,7 +1619,7 @@ impl Clone for PatStruct {
             path: self.path.clone(),
             brace_token: self.brace_token.clone(),
             fields: self.fields.clone(),
-            dot2_token: self.dot2_token.clone(),
+            rest: self.rest.clone(),
         }
     }
 }
diff --git a/src/gen/debug.rs b/src/gen/debug.rs
index d21adc28..bb59cf1c 100644
--- a/src/gen/debug.rs
+++ b/src/gen/debug.rs
@@ -2229,7 +2229,7 @@ impl Debug for PatStruct {
         formatter.field("path", &self.path);
         formatter.field("brace_token", &self.brace_token);
         formatter.field("fields", &self.fields);
-        formatter.field("dot2_token", &self.dot2_token);
+        formatter.field("rest", &self.rest);
         formatter.finish()
     }
 }
diff --git a/src/gen/eq.rs b/src/gen/eq.rs
index f285fe2f..936eede7 100644
--- a/src/gen/eq.rs
+++ b/src/gen/eq.rs
@@ -1535,7 +1535,7 @@ impl Eq for PatStruct {}
 impl PartialEq for PatStruct {
     fn eq(&self, other: &Self) -> bool {
         self.attrs == other.attrs && self.qself == other.qself && self.path == other.path
-            && self.fields == other.fields && self.dot2_token == other.dot2_token
+            && self.fields == other.fields && self.rest == other.rest
     }
 }
 #[cfg(feature = "full")]
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index 555cdde6..89ba5b77 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -2643,7 +2643,7 @@ where
         path: f.fold_path(node.path),
         brace_token: Brace(tokens_helper(f, &node.brace_token.span)),
         fields: FoldHelper::lift(node.fields, |it| f.fold_field_pat(it)),
-        dot2_token: (node.dot2_token).map(|it| Token![..](tokens_helper(f, &it.spans))),
+        rest: (node.rest).map(|it| f.fold_pat_rest(it)),
     }
 }
 #[cfg(feature = "full")]
diff --git a/src/gen/hash.rs b/src/gen/hash.rs
index a0cc0cfc..2e0dd484 100644
--- a/src/gen/hash.rs
+++ b/src/gen/hash.rs
@@ -2068,7 +2068,7 @@ impl Hash for PatStruct {
         self.qself.hash(state);
         self.path.hash(state);
         self.fields.hash(state);
-        self.dot2_token.hash(state);
+        self.rest.hash(state);
     }
 }
 #[cfg(feature = "full")]
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
index ef98a430..8502acd1 100644
--- a/src/gen/visit.rs
+++ b/src/gen/visit.rs
@@ -2983,8 +2983,8 @@ where
             tokens_helper(v, &p.spans);
         }
     }
-    if let Some(it) = &node.dot2_token {
-        tokens_helper(v, &it.spans);
+    if let Some(it) = &node.rest {
+        v.visit_pat_rest(it);
     }
 }
 #[cfg(feature = "full")]
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
index 019138cd..b06f6e3e 100644
--- a/src/gen/visit_mut.rs
+++ b/src/gen/visit_mut.rs
@@ -2983,8 +2983,8 @@ where
             tokens_helper(v, &mut p.spans);
         }
     }
-    if let Some(it) = &mut node.dot2_token {
-        tokens_helper(v, &mut it.spans);
+    if let Some(it) = &mut node.rest {
+        v.visit_pat_rest_mut(it);
     }
 }
 #[cfg(feature = "full")]
diff --git a/src/pat.rs b/src/pat.rs
index 7443afe5..5f28b9cb 100644
--- a/src/pat.rs
+++ b/src/pat.rs
@@ -217,7 +217,7 @@ ast_struct! {
         pub path: Path,
         pub brace_token: token::Brace,
         pub fields: Punctuated<FieldPat, Token![,]>,
-        pub dot2_token: Option<Token![..]>,
+        pub rest: Option<PatRest>,
     }
 }
 
@@ -436,7 +436,6 @@ pub mod parsing {
     }
 
     fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
-        let begin = input.fork();
         let (qself, path) = path::parsing::qpath(input, true)?;
 
         if qself.is_none() && input.peek(Token![!]) && !input.peek(Token![!=]) {
@@ -466,7 +465,7 @@ pub mod parsing {
         }
 
         if input.peek(token::Brace) {
-            pat_struct(begin.fork(), input, qself, path)
+            pat_struct(input, qself, path).map(Pat::Struct)
         } else if input.peek(token::Paren) {
             pat_tuple_struct(input, qself, path).map(Pat::TupleStruct)
         } else if input.peek(Token![..]) {
@@ -526,24 +525,19 @@ pub mod parsing {
         })
     }
 
-    fn pat_struct(
-        begin: ParseBuffer,
-        input: ParseStream,
-        qself: Option<QSelf>,
-        path: Path,
-    ) -> Result<Pat> {
+    fn pat_struct(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatStruct> {
         let content;
         let brace_token = braced!(content in input);
 
         let mut fields = Punctuated::new();
-        let mut dot2_token = None;
+        let mut rest = None;
         while !content.is_empty() {
             let attrs = content.call(Attribute::parse_outer)?;
             if content.peek(Token![..]) {
-                dot2_token = Some(content.parse()?);
-                if !attrs.is_empty() {
-                    return Ok(Pat::Verbatim(verbatim::between(begin, input)));
-                }
+                rest = Some(PatRest {
+                    attrs,
+                    dot2_token: content.parse()?,
+                });
                 break;
             }
             let mut value = content.call(field_pat)?;
@@ -556,14 +550,14 @@ pub mod parsing {
             fields.push_punct(punct);
         }
 
-        Ok(Pat::Struct(PatStruct {
+        Ok(PatStruct {
             attrs: Vec::new(),
             qself,
             path,
             brace_token,
             fields,
-            dot2_token,
-        }))
+            rest,
+        })
     }
 
     impl Member {
@@ -824,10 +818,10 @@ mod printing {
             self.brace_token.surround(tokens, |tokens| {
                 self.fields.to_tokens(tokens);
                 // NOTE: We need a comma before the dot2 token if it is present.
-                if !self.fields.empty_or_trailing() && self.dot2_token.is_some() {
+                if !self.fields.empty_or_trailing() && self.rest.is_some() {
                     <Token![,]>::default().to_tokens(tokens);
                 }
-                self.dot2_token.to_tokens(tokens);
+                self.rest.to_tokens(tokens);
             });
         }
     }
diff --git a/syn.json b/syn.json
index dca61963..b9cc89f1 100644
--- a/syn.json
+++ b/syn.json
@@ -4067,9 +4067,9 @@
             "punct": "Comma"
           }
         },
-        "dot2_token": {
+        "rest": {
           "option": {
-            "token": "Dot2"
+            "syn": "PatRest"
           }
         }
       }


Test patch:
diff --git a/tests/debug/gen.rs b/tests/debug/gen.rs
index f5e53d97..0351c298 100644
--- a/tests/debug/gen.rs
+++ b/tests/debug/gen.rs
@@ -3989,17 +3989,21 @@ impl Debug for Lite<syn::Pat> {
                 if !_val.fields.is_empty() {
                     formatter.field("fields", Lite(&_val.fields));
                 }
-                if let Some(val) = &_val.dot2_token {
+                if let Some(val) = &_val.rest {
                     #[derive(RefCast)]
                     #[repr(transparent)]
-                    struct Print(syn::token::Dot2);
+                    struct Print(syn::PatRest);
                     impl Debug for Print {
                         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                             formatter.write_str("Some")?;
+                            let _val = &self.0;
+                            formatter.write_str("(")?;
+                            Debug::fmt(Lite(_val), formatter)?;
+                            formatter.write_str(")")?;
                             Ok(())
                         }
                     }
-                    formatter.field("dot2_token", Print::ref_cast(val));
+                    formatter.field("rest", Print::ref_cast(val));
                 }
                 formatter.finish()
             }
@@ -4317,17 +4321,21 @@ impl Debug for Lite<syn::PatStruct> {
         if !_val.fields.is_empty() {
             formatter.field("fields", Lite(&_val.fields));
         }
-        if let Some(val) = &_val.dot2_token {
+        if let Some(val) = &_val.rest {
             #[derive(RefCast)]
             #[repr(transparent)]
-            struct Print(syn::token::Dot2);
+            struct Print(syn::PatRest);
             impl Debug for Print {
                 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                     formatter.write_str("Some")?;
+                    let _val = &self.0;
+                    formatter.write_str("(")?;
+                    Debug::fmt(Lite(_val), formatter)?;
+                    formatter.write_str(")")?;
                     Ok(())
                 }
             }
-            formatter.field("dot2_token", Print::ref_cast(val));
+            formatter.field("rest", Print::ref_cast(val));
         }
         formatter.finish()
     }
diff --git a/tests/test_size.rs b/tests/test_size.rs
index 0850b1c7..8252008f 100644
--- a/tests/test_size.rs
+++ b/tests/test_size.rs
@@ -6,7 +6,7 @@ use syn::{Expr, Item, Lit, Pat, Type};
 #[rustversion::attr(before(2022-11-24), ignore)]
 #[test]
 fn test_expr_size() {
-    assert_eq!(mem::size_of::<Expr>(), 304);
+    assert_eq!(mem::size_of::<Expr>(), 312);
 }
 
 #[rustversion::attr(before(2022-09-09), ignore)]
@@ -18,13 +18,13 @@ fn test_item_size() {
 #[rustversion::attr(before(2022-11-24), ignore)]
 #[test]
 fn test_type_size() {
-    assert_eq!(mem::size_of::<Type>(), 320);
+    assert_eq!(mem::size_of::<Type>(), 328);
 }
 
 #[rustversion::attr(before(2021-10-11), ignore)]
 #[test]
 fn test_pat_size() {
-    assert_eq!(mem::size_of::<Pat>(), 176);
+    assert_eq!(mem::size_of::<Pat>(), 184);
 }
 
 #[rustversion::attr(before(2022-09-09), ignore)]