nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: dtolnay/syn
Pull request #1212 (2022-09-18 22:21:03)

Parse closures with explicit empty lifetime list


Patch:
diff --git a/src/expr.rs b/src/expr.rs
index cf0fa0af..fbab6814 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1727,7 +1727,10 @@ pub(crate) mod parsing {
             || input.peek(Token![move])
         {
             expr_closure(input, allow_struct).map(Expr::Closure)
-        } else if input.peek(Token![for]) && input.peek2(Token![<]) && input.peek3(Lifetime) {
+        } else if input.peek(Token![for])
+            && input.peek2(Token![<])
+            && (input.peek3(Lifetime) || input.peek3(Token![>]))
+        {
             let begin = input.fork();
             input.parse::<BoundLifetimes>()?;
             expr_closure(input, allow_struct)?;
@@ -2010,7 +2013,9 @@ pub(crate) mod parsing {
             Expr::If(input.parse()?)
         } else if input.peek(Token![while]) {
             Expr::While(input.parse()?)
-        } else if input.peek(Token![for]) {
+        } else if input.peek(Token![for])
+            && !(input.peek2(Token![<]) && (input.peek3(Lifetime) || input.peek3(Token![>])))
+        {
             Expr::ForLoop(input.parse()?)
         } else if input.peek(Token![loop]) {
             Expr::Loop(input.parse()?)


Test patch:
diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs
index 01a8bade..a584f6b8 100644
--- a/tests/repo/mod.rs
+++ b/tests/repo/mod.rs
@@ -14,10 +14,6 @@ const REVISION: &str = "98ad6a5519651af36e246c0335c964dd52c554ba";
 
 #[rustfmt::skip]
 static EXCLUDE_FILES: &[&str] = &[
-    // TODO: for<> closures with empty lifetime list
-    "src/tools/rustfmt/tests/source/closure.rs",
-    "src/tools/rustfmt/tests/target/closure.rs",
-
     // TODO: dyn*
     "src/test/ui/dyn-star/const.rs",
     "src/test/ui/dyn-star/drop.rs",
Repository: dtolnay/syn
Pull request #1217 (2022-09-18 23:58:34)

Parse associated type on path with parenthesized generic arguments


Patch:
diff --git a/src/ty.rs b/src/ty.rs
index 09ed8a91..1fe07960 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -825,15 +825,28 @@ pub mod parsing {
     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
     impl Parse for TypePath {
         fn parse(input: ParseStream) -> Result<Self> {
-            let (qself, mut path) = path::parsing::qpath(input, false)?;
+            let expr_style = false;
+            let (qself, mut path) = path::parsing::qpath(input, expr_style)?;
 
             if path.segments.last().unwrap().arguments.is_empty()
                 && (input.peek(token::Paren) || input.peek(Token![::]) && input.peek3(token::Paren))
             {
                 input.parse::<Option<Token![::]>>()?;
                 let args: ParenthesizedGenericArguments = input.parse()?;
+                let allow_associated_type = cfg!(feature = "full")
+                    && match &args.output {
+                        ReturnType::Default => true,
+                        ReturnType::Type(_, ty) => match **ty {
+                            // TODO: probably some of the other kinds allow this too.
+                            Type::Paren(_) => true,
+                            _ => false,
+                        },
+                    };
                 let parenthesized = PathArguments::Parenthesized(args);
                 path.segments.last_mut().unwrap().arguments = parenthesized;
+                if allow_associated_type {
+                    Path::parse_rest(input, &mut path, expr_style)?;
+                }
             }
 
             Ok(TypePath { qself, path })


Test patch:
diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs
index 494c63e1..5c290158 100644
--- a/tests/repo/mod.rs
+++ b/tests/repo/mod.rs
@@ -14,9 +14,6 @@ const REVISION: &str = "98ad6a5519651af36e246c0335c964dd52c554ba";
 
 #[rustfmt::skip]
 static EXCLUDE_FILES: &[&str] = &[
-    // TODO: associated type of a path with parenthesized generic arguments
-    "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs",
-
     // TODO: trailing comma after variadic in extern fn signature
     "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs",
Repository: dtolnay/syn
Pull request #1218 (2022-09-19 00:12:15)

Fix printing of variadic extern fn with trailing comma


Patch:
diff --git a/src/item.rs b/src/item.rs
index 1ce970ee..a1ef7ab4 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -2765,7 +2765,6 @@ mod printing {
     use super::*;
     use crate::attr::FilterAttrs;
     use crate::print::TokensOrDefault;
-    use crate::punctuated::Pair;
     use proc_macro2::TokenStream;
     use quote::{ToTokens, TokenStreamExt};
 
@@ -3283,16 +3282,9 @@ mod printing {
             self.generics.to_tokens(tokens);
             self.paren_token.surround(tokens, |tokens| {
                 let mut last_is_variadic = false;
-                for input in self.inputs.pairs() {
-                    match input {
-                        Pair::Punctuated(input, comma) => {
-                            maybe_variadic_to_tokens(input, tokens);
-                            comma.to_tokens(tokens);
-                        }
-                        Pair::End(input) => {
-                            last_is_variadic = maybe_variadic_to_tokens(input, tokens);
-                        }
-                    }
+                for pair in self.inputs.pairs() {
+                    last_is_variadic = maybe_variadic_to_tokens(pair.value(), tokens);
+                    pair.punct().to_tokens(tokens);
                 }
                 if self.variadic.is_some() && !last_is_variadic {
                     if !self.inputs.empty_or_trailing() {


Test patch:
diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs
index 5c290158..4c7be853 100644
--- a/tests/repo/mod.rs
+++ b/tests/repo/mod.rs
@@ -14,9 +14,6 @@ const REVISION: &str = "98ad6a5519651af36e246c0335c964dd52c554ba";
 
 #[rustfmt::skip]
 static EXCLUDE_FILES: &[&str] = &[
-    // TODO: trailing comma after variadic in extern fn signature
-    "src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs",
-
     // TODO: impl ~const T {}
     // https://github.com/dtolnay/syn/issues/1051
     "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",
Repository: dtolnay/syn
Pull request #1348 (2023-01-31 21:23:58)

Parse unsafe attributes
https://github.com/rust-lang/rfcs/pull/3325


Patch:
diff --git a/src/attr.rs b/src/attr.rs
index 45d23187..7faf6bd5 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -508,6 +508,7 @@ impl<'a> FilterAttrs<'a> for &'a [Attribute] {
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
+    use crate::ext::IdentExt;
     use crate::parse::{Parse, ParseStream, Result};
 
     pub fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
@@ -540,8 +541,13 @@ pub mod parsing {
     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
     impl Parse for Meta {
         fn parse(input: ParseStream) -> Result<Self> {
-            let path = input.call(Path::parse_mod_style)?;
-            parse_meta_after_path(path, input)
+            if cfg!(feature = "full") && input.peek(Token![unsafe]) {
+                let unsafe_ident = Ident::parse_any(input)?;
+                parse_meta_list_after_path(Path::from(unsafe_ident), input).map(Meta::List)
+            } else {
+                let path = input.call(Path::parse_mod_style)?;
+                parse_meta_after_path(path, input)
+            }
         }
     }
 


Test patch:
diff --git a/tests/test_attribute.rs b/tests/test_attribute.rs
index 597ae3ad..8ab4e1b5 100644
--- a/tests/test_attribute.rs
+++ b/tests/test_attribute.rs
@@ -215,6 +215,25 @@ fn test_negative_lit() {
     "###);
 }
 
+#[test]
+fn test_unsafe() {
+    let meta = test("#[unsafe(no_mangle)]");
+
+    snapshot!(meta, @r###"
+    Meta::List {
+        path: Path {
+            segments: [
+                PathSegment {
+                    ident: "unsafe",
+                },
+            ],
+        },
+        delimiter: MacroDelimiter::Paren,
+        tokens: TokenStream(`no_mangle`),
+    }
+    "###);
+}
+
 fn test(input: &str) -> Meta {
     let attrs = Attribute::parse_outer.parse_str(input).unwrap();
Repository: dtolnay/syn
Pull request #1431 (2023-03-30 14:17:08)

Qualify `compile_error!`
Proposed fix for #1427


Patch:
diff --git a/src/error.rs b/src/error.rs
index 7eebd243..2a0bcd9b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -278,8 +278,19 @@ impl ErrorMessage {
             None => (Span::call_site(), Span::call_site()),
         };
 
-        // compile_error!($message)
+        // core::compile_error!($message)
         TokenStream::from_iter(vec![
+            TokenTree::Ident(Ident::new("core", start)),
+            TokenTree::Punct({
+                let mut punct = Punct::new(':', Spacing::Joint);
+                punct.set_span(start);
+                punct
+            }),
+            TokenTree::Punct({
+                let mut punct = Punct::new(':', Spacing::Alone);
+                punct.set_span(start);
+                punct
+            }),
             TokenTree::Ident(Ident::new("compile_error", start)),
             TokenTree::Punct({
                 let mut punct = Punct::new('!', Spacing::Alone);


Test patch:
diff --git a/tests/test_compile_error.rs b/tests/test_compile_error.rs
new file mode 100644
index 00000000..5433ccdd
--- /dev/null
+++ b/tests/test_compile_error.rs
@@ -0,0 +1,18 @@
+use quote::quote;
+use syn::Item;
+
+#[test]
+fn parse_crate_root_custom_inner_attribute() {
+    let tokens = quote! {
+        #![feature(custom_inner_attributes)]
+        #[prelude_import]
+        use std::prelude::rust_2021::*;
+        #[macro_use]
+        extern crate std;
+    };
+    let error = syn::parse2::<Item>(tokens).unwrap_err();
+    assert_eq!(
+        error.to_compile_error().to_string(),
+        r#"core :: compile_error ! { "expected square brackets" }"#
+    );
+}
Repository: dtolnay/syn
Pull request #1475 (2023-06-24 23:13:42)

Support parsing c-str literals
RFC: https://github.com/rust-lang/rfcs/pull/3348
Tracking issue: https://github.com/rust-lang/rust/issues/105723
Proc-macro2 implementation: https://github.com/dtolnay/proc-macro2/pull/395


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 79de385e..404753e2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -35,7 +35,7 @@ proc-macro = ["proc-macro2/proc-macro", "quote/proc-macro"]
 test = ["syn-test-suite/all-features"]
 
 [dependencies]
-proc-macro2 = { version = "1.0.61", default-features = false }
+proc-macro2 = { version = "1.0.62", default-features = false }
 quote = { version = "1.0.28", optional = true, default-features = false }
 unicode-ident = "1"
 


Test patch:
diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs
index 244f3053..79cccb1a 100644
--- a/tests/repo/mod.rs
+++ b/tests/repo/mod.rs
@@ -17,30 +17,6 @@ const REVISION: &str = "fe7454bf439c93cbe9ac8a8f7fcfacd5a40244c2";
 
 #[rustfmt::skip]
 static EXCLUDE_FILES: &[&str] = &[
-    // TODO: c"string" CStr literals
-    // https://github.com/rust-lang/rust/issues/105723
-    "compiler/rustc_codegen_llvm/src/allocator.rs",
-    "compiler/rustc_codegen_llvm/src/back/lto.rs",
-    "compiler/rustc_codegen_llvm/src/back/write.rs",
-    "compiler/rustc_codegen_llvm/src/base.rs",
-    "compiler/rustc_codegen_llvm/src/builder.rs",
-    "compiler/rustc_codegen_llvm/src/consts.rs",
-    "compiler/rustc_codegen_llvm/src/context.rs",
-    "compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs",
-    "compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs",
-    "compiler/rustc_codegen_llvm/src/debuginfo/mod.rs",
-    "library/std/src/sys/unix/args.rs",
-    "library/std/src/sys/unix/fs.rs",
-    "library/std/src/sys/unix/mod.rs",
-    "library/std/src/sys/unix/process/process_common.rs",
-    "library/std/src/sys/unix/thread.rs",
-    "library/std/src/sys/windows/c.rs",
-    "library/std/src/sys/windows/compat.rs",
-    "library/std/src/sys/windows/mod.rs",
-    "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs",
-    "tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs",
-    "tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs",
-
     // TODO: non-lifetime binders: `where for<'a, T> &'a Struct<T>: Trait`
     // https://github.com/dtolnay/syn/issues/1435
     "tests/rustdoc-json/non_lifetime_binders.rs",
Repository: dtolnay/syn
Pull request #1543 (2023-12-11 02:03:10)

Respect None-delimited group when parsing unary expr
Example input: `$expr.method()` where expr is `&self`.

**Before:** incorrect, this is `&(self.method())`

```rust
Expr::Reference {
    expr: Expr::MethodCall {
        receiver: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "self",
                    },
                ],
            },
        },
        method: "method",
    },
}
```

**After:** correct. `(&self).method()`

```rust
Expr::MethodCall {
    receiver: Expr::Group {
        expr: Expr::Reference {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "self",
                        },
                    ],
                },
            },
        },
    },
    method: "method",
}
```


Patch:
diff --git a/src/expr.rs b/src/expr.rs
index f3e37d49..334caada 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1368,6 +1368,10 @@ pub(crate) mod parsing {
     fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result<Expr> {
         let begin = input.fork();
         let attrs = input.call(expr_attrs)?;
+        if input.peek(token::Group) {
+            return trailer_expr(begin, attrs, input, allow_struct);
+        }
+
         if input.peek(Token![&]) {
             let and_token: Token![&] = input.parse()?;
             let raw: Option<kw::raw> = if input.peek(kw::raw)


Test patch:
diff --git a/tests/test_expr.rs b/tests/test_expr.rs
index 9d0b44f9..64cbea88 100644
--- a/tests/test_expr.rs
+++ b/tests/test_expr.rs
@@ -216,6 +216,31 @@ fn test_macro_variable_struct() {
     "###);
 }
 
+#[test]
+fn test_macro_variable_unary() {
+    // mimics the token stream corresponding to `$expr.method()` where expr is `&self`
+    let inner = Group::new(Delimiter::None, quote!(&self));
+    let tokens = quote!(#inner.method());
+    snapshot!(tokens as Expr, @r###"
+    Expr::MethodCall {
+        receiver: Expr::Group {
+            expr: Expr::Reference {
+                expr: Expr::Path {
+                    path: Path {
+                        segments: [
+                            PathSegment {
+                                ident: "self",
+                            },
+                        ],
+                    },
+                },
+            },
+        },
+        method: "method",
+    }
+    "###);
+}
+
 #[test]
 fn test_macro_variable_match_arm() {
     // mimics the token stream corresponding to `match v { _ => $expr }`
Repository: dtolnay/syn
Pull request #1545 (2023-12-11 02:30:02)

Fix None-delimited let expression in stmt position


Patch:
diff --git a/src/stmt.rs b/src/stmt.rs
index fb67fecc..fd14aec2 100644
--- a/src/stmt.rs
+++ b/src/stmt.rs
@@ -200,7 +200,7 @@ pub(crate) mod parsing {
             }
         }
 
-        if input.peek(Token![let]) {
+        if input.peek(Token![let]) && !input.peek(token::Group) {
             stmt_local(input, attrs).map(Stmt::Local)
         } else if input.peek(Token![pub])
             || input.peek(Token![crate]) && !input.peek2(Token![::])


Test patch:
diff --git a/tests/test_stmt.rs b/tests/test_stmt.rs
index 6223a6df..61890a40 100644
--- a/tests/test_stmt.rs
+++ b/tests/test_stmt.rs
@@ -8,7 +8,7 @@
 mod macros;
 
 use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
-use quote::quote;
+use quote::{quote, ToTokens as _};
 use syn::parse::Parser as _;
 use syn::{Block, Stmt};
 
@@ -68,7 +68,6 @@ fn test_none_group() {
             TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())),
         ]),
     ))]);
-
     snapshot!(tokens as Stmt, @r###"
     Stmt::Item(Item::Fn {
         vis: Visibility::Inherited,
@@ -83,6 +82,32 @@ fn test_none_group() {
         },
     })
     "###);
+
+    let tokens = Group::new(Delimiter::None, quote!(let None = None)).to_token_stream();
+    let stmts = Block::parse_within.parse2(tokens).unwrap();
+    snapshot!(stmts, @r###"
+    [
+        Stmt::Expr(
+            Expr::Group {
+                expr: Expr::Let {
+                    pat: Pat::Ident {
+                        ident: "None",
+                    },
+                    expr: Expr::Path {
+                        path: Path {
+                            segments: [
+                                PathSegment {
+                                    ident: "None",
+                                },
+                            ],
+                        },
+                    },
+                },
+            },
+            None,
+        ),
+    ]
+    "###);
 }
 
 #[test]
Repository: dtolnay/syn
Pull request #1548 (2023-12-12 22:49:54)

Support parsing Field in parse_quote
```rust
let field: Field = parse_quote!(pub enabled: bool);
```


Patch:
diff --git a/src/parse_quote.rs b/src/parse_quote.rs
index 59e51b41..18de4745 100644
--- a/src/parse_quote.rs
+++ b/src/parse_quote.rs
@@ -136,7 +136,7 @@ impl<T: Parse> ParseQuote for T {
 
 use crate::punctuated::Punctuated;
 #[cfg(any(feature = "full", feature = "derive"))]
-use crate::{attr, Attribute};
+use crate::{attr, Attribute, Field, FieldMutability, Ident, Type, Visibility};
 #[cfg(feature = "full")]
 use crate::{Block, Pat, Stmt};
 
@@ -151,6 +151,36 @@ impl ParseQuote for Attribute {
     }
 }
 
+#[cfg(any(feature = "full", feature = "derive"))]
+impl ParseQuote for Field {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let attrs = input.call(Attribute::parse_outer)?;
+        let vis: Visibility = input.parse()?;
+
+        let ident: Option<Ident>;
+        let colon_token: Option<Token![:]>;
+        let is_named = input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]);
+        if is_named {
+            ident = Some(input.parse()?);
+            colon_token = Some(input.parse()?);
+        } else {
+            ident = None;
+            colon_token = None;
+        }
+
+        let ty: Type = input.parse()?;
+
+        Ok(Field {
+            attrs,
+            vis,
+            mutability: FieldMutability::None,
+            ident,
+            colon_token,
+            ty,
+        })
+    }
+}
+
 #[cfg(feature = "full")]
 impl ParseQuote for Pat {
     fn parse(input: ParseStream) -> Result<Self> {


Test patch:
diff --git a/tests/test_parse_quote.rs b/tests/test_parse_quote.rs
index 1c912064..dff0c2cc 100644
--- a/tests/test_parse_quote.rs
+++ b/tests/test_parse_quote.rs
@@ -2,7 +2,7 @@
 mod macros;
 
 use syn::punctuated::Punctuated;
-use syn::{parse_quote, Attribute, Lit, Pat, Stmt, Token};
+use syn::{parse_quote, Attribute, Field, Lit, Pat, Stmt, Token};
 
 #[test]
 fn test_attribute() {
@@ -35,6 +35,46 @@ fn test_attribute() {
     "###);
 }
 
+#[test]
+fn test_field() {
+    let field: Field = parse_quote!(pub enabled: bool);
+    snapshot!(field, @r###"
+    Field {
+        vis: Visibility::Public,
+        ident: Some("enabled"),
+        colon_token: Some,
+        ty: Type::Path {
+            path: Path {
+                segments: [
+                    PathSegment {
+                        ident: "bool",
+                    },
+                ],
+            },
+        },
+    }
+    "###);
+
+    let field: Field = parse_quote!(primitive::bool);
+    snapshot!(field, @r###"
+    Field {
+        vis: Visibility::Inherited,
+        ty: Type::Path {
+            path: Path {
+                segments: [
+                    PathSegment {
+                        ident: "primitive",
+                    },
+                    PathSegment {
+                        ident: "bool",
+                    },
+                ],
+            },
+        },
+    }
+    "###);
+}
+
 #[test]
 fn test_pat() {
     let pat: Pat = parse_quote!(Some(false) | None);
Repository: dtolnay/syn
Pull request #1559 (2023-12-25 04:27:47)

Fix ToTokens for PatTuple to insert trailing comma
Fixes https://github.com/dtolnay/syn/issues/1553.


Patch:
diff --git a/src/pat.rs b/src/pat.rs
index df7da5bb..24996045 100644
--- a/src/pat.rs
+++ b/src/pat.rs
@@ -856,6 +856,15 @@ mod printing {
             tokens.append_all(self.attrs.outer());
             self.paren_token.surround(tokens, |tokens| {
                 self.elems.to_tokens(tokens);
+                // If there is only one element, a trailing comma is needed to
+                // distinguish PatTuple from PatParen, unless this is `(..)`
+                // which is a tuple pattern even without comma.
+                if self.elems.len() == 1
+                    && !self.elems.trailing_punct()
+                    && !matches!(self.elems[0], Pat::Rest { .. })
+                {
+                    <Token![,]>::default().to_tokens(tokens);
+                }
             });
         }
     }


Test patch:
diff --git a/tests/test_pat.rs b/tests/test_pat.rs
index 89033083..7b5f8b02 100644
--- a/tests/test_pat.rs
+++ b/tests/test_pat.rs
@@ -107,10 +107,13 @@ fn test_tuple_comma() {
     snapshot!(expr.to_token_stream() as Pat, @"Pat::Tuple");
 
     expr.elems.push_value(parse_quote!(_));
-    // FIXME: must parse to Pat::Tuple, not Pat::Paren
+    // Must not parse to Pat::Paren
     snapshot!(expr.to_token_stream() as Pat, @r###"
-    Pat::Paren {
-        pat: Pat::Wild,
+    Pat::Tuple {
+        elems: [
+            Pat::Wild,
+            Token![,],
+        ],
     }
     "###);