diff --git a/src/expr.rs b/src/expr.rs index 43c4154b6e..772f24948c 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -374,6 +374,7 @@ ast_struct! { #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub struct ExprClosure #full { pub attrs: Vec, + pub lifetimes: Option, pub movability: Option, pub asyncness: Option, pub capture: Option, @@ -1633,20 +1634,14 @@ pub(crate) mod parsing { } else if input.peek(Token![try]) && input.peek2(token::Brace) { input.parse().map(Expr::TryBlock) } else if input.peek(Token![|]) - || input.peek(Token![async]) && (input.peek2(Token![|]) || input.peek2(Token![move])) - || input.peek(Token![static]) || input.peek(Token![move]) + || input.peek(Token![for]) + && input.peek2(Token![<]) + && (input.peek3(Lifetime) || input.peek3(Token![>])) + || input.peek(Token![static]) + || input.peek(Token![async]) && (input.peek2(Token![|]) || input.peek2(Token![move])) { expr_closure(input, allow_struct).map(Expr::Closure) - } else if input.peek(Token![for]) - && input.peek2(Token![<]) - && (input.peek3(Lifetime) || input.peek3(Token![>])) - { - let begin = input.fork(); - input.parse::()?; - expr_closure(input, allow_struct)?; - let verbatim = verbatim::between(begin, input); - Ok(Expr::Verbatim(verbatim)) } else if input.peek(Ident) || input.peek(Token![::]) || input.peek(Token![<]) @@ -2346,6 +2341,7 @@ pub(crate) mod parsing { #[cfg(feature = "full")] fn expr_closure(input: ParseStream, allow_struct: AllowStruct) -> Result { + let lifetimes: Option = input.parse()?; let movability: Option = input.parse()?; let asyncness: Option = input.parse()?; let capture: Option = input.parse()?; @@ -2385,6 +2381,7 @@ pub(crate) mod parsing { Ok(ExprClosure { attrs: Vec::new(), + lifetimes, movability, asyncness, capture, @@ -3186,6 +3183,7 @@ pub(crate) mod printing { impl ToTokens for ExprClosure { fn to_tokens(&self, tokens: &mut TokenStream) { outer_attrs_to_tokens(&self.attrs, tokens); + self.lifetimes.to_tokens(tokens); self.movability.to_tokens(tokens); self.asyncness.to_tokens(tokens); self.capture.to_tokens(tokens); diff --git a/src/gen/clone.rs b/src/gen/clone.rs index b27b87475c..57960d07f5 100644 --- a/src/gen/clone.rs +++ b/src/gen/clone.rs @@ -414,6 +414,7 @@ impl Clone for ExprClosure { fn clone(&self) -> Self { ExprClosure { attrs: self.attrs.clone(), + lifetimes: self.lifetimes.clone(), movability: self.movability.clone(), asyncness: self.asyncness.clone(), capture: self.capture.clone(), diff --git a/src/gen/debug.rs b/src/gen/debug.rs index e2a0963c2d..d1cb3fa21c 100644 --- a/src/gen/debug.rs +++ b/src/gen/debug.rs @@ -732,6 +732,7 @@ impl Debug for ExprClosure { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { let mut formatter = formatter.debug_struct("ExprClosure"); formatter.field("attrs", &self.attrs); + formatter.field("lifetimes", &self.lifetimes); formatter.field("movability", &self.movability); formatter.field("asyncness", &self.asyncness); formatter.field("capture", &self.capture); diff --git a/src/gen/eq.rs b/src/gen/eq.rs index d9802f2b03..c172e90cb8 100644 --- a/src/gen/eq.rs +++ b/src/gen/eq.rs @@ -423,10 +423,10 @@ impl Eq for ExprClosure {} #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] impl PartialEq for ExprClosure { fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs && self.movability == other.movability - && self.asyncness == other.asyncness && self.capture == other.capture - && self.inputs == other.inputs && self.output == other.output - && self.body == other.body + self.attrs == other.attrs && self.lifetimes == other.lifetimes + && self.movability == other.movability && self.asyncness == other.asyncness + && self.capture == other.capture && self.inputs == other.inputs + && self.output == other.output && self.body == other.body } } #[cfg(feature = "full")] diff --git a/src/gen/fold.rs b/src/gen/fold.rs index da4424fb7e..8639aee419 100644 --- a/src/gen/fold.rs +++ b/src/gen/fold.rs @@ -1272,6 +1272,7 @@ where { ExprClosure { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), movability: (node.movability) .map(|it| Token![static](tokens_helper(f, &it.span))), asyncness: (node.asyncness).map(|it| Token![async](tokens_helper(f, &it.span))), diff --git a/src/gen/hash.rs b/src/gen/hash.rs index f32fc24804..347bc79776 100644 --- a/src/gen/hash.rs +++ b/src/gen/hash.rs @@ -646,6 +646,7 @@ impl Hash for ExprClosure { H: Hasher, { self.attrs.hash(state); + self.lifetimes.hash(state); self.movability.hash(state); self.asyncness.hash(state); self.capture.hash(state); diff --git a/src/gen/visit.rs b/src/gen/visit.rs index 34bd0b497c..f4122eda28 100644 --- a/src/gen/visit.rs +++ b/src/gen/visit.rs @@ -1378,6 +1378,9 @@ where for it in &node.attrs { v.visit_attribute(it); } + if let Some(it) = &node.lifetimes { + v.visit_bound_lifetimes(it); + } if let Some(it) = &node.movability { tokens_helper(v, &it.span); } diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs index d3216ee3e2..631aadd82c 100644 --- a/src/gen/visit_mut.rs +++ b/src/gen/visit_mut.rs @@ -1379,6 +1379,9 @@ where for it in &mut node.attrs { v.visit_attribute_mut(it); } + if let Some(it) = &mut node.lifetimes { + v.visit_bound_lifetimes_mut(it); + } if let Some(it) = &mut node.movability { tokens_helper(v, &mut it.span); } diff --git a/syn.json b/syn.json index adea26a5ba..a729046325 100644 --- a/syn.json +++ b/syn.json @@ -1089,6 +1089,11 @@ "syn": "Attribute" } }, + "lifetimes": { + "option": { + "syn": "BoundLifetimes" + } + }, "movability": { "option": { "token": "Static" diff --git a/tests/debug/gen.rs b/tests/debug/gen.rs index d4fc5d675e..65a5282012 100644 --- a/tests/debug/gen.rs +++ b/tests/debug/gen.rs @@ -590,6 +590,22 @@ impl Debug for Lite { if !_val.attrs.is_empty() { formatter.field("attrs", Lite(&_val.attrs)); } + if let Some(val) = &_val.lifetimes { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::BoundLifetimes); + 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("lifetimes", Print::ref_cast(val)); + } if let Some(val) = &_val.movability { #[derive(RefCast)] #[repr(transparent)] @@ -1301,6 +1317,22 @@ impl Debug for Lite { if !_val.attrs.is_empty() { formatter.field("attrs", Lite(&_val.attrs)); } + if let Some(val) = &_val.lifetimes { + #[derive(RefCast)] + #[repr(transparent)] + struct Print(syn::BoundLifetimes); + 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("lifetimes", Print::ref_cast(val)); + } if let Some(val) = &_val.movability { #[derive(RefCast)] #[repr(transparent)]