From f3c2e71ca7fbeb8ad4083643323e12a490c2ad2d Mon Sep 17 00:00:00 2001 From: Michael Sloan Date: Fri, 23 May 2025 13:31:25 -0600 Subject: [PATCH] Update syn crate from 1.0.109 to 2.0.101 (#31301) Nearly all generated by Zed Agent + Claude Opus 4. I just wrote the test `Args` struct and pointed it at the [2.0 release notes](https://github.com/dtolnay/syn/releases/tag/2.0.0). Release Notes: - N/A --- Cargo.lock | 10 +- Cargo.toml | 2 +- crates/gpui_macros/src/gpui_macros.rs | 2 +- crates/gpui_macros/src/test.rs | 204 ++++++++++++------ .../src/derive_refineable.rs | 25 +-- crates/ui_macros/src/dynamic_spacing.rs | 2 +- 6 files changed, 155 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a19ff0b8f..b2713cc1dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4351,7 +4351,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.101", "workspace-hack", ] @@ -7125,7 +7125,7 @@ dependencies = [ "gpui", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.101", "workspace-hack", ] @@ -14757,7 +14757,7 @@ version = "0.1.0" dependencies = [ "sqlez", "sqlformat", - "syn 1.0.109", + "syn 2.0.101", "workspace-hack", ] @@ -16842,7 +16842,7 @@ name = "ui_macros" version = "0.1.0" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.101", "workspace-hack", ] @@ -17099,7 +17099,7 @@ name = "util_macros" version = "0.1.0" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.101", "workspace-hack", ] diff --git a/Cargo.toml b/Cargo.toml index c5137091ef..74a55a926b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -550,7 +550,7 @@ streaming-iterator = "0.1" strsim = "0.11" strum = { version = "0.27.0", features = ["derive"] } subtle = "2.5.0" -syn = { version = "1.0.72", features = ["full", "extra-traits"] } +syn = { version = "2.0.101", features = ["full", "extra-traits"] } sys-locale = "0.3.1" sysinfo = "0.31.0" take-until = "0.2.0" diff --git a/crates/gpui_macros/src/gpui_macros.rs b/crates/gpui_macros/src/gpui_macros.rs index 7e1b39cf68..f753a5e46f 100644 --- a/crates/gpui_macros/src/gpui_macros.rs +++ b/crates/gpui_macros/src/gpui_macros.rs @@ -183,7 +183,7 @@ pub(crate) fn get_simple_attribute_field(ast: &DeriveInput, name: &'static str) syn::Data::Struct(data_struct) => data_struct .fields .iter() - .find(|field| field.attrs.iter().any(|attr| attr.path.is_ident(name))) + .find(|field| field.attrs.iter().any(|attr| attr.path().is_ident(name))) .map(|field| field.ident.clone().unwrap()), syn::Data::Enum(_) => None, syn::Data::Union(_) => None, diff --git a/crates/gpui_macros/src/test.rs b/crates/gpui_macros/src/test.rs index aeec19a3a3..2c52149897 100644 --- a/crates/gpui_macros/src/test.rs +++ b/crates/gpui_macros/src/test.rs @@ -3,76 +3,132 @@ use proc_macro2::Ident; use quote::{format_ident, quote}; use std::mem; use syn::{ - AttributeArgs, FnArg, ItemFn, Lit, Meta, MetaList, NestedMeta, PathSegment, Type, parse_quote, + self, Expr, ExprLit, FnArg, ItemFn, Lit, Meta, MetaList, PathSegment, Token, Type, + parse::{Parse, ParseStream}, + parse_quote, + punctuated::Punctuated, spanned::Spanned, }; -pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as AttributeArgs); - try_test(args, function).unwrap_or_else(|err| err) +struct Args { + seeds: Vec, + max_retries: usize, + max_iterations: usize, + on_failure_fn_name: proc_macro2::TokenStream, } -fn try_test(args: Vec, function: TokenStream) -> Result { - let mut seeds = Vec::::new(); - let mut max_retries = 0; - let mut num_iterations = 1; - let mut on_failure_fn_name = quote!(None); +impl Parse for Args { + fn parse(input: ParseStream) -> Result { + let mut seeds = Vec::::new(); + let mut max_retries = 0; + let mut max_iterations = 1; + let mut on_failure_fn_name = quote!(None); - for arg in args { - let NestedMeta::Meta(arg) = arg else { - return Err(error_with_message("unexpected literal", arg)); - }; + let metas = Punctuated::::parse_terminated(input)?; - let ident = { - let meta_path = match &arg { - Meta::NameValue(meta) => &meta.path, - Meta::List(list) => &list.path, - Meta::Path(path) => return Err(error_with_message("invalid path argument", path)), - }; - let Some(ident) = meta_path.get_ident() else { - return Err(error_with_message("unexpected path", meta_path)); - }; - ident.to_string() - }; - - match (&arg, ident.as_str()) { - (Meta::NameValue(meta), "retries") => max_retries = parse_usize(&meta.lit)?, - (Meta::NameValue(meta), "iterations") => num_iterations = parse_usize(&meta.lit)?, - (Meta::NameValue(meta), "on_failure") => { - let Lit::Str(name) = &meta.lit else { - return Err(error_with_message( - "on_failure argument must be a string", - &meta.lit, - )); + for meta in metas { + let ident = { + let meta_path = match &meta { + Meta::NameValue(meta) => &meta.path, + Meta::List(list) => &list.path, + Meta::Path(path) => { + return Err(syn::Error::new(path.span(), "invalid path argument")); + } }; - let segments = name - .value() - .split("::") - .map(|part| PathSegment::from(Ident::new(part, name.span()))) - .collect(); - let path = syn::Path { - leading_colon: None, - segments, + let Some(ident) = meta_path.get_ident() else { + return Err(syn::Error::new(meta_path.span(), "unexpected path")); }; - on_failure_fn_name = quote!(Some(#path)); - } - (Meta::NameValue(meta), "seed") => seeds = vec![parse_usize(&meta.lit)? as u64], - (Meta::List(list), "seeds") => seeds = parse_u64_array(&list)?, - (Meta::Path(path), _) => { - return Err(error_with_message("invalid path argument", path)); - } - (_, _) => { - return Err(error_with_message("invalid argument name", arg)); + ident.to_string() + }; + + match (&meta, ident.as_str()) { + (Meta::NameValue(meta), "retries") => { + max_retries = parse_usize_from_expr(&meta.value)? + } + (Meta::NameValue(meta), "iterations") => { + max_iterations = parse_usize_from_expr(&meta.value)? + } + (Meta::NameValue(meta), "on_failure") => { + let Expr::Lit(ExprLit { + lit: Lit::Str(name), + .. + }) = &meta.value + else { + return Err(syn::Error::new( + meta.value.span(), + "on_failure argument must be a string", + )); + }; + let segments = name + .value() + .split("::") + .map(|part| PathSegment::from(Ident::new(part, name.span()))) + .collect(); + let path = syn::Path { + leading_colon: None, + segments, + }; + on_failure_fn_name = quote!(Some(#path)); + } + (Meta::NameValue(meta), "seed") => { + seeds = vec![parse_usize_from_expr(&meta.value)? as u64] + } + (Meta::List(list), "seeds") => seeds = parse_u64_array(&list)?, + (Meta::Path(_), _) => { + return Err(syn::Error::new(meta.span(), "invalid path argument")); + } + (_, _) => { + return Err(syn::Error::new(meta.span(), "invalid argument name")); + } } } - } - let seeds = quote!( #(#seeds),* ); - let mut inner_fn = syn::parse::(function).map_err(error_to_stream)?; + Ok(Args { + seeds, + max_retries, + max_iterations: max_iterations, + on_failure_fn_name, + }) + } +} + +pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { + let args = syn::parse_macro_input!(args as Args); + let mut inner_fn = match syn::parse::(function) { + Ok(f) => f, + Err(err) => return error_to_stream(err), + }; + let inner_fn_attributes = mem::take(&mut inner_fn.attrs); let inner_fn_name = format_ident!("_{}", inner_fn.sig.ident); let outer_fn_name = mem::replace(&mut inner_fn.sig.ident, inner_fn_name.clone()); + let result = generate_test_function( + args, + inner_fn, + inner_fn_attributes, + inner_fn_name, + outer_fn_name, + ); + match result { + Ok(tokens) => tokens, + Err(tokens) => tokens, + } +} + +fn generate_test_function( + args: Args, + inner_fn: ItemFn, + inner_fn_attributes: Vec, + inner_fn_name: Ident, + outer_fn_name: Ident, +) -> Result { + let seeds = &args.seeds; + let max_retries = args.max_retries; + let num_iterations = args.max_iterations; + let on_failure_fn_name = &args.on_failure_fn_name; + let seeds = quote!( #(#seeds),* ); + let mut outer_fn: ItemFn = if inner_fn.sig.asyncness.is_some() { // Pass to the test function the number of app contexts that it needs, // based on its parameter list. @@ -230,25 +286,37 @@ fn try_test(args: Vec, function: TokenStream) -> Result Result { - let Lit::Int(int) = &literal else { - return Err(error_with_message("expected an usize", literal)); +fn parse_usize_from_expr(expr: &Expr) -> Result { + let Expr::Lit(ExprLit { + lit: Lit::Int(int), .. + }) = expr + else { + return Err(syn::Error::new(expr.span(), "expected an integer")); }; - int.base10_parse().map_err(error_to_stream) + int.base10_parse() + .map_err(|_| syn::Error::new(int.span(), "failed to parse integer")) } -fn parse_u64_array(meta_list: &MetaList) -> Result, TokenStream> { - meta_list - .nested - .iter() - .map(|meta| { - if let NestedMeta::Lit(literal) = &meta { - parse_usize(literal).map(|value| value as u64) +fn parse_u64_array(meta_list: &MetaList) -> Result, syn::Error> { + let mut result = Vec::new(); + let tokens = &meta_list.tokens; + let parser = |input: ParseStream| { + let exprs = Punctuated::::parse_terminated(input)?; + for expr in exprs { + if let Expr::Lit(ExprLit { + lit: Lit::Int(int), .. + }) = expr + { + let value: usize = int.base10_parse()?; + result.push(value as u64); } else { - Err(error_with_message("expected an integer", meta.span())) + return Err(syn::Error::new(expr.span(), "expected an integer")); } - }) - .collect() + } + Ok(()) + }; + syn::parse::Parser::parse2(parser, tokens.clone())?; + Ok(result) } fn error_with_message(message: &str, spanned: impl Spanned) -> TokenStream { diff --git a/crates/refineable/derive_refineable/src/derive_refineable.rs b/crates/refineable/derive_refineable/src/derive_refineable.rs index aa297a8c0d..4af33df85e 100644 --- a/crates/refineable/derive_refineable/src/derive_refineable.rs +++ b/crates/refineable/derive_refineable/src/derive_refineable.rs @@ -16,25 +16,20 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream { .. } = parse_macro_input!(input); - let refineable_attr = attrs.iter().find(|attr| attr.path.is_ident("refineable")); + let refineable_attr = attrs.iter().find(|attr| attr.path().is_ident("refineable")); let mut impl_debug_on_refinement = false; let mut refinement_traits_to_derive = vec![]; if let Some(refineable_attr) = refineable_attr { - if let Ok(syn::Meta::List(meta_list)) = refineable_attr.parse_meta() { - for nested in meta_list.nested { - let syn::NestedMeta::Meta(syn::Meta::Path(path)) = nested else { - continue; - }; - - if path.is_ident("Debug") { - impl_debug_on_refinement = true; - } else { - refinement_traits_to_derive.push(path); - } + let _ = refineable_attr.parse_nested_meta(|meta| { + if meta.path.is_ident("Debug") { + impl_debug_on_refinement = true; + } else { + refinement_traits_to_derive.push(meta.path); } - } + Ok(()) + }); } let refinement_ident = format_ident!("{}Refinement", ident); @@ -325,7 +320,9 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream { } fn is_refineable_field(f: &Field) -> bool { - f.attrs.iter().any(|attr| attr.path.is_ident("refineable")) + f.attrs + .iter() + .any(|attr| attr.path().is_ident("refineable")) } fn is_optional_field(f: &Field) -> bool { diff --git a/crates/ui_macros/src/dynamic_spacing.rs b/crates/ui_macros/src/dynamic_spacing.rs index 6f9744e94c..bd7c72e90e 100644 --- a/crates/ui_macros/src/dynamic_spacing.rs +++ b/crates/ui_macros/src/dynamic_spacing.rs @@ -23,7 +23,7 @@ enum DynamicSpacingValue { impl Parse for DynamicSpacingInput { fn parse(input: ParseStream) -> syn::Result { Ok(DynamicSpacingInput { - values: input.parse_terminated(DynamicSpacingValue::parse)?, + values: input.parse_terminated(DynamicSpacingValue::parse, Token![,])?, }) } }