diff --git a/src/expr.rs b/src/expr.rs index ff36971c63..6345575c17 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -154,6 +154,9 @@ ast_enum_of_structs! { /// A square bracketed indexing expression: `vector[2]`. Index(ExprIndex), + /// The inferred value of a const generic argument, denoted `_`. + Infer(ExprInfer), + /// A `let` guard: `let Some(x) = opt`. Let(ExprLet), @@ -473,6 +476,14 @@ ast_struct! { } } +ast_struct! { + /// The inferred value of a const generic argument, denoted `_`. + pub struct ExprInfer #full { + pub attrs: Vec, + pub underscore_token: Token![_], + } +} + ast_struct! { /// A `let` guard: `let Some(x) = opt`. #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] @@ -740,6 +751,7 @@ impl Expr { | Expr::Group(ExprGroup { attrs, .. }) | Expr::If(ExprIf { attrs, .. }) | Expr::Index(ExprIndex { attrs, .. }) + | Expr::Infer(ExprInfer { attrs, .. }) | Expr::Let(ExprLet { attrs, .. }) | Expr::Lit(ExprLit { attrs, .. }) | Expr::Loop(ExprLoop { attrs, .. }) @@ -1005,8 +1017,6 @@ pub(crate) mod parsing { use crate::parse::ParseBuffer; use crate::parse::{Parse, ParseStream, Result}; use crate::path; - #[cfg(feature = "full")] - use proc_macro2::TokenTree; use std::cmp::Ordering; crate::custom_keyword!(raw); @@ -1687,9 +1697,7 @@ pub(crate) mod parsing { } else if input.peek(Token![..]) { expr_range(input, allow_struct).map(Expr::Range) } else if input.peek(Token![_]) { - Ok(Expr::Verbatim(TokenStream::from( - input.parse::()?, - ))) + input.parse().map(Expr::Infer) } else if input.peek(Lifetime) { let the_label: Label = input.parse()?; let mut expr = if input.peek(Token![while]) { @@ -2103,6 +2111,17 @@ pub(crate) mod parsing { Ok((else_token, Box::new(else_branch))) } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] + impl Parse for ExprInfer { + fn parse(input: ParseStream) -> Result { + Ok(ExprInfer { + attrs: input.call(Attribute::parse_outer)?, + underscore_token: input.parse()?, + }) + } + } + #[cfg(feature = "full")] #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] impl Parse for ExprForLoop { @@ -3293,6 +3312,15 @@ pub(crate) mod printing { } } + #[cfg(feature = "full")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] + impl ToTokens for ExprInfer { + fn to_tokens(&self, tokens: &mut TokenStream) { + outer_attrs_to_tokens(&self.attrs, tokens); + self.underscore_token.to_tokens(tokens); + } + } + #[cfg(feature = "full")] #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ToTokens for RangeLimits { diff --git a/src/gen/clone.rs b/src/gen/clone.rs index d30cb85760..7100fa4211 100644 --- a/src/gen/clone.rs +++ b/src/gen/clone.rs @@ -236,6 +236,8 @@ impl Clone for Expr { Expr::If(v0) => Expr::If(v0.clone()), Expr::Index(v0) => Expr::Index(v0.clone()), #[cfg(feature = "full")] + Expr::Infer(v0) => Expr::Infer(v0.clone()), + #[cfg(feature = "full")] Expr::Let(v0) => Expr::Let(v0.clone()), Expr::Lit(v0) => Expr::Lit(v0.clone()), #[cfg(feature = "full")] @@ -514,6 +516,16 @@ impl Clone for ExprIndex { } #[cfg(feature = "full")] #[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))] +impl Clone for ExprInfer { + fn clone(&self) -> Self { + ExprInfer { + attrs: self.attrs.clone(), + underscore_token: self.underscore_token.clone(), + } + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))] impl Clone for ExprLet { fn clone(&self) -> Self { ExprLet { diff --git a/src/gen/debug.rs b/src/gen/debug.rs index bb59cf1c8c..de0c9de39c 100644 --- a/src/gen/debug.rs +++ b/src/gen/debug.rs @@ -466,6 +466,12 @@ impl Debug for Expr { formatter.finish() } #[cfg(feature = "full")] + Expr::Infer(v0) => { + let mut formatter = formatter.debug_tuple("Infer"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] Expr::Let(v0) => { let mut formatter = formatter.debug_tuple("Let"); formatter.field(v0); @@ -832,6 +838,16 @@ impl Debug for ExprIndex { } #[cfg(feature = "full")] #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] +impl Debug for ExprInfer { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprInfer"); + formatter.field("attrs", &self.attrs); + formatter.field("underscore_token", &self.underscore_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] impl Debug for ExprLet { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { let mut formatter = formatter.debug_struct("ExprLet"); diff --git a/src/gen/eq.rs b/src/gen/eq.rs index 936eede789..b282c7a741 100644 --- a/src/gen/eq.rs +++ b/src/gen/eq.rs @@ -258,6 +258,8 @@ impl PartialEq for Expr { (Expr::If(self0), Expr::If(other0)) => self0 == other0, (Expr::Index(self0), Expr::Index(other0)) => self0 == other0, #[cfg(feature = "full")] + (Expr::Infer(self0), Expr::Infer(other0)) => self0 == other0, + #[cfg(feature = "full")] (Expr::Let(self0), Expr::Let(other0)) => self0 == other0, (Expr::Lit(self0), Expr::Lit(other0)) => self0 == other0, #[cfg(feature = "full")] @@ -506,6 +508,16 @@ impl PartialEq for ExprIndex { } #[cfg(feature = "full")] #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] +impl Eq for ExprInfer {} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] +impl PartialEq for ExprInfer { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] impl Eq for ExprLet {} #[cfg(feature = "full")] #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] diff --git a/src/gen/fold.rs b/src/gen/fold.rs index 89ba5b77e7..3f118a9ab5 100644 --- a/src/gen/fold.rs +++ b/src/gen/fold.rs @@ -179,6 +179,10 @@ pub trait Fold { fold_expr_index(self, i) } #[cfg(feature = "full")] + fn fold_expr_infer(&mut self, i: ExprInfer) -> ExprInfer { + fold_expr_infer(self, i) + } + #[cfg(feature = "full")] fn fold_expr_let(&mut self, i: ExprLet) -> ExprLet { fold_expr_let(self, i) } @@ -1104,6 +1108,7 @@ where Expr::Group(_binding_0) => Expr::Group(full!(f.fold_expr_group(_binding_0))), Expr::If(_binding_0) => Expr::If(full!(f.fold_expr_if(_binding_0))), Expr::Index(_binding_0) => Expr::Index(f.fold_expr_index(_binding_0)), + Expr::Infer(_binding_0) => Expr::Infer(full!(f.fold_expr_infer(_binding_0))), Expr::Let(_binding_0) => Expr::Let(full!(f.fold_expr_let(_binding_0))), Expr::Lit(_binding_0) => Expr::Lit(f.fold_expr_lit(_binding_0)), Expr::Loop(_binding_0) => Expr::Loop(full!(f.fold_expr_loop(_binding_0))), @@ -1375,6 +1380,16 @@ where } } #[cfg(feature = "full")] +pub fn fold_expr_infer(f: &mut F, node: ExprInfer) -> ExprInfer +where + F: Fold + ?Sized, +{ + ExprInfer { + attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), + underscore_token: Token![_](tokens_helper(f, &node.underscore_token.spans)), + } +} +#[cfg(feature = "full")] pub fn fold_expr_let(f: &mut F, node: ExprLet) -> ExprLet where F: Fold + ?Sized, diff --git a/src/gen/hash.rs b/src/gen/hash.rs index 2e0dd4840e..2d861d2d15 100644 --- a/src/gen/hash.rs +++ b/src/gen/hash.rs @@ -398,108 +398,113 @@ impl Hash for Expr { v0.hash(state); } #[cfg(feature = "full")] - Expr::Let(v0) => { + Expr::Infer(v0) => { state.write_u8(19u8); v0.hash(state); } - Expr::Lit(v0) => { + #[cfg(feature = "full")] + Expr::Let(v0) => { state.write_u8(20u8); v0.hash(state); } + Expr::Lit(v0) => { + state.write_u8(21u8); + v0.hash(state); + } #[cfg(feature = "full")] Expr::Loop(v0) => { - state.write_u8(21u8); + state.write_u8(22u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Macro(v0) => { - state.write_u8(22u8); + state.write_u8(23u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Match(v0) => { - state.write_u8(23u8); + state.write_u8(24u8); v0.hash(state); } #[cfg(feature = "full")] Expr::MethodCall(v0) => { - state.write_u8(24u8); + state.write_u8(25u8); v0.hash(state); } Expr::Paren(v0) => { - state.write_u8(25u8); + state.write_u8(26u8); v0.hash(state); } Expr::Path(v0) => { - state.write_u8(26u8); + state.write_u8(27u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Range(v0) => { - state.write_u8(27u8); + state.write_u8(28u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Reference(v0) => { - state.write_u8(28u8); + state.write_u8(29u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Repeat(v0) => { - state.write_u8(29u8); + state.write_u8(30u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Return(v0) => { - state.write_u8(30u8); + state.write_u8(31u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Struct(v0) => { - state.write_u8(31u8); + state.write_u8(32u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Try(v0) => { - state.write_u8(32u8); + state.write_u8(33u8); v0.hash(state); } #[cfg(feature = "full")] Expr::TryBlock(v0) => { - state.write_u8(33u8); + state.write_u8(34u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Tuple(v0) => { - state.write_u8(34u8); + state.write_u8(35u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Type(v0) => { - state.write_u8(35u8); + state.write_u8(36u8); v0.hash(state); } Expr::Unary(v0) => { - state.write_u8(36u8); + state.write_u8(37u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Unsafe(v0) => { - state.write_u8(37u8); + state.write_u8(38u8); v0.hash(state); } Expr::Verbatim(v0) => { - state.write_u8(38u8); + state.write_u8(39u8); TokenStreamHelper(v0).hash(state); } #[cfg(feature = "full")] Expr::While(v0) => { - state.write_u8(39u8); + state.write_u8(40u8); v0.hash(state); } #[cfg(feature = "full")] Expr::Yield(v0) => { - state.write_u8(40u8); + state.write_u8(41u8); v0.hash(state); } #[cfg(any(syn_no_non_exhaustive, not(feature = "full")))] @@ -742,6 +747,16 @@ impl Hash for ExprIndex { } #[cfg(feature = "full")] #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] +impl Hash for ExprInfer { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + } +} +#[cfg(feature = "full")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))] impl Hash for ExprLet { fn hash(&self, state: &mut H) where diff --git a/src/gen/visit.rs b/src/gen/visit.rs index 8502acd1f0..e099d85c9f 100644 --- a/src/gen/visit.rs +++ b/src/gen/visit.rs @@ -181,6 +181,10 @@ pub trait Visit<'ast> { visit_expr_index(self, i); } #[cfg(feature = "full")] + fn visit_expr_infer(&mut self, i: &'ast ExprInfer) { + visit_expr_infer(self, i); + } + #[cfg(feature = "full")] fn visit_expr_let(&mut self, i: &'ast ExprLet) { visit_expr_let(self, i); } @@ -1151,6 +1155,9 @@ where Expr::Index(_binding_0) => { v.visit_expr_index(_binding_0); } + Expr::Infer(_binding_0) => { + full!(v.visit_expr_infer(_binding_0)); + } Expr::Let(_binding_0) => { full!(v.visit_expr_let(_binding_0)); } @@ -1498,6 +1505,16 @@ where v.visit_expr(&*node.index); } #[cfg(feature = "full")] +pub fn visit_expr_infer<'ast, V>(v: &mut V, node: &'ast ExprInfer) +where + V: Visit<'ast> + ?Sized, +{ + for it in &node.attrs { + v.visit_attribute(it); + } + tokens_helper(v, &node.underscore_token.spans); +} +#[cfg(feature = "full")] pub fn visit_expr_let<'ast, V>(v: &mut V, node: &'ast ExprLet) where V: Visit<'ast> + ?Sized, diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs index b06f6e3e0c..58464157fd 100644 --- a/src/gen/visit_mut.rs +++ b/src/gen/visit_mut.rs @@ -182,6 +182,10 @@ pub trait VisitMut { visit_expr_index_mut(self, i); } #[cfg(feature = "full")] + fn visit_expr_infer_mut(&mut self, i: &mut ExprInfer) { + visit_expr_infer_mut(self, i); + } + #[cfg(feature = "full")] fn visit_expr_let_mut(&mut self, i: &mut ExprLet) { visit_expr_let_mut(self, i); } @@ -1152,6 +1156,9 @@ where Expr::Index(_binding_0) => { v.visit_expr_index_mut(_binding_0); } + Expr::Infer(_binding_0) => { + full!(v.visit_expr_infer_mut(_binding_0)); + } Expr::Let(_binding_0) => { full!(v.visit_expr_let_mut(_binding_0)); } @@ -1499,6 +1506,16 @@ where v.visit_expr_mut(&mut *node.index); } #[cfg(feature = "full")] +pub fn visit_expr_infer_mut(v: &mut V, node: &mut ExprInfer) +where + V: VisitMut + ?Sized, +{ + for it in &mut node.attrs { + v.visit_attribute_mut(it); + } + tokens_helper(v, &mut node.underscore_token.spans); +} +#[cfg(feature = "full")] pub fn visit_expr_let_mut(v: &mut V, node: &mut ExprLet) where V: VisitMut + ?Sized, diff --git a/src/lib.rs b/src/lib.rs index 024286aada..69768e8130 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -349,10 +349,10 @@ pub use crate::expr::{ pub use crate::expr::{ Expr, ExprArray, ExprAssign, ExprAssignOp, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBox, ExprBreak, ExprCall, ExprCast, ExprClosure, ExprConst, ExprContinue, ExprField, - ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprLet, ExprLit, ExprLoop, ExprMacro, ExprMatch, - ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn, - ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, ExprWhile, - ExprYield, Index, Member, + ExprForLoop, ExprGroup, ExprIf, ExprIndex, ExprInfer, ExprLet, ExprLit, ExprLoop, ExprMacro, + ExprMatch, ExprMethodCall, ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, + ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprType, ExprUnary, ExprUnsafe, + ExprWhile, ExprYield, Index, Member, }; #[cfg(feature = "parsing")] diff --git a/syn.json b/syn.json index b9cc89f1cd..efbec7d1ea 100644 --- a/syn.json +++ b/syn.json @@ -663,6 +663,11 @@ "syn": "ExprIndex" } ], + "Infer": [ + { + "syn": "ExprInfer" + } + ], "Let": [ { "syn": "ExprLet" @@ -1338,6 +1343,24 @@ } } }, + { + "ident": "ExprInfer", + "features": { + "any": [ + "full" + ] + }, + "fields": { + "attrs": { + "vec": { + "syn": "Attribute" + } + }, + "underscore_token": { + "token": "Underscore" + } + } + }, { "ident": "ExprLet", "features": { diff --git a/tests/debug/gen.rs b/tests/debug/gen.rs index 0351c298a9..d08b6452c4 100644 --- a/tests/debug/gen.rs +++ b/tests/debug/gen.rs @@ -769,6 +769,13 @@ impl Debug for Lite { formatter.field("index", Lite(&_val.index)); formatter.finish() } + syn::Expr::Infer(_val) => { + let mut formatter = formatter.debug_struct("Expr::Infer"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.finish() + } syn::Expr::Let(_val) => { let mut formatter = formatter.debug_struct("Expr::Let"); if !_val.attrs.is_empty() { @@ -1546,6 +1553,16 @@ impl Debug for Lite { formatter.finish() } } +impl Debug for Lite { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let _val = &self.value; + let mut formatter = formatter.debug_struct("ExprInfer"); + if !_val.attrs.is_empty() { + formatter.field("attrs", Lite(&_val.attrs)); + } + formatter.finish() + } +} impl Debug for Lite { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { let _val = &self.value;