diff options
Diffstat (limited to 'vendor/syn/tests/test_expr.rs')
| -rw-r--r-- | vendor/syn/tests/test_expr.rs | 1699 |
1 files changed, 0 insertions, 1699 deletions
diff --git a/vendor/syn/tests/test_expr.rs b/vendor/syn/tests/test_expr.rs deleted file mode 100644 index e23d0bd9..00000000 --- a/vendor/syn/tests/test_expr.rs +++ /dev/null @@ -1,1699 +0,0 @@ -#![cfg(not(miri))] -#![recursion_limit = "1024"] -#![feature(rustc_private)] -#![allow( - clippy::elidable_lifetime_names, - clippy::match_like_matches_macro, - clippy::needless_lifetimes, - clippy::single_element_loop, - clippy::too_many_lines, - clippy::uninlined_format_args, - clippy::unreadable_literal -)] - -#[macro_use] -mod macros; - -mod common; - -use crate::common::visit::{AsIfPrinted, FlattenParens}; -use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream}; -use quote::{quote, ToTokens as _}; -use std::process::ExitCode; -use syn::punctuated::Punctuated; -use syn::visit_mut::VisitMut as _; -use syn::{ - parse_quote, token, AngleBracketedGenericArguments, Arm, BinOp, Block, Expr, ExprArray, - ExprAssign, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBreak, ExprCall, ExprCast, - ExprClosure, ExprConst, ExprContinue, ExprField, ExprForLoop, ExprIf, ExprIndex, ExprLet, - ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall, ExprPath, ExprRange, ExprRawAddr, - ExprReference, ExprReturn, ExprStruct, ExprTry, ExprTryBlock, ExprTuple, ExprUnary, ExprUnsafe, - ExprWhile, ExprYield, GenericArgument, Label, Lifetime, Lit, LitInt, Macro, MacroDelimiter, - Member, Pat, PatWild, Path, PathArguments, PathSegment, PointerMutability, QSelf, RangeLimits, - ReturnType, Stmt, Token, Type, TypePath, UnOp, -}; - -#[test] -fn test_expr_parse() { - let tokens = quote!(..100u32); - snapshot!(tokens as Expr, @r#" - Expr::Range { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Lit { - lit: 100u32, - }), - } - "#); - - let tokens = quote!(..100u32); - snapshot!(tokens as ExprRange, @r#" - ExprRange { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Lit { - lit: 100u32, - }), - } - "#); -} - -#[test] -fn test_await() { - // Must not parse as Expr::Field. - let tokens = quote!(fut.await); - - snapshot!(tokens as Expr, @r#" - Expr::Await { - base: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "fut", - }, - ], - }, - }, - } - "#); -} - -#[rustfmt::skip] -#[test] -fn test_tuple_multi_index() { - let expected = snapshot!("tuple.0.0" as Expr, @r#" - Expr::Field { - base: Expr::Field { - base: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "tuple", - }, - ], - }, - }, - member: Member::Unnamed(Index { - index: 0, - }), - }, - member: Member::Unnamed(Index { - index: 0, - }), - } - "#); - - for &input in &[ - "tuple .0.0", - "tuple. 0.0", - "tuple.0 .0", - "tuple.0. 0", - "tuple . 0 . 0", - ] { - assert_eq!(expected, syn::parse_str(input).unwrap()); - } - - for tokens in [ - quote!(tuple.0.0), - quote!(tuple .0.0), - quote!(tuple. 0.0), - quote!(tuple.0 .0), - quote!(tuple.0. 0), - quote!(tuple . 0 . 0), - ] { - assert_eq!(expected, syn::parse2(tokens).unwrap()); - } -} - -#[test] -fn test_macro_variable_func() { - // mimics the token stream corresponding to `$fn()` - let path = Group::new(Delimiter::None, quote!(f)); - let tokens = quote!(#path()); - - snapshot!(tokens as Expr, @r#" - Expr::Call { - func: Expr::Group { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "f", - }, - ], - }, - }, - }, - } - "#); - - let path = Group::new(Delimiter::None, quote! { #[inside] f }); - let tokens = quote!(#[outside] #path()); - - snapshot!(tokens as Expr, @r#" - Expr::Call { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "outside", - }, - ], - }, - }, - ], - func: Expr::Group { - expr: Expr::Path { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "inside", - }, - ], - }, - }, - ], - path: Path { - segments: [ - PathSegment { - ident: "f", - }, - ], - }, - }, - }, - } - "#); -} - -#[test] -fn test_macro_variable_macro() { - // mimics the token stream corresponding to `$macro!()` - let mac = Group::new(Delimiter::None, quote!(m)); - let tokens = quote!(#mac!()); - - snapshot!(tokens as Expr, @r#" - Expr::Macro { - mac: Macro { - path: Path { - segments: [ - PathSegment { - ident: "m", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(``), - }, - } - "#); -} - -#[test] -fn test_macro_variable_struct() { - // mimics the token stream corresponding to `$struct {}` - let s = Group::new(Delimiter::None, quote! { S }); - let tokens = quote!(#s {}); - - snapshot!(tokens as Expr, @r#" - Expr::Struct { - path: Path { - segments: [ - PathSegment { - ident: "S", - }, - ], - }, - } - "#); -} - -#[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 }` - let expr = Group::new(Delimiter::None, quote! { #[a] () }); - let tokens = quote!(match v { _ => #expr }); - snapshot!(tokens as Expr, @r#" - Expr::Match { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "v", - }, - ], - }, - }, - arms: [ - Arm { - pat: Pat::Wild, - body: Expr::Group { - expr: Expr::Tuple { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::Path { - segments: [ - PathSegment { - ident: "a", - }, - ], - }, - }, - ], - }, - }, - }, - ], - } - "#); - - let expr = Group::new(Delimiter::None, quote!(loop {} + 1)); - let tokens = quote!(match v { _ => #expr }); - snapshot!(tokens as Expr, @r#" - Expr::Match { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "v", - }, - ], - }, - }, - arms: [ - Arm { - pat: Pat::Wild, - body: Expr::Group { - expr: Expr::Binary { - left: Expr::Loop { - body: Block { - stmts: [], - }, - }, - op: BinOp::Add, - right: Expr::Lit { - lit: 1, - }, - }, - }, - }, - ], - } - "#); -} - -// https://github.com/dtolnay/syn/issues/1019 -#[test] -fn test_closure_vs_rangefull() { - #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/4808 - let tokens = quote!(|| .. .method()); - snapshot!(tokens as Expr, @r#" - Expr::MethodCall { - receiver: Expr::Closure { - output: ReturnType::Default, - body: Expr::Range { - limits: RangeLimits::HalfOpen, - }, - }, - method: "method", - } - "#); -} - -#[test] -fn test_postfix_operator_after_cast() { - syn::parse_str::<Expr>("|| &x as T[0]").unwrap_err(); - syn::parse_str::<Expr>("|| () as ()()").unwrap_err(); -} - -#[test] -fn test_range_kinds() { - syn::parse_str::<Expr>("..").unwrap(); - syn::parse_str::<Expr>("..hi").unwrap(); - syn::parse_str::<Expr>("lo..").unwrap(); - syn::parse_str::<Expr>("lo..hi").unwrap(); - - syn::parse_str::<Expr>("..=").unwrap_err(); - syn::parse_str::<Expr>("..=hi").unwrap(); - syn::parse_str::<Expr>("lo..=").unwrap_err(); - syn::parse_str::<Expr>("lo..=hi").unwrap(); - - syn::parse_str::<Expr>("...").unwrap_err(); - syn::parse_str::<Expr>("...hi").unwrap_err(); - syn::parse_str::<Expr>("lo...").unwrap_err(); - syn::parse_str::<Expr>("lo...hi").unwrap_err(); -} - -#[test] -fn test_range_precedence() { - snapshot!(".. .." as Expr, @r#" - Expr::Range { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - } - "#); - - snapshot!(".. .. ()" as Expr, @r#" - Expr::Range { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - end: Some(Expr::Tuple), - }), - } - "#); - - snapshot!("() .. .." as Expr, @r#" - Expr::Range { - start: Some(Expr::Tuple), - limits: RangeLimits::HalfOpen, - end: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - } - "#); - - snapshot!("() = .. + ()" as Expr, @r" - Expr::Binary { - left: Expr::Assign { - left: Expr::Tuple, - right: Expr::Range { - limits: RangeLimits::HalfOpen, - }, - }, - op: BinOp::Add, - right: Expr::Tuple, - } - "); - - // A range with a lower bound cannot be the upper bound of another range, - // and a range with an upper bound cannot be the lower bound of another - // range. - syn::parse_str::<Expr>(".. x ..").unwrap_err(); - syn::parse_str::<Expr>("x .. x ..").unwrap_err(); -} - -#[test] -fn test_range_attrs() { - // Attributes are not allowed on range expressions starting with `..` - syn::parse_str::<Expr>("#[allow()] ..").unwrap_err(); - syn::parse_str::<Expr>("#[allow()] .. hi").unwrap_err(); - - snapshot!("#[allow()] lo .. hi" as Expr, @r#" - Expr::Range { - start: Some(Expr::Path { - attrs: [ - Attribute { - style: AttrStyle::Outer, - meta: Meta::List { - path: Path { - segments: [ - PathSegment { - ident: "allow", - }, - ], - }, - delimiter: MacroDelimiter::Paren, - tokens: TokenStream(``), - }, - }, - ], - path: Path { - segments: [ - PathSegment { - ident: "lo", - }, - ], - }, - }), - limits: RangeLimits::HalfOpen, - end: Some(Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "hi", - }, - ], - }, - }), - } - "#); -} - -#[test] -fn test_ranges_bailout() { - syn::parse_str::<Expr>(".. ?").unwrap_err(); - syn::parse_str::<Expr>(".. .field").unwrap_err(); - - snapshot!("return .. ?" as Expr, @r" - Expr::Try { - expr: Expr::Return { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - } - "); - - snapshot!("break .. ?" as Expr, @r" - Expr::Try { - expr: Expr::Break { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - } - "); - - snapshot!("|| .. ?" as Expr, @r" - Expr::Try { - expr: Expr::Closure { - output: ReturnType::Default, - body: Expr::Range { - limits: RangeLimits::HalfOpen, - }, - }, - } - "); - - snapshot!("return .. .field" as Expr, @r#" - Expr::Field { - base: Expr::Return { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - member: Member::Named("field"), - } - "#); - - snapshot!("break .. .field" as Expr, @r#" - Expr::Field { - base: Expr::Break { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - member: Member::Named("field"), - } - "#); - - snapshot!("|| .. .field" as Expr, @r#" - Expr::Field { - base: Expr::Closure { - output: ReturnType::Default, - body: Expr::Range { - limits: RangeLimits::HalfOpen, - }, - }, - member: Member::Named("field"), - } - "#); - - snapshot!("return .. = ()" as Expr, @r" - Expr::Assign { - left: Expr::Return { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - right: Expr::Tuple, - } - "); - - snapshot!("return .. += ()" as Expr, @r" - Expr::Binary { - left: Expr::Return { - expr: Some(Expr::Range { - limits: RangeLimits::HalfOpen, - }), - }, - op: BinOp::AddAssign, - right: Expr::Tuple, - } - "); -} - -#[test] -fn test_ambiguous_label() { - for stmt in [ - quote! { - return 'label: loop { break 'label 42; }; - }, - quote! { - break ('label: loop { break 'label 42; }); - }, - quote! { - break 1 + 'label: loop { break 'label 42; }; - }, - quote! { - break 'outer 'inner: loop { break 'inner 42; }; - }, - ] { - syn::parse2::<Stmt>(stmt).unwrap(); - } - - for stmt in [ - // Parentheses required. See https://github.com/rust-lang/rust/pull/87026. - quote! { - break 'label: loop { break 'label 42; }; - }, - ] { - syn::parse2::<Stmt>(stmt).unwrap_err(); - } -} - -#[test] -fn test_extended_interpolated_path() { - let path = Group::new(Delimiter::None, quote!(a::b)); - - let tokens = quote!(if #path {}); - snapshot!(tokens as Expr, @r#" - Expr::If { - cond: Expr::Group { - expr: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "a", - }, - Token![::], - PathSegment { - ident: "b", - }, - ], - }, - }, - }, - then_branch: Block { - stmts: [], - }, - } - "#); - - let tokens = quote!(#path {}); - snapshot!(tokens as Expr, @r#" - Expr::Struct { - path: Path { - segments: [ - PathSegment { - ident: "a", - }, - Token![::], - PathSegment { - ident: "b", - }, - ], - }, - } - "#); - - let tokens = quote!(#path :: c); - snapshot!(tokens as Expr, @r#" - Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "a", - }, - Token![::], - PathSegment { - ident: "b", - }, - Token![::], - PathSegment { - ident: "c", - }, - ], - }, - } - "#); - - let nested = Group::new(Delimiter::None, quote!(a::b || true)); - let tokens = quote!(if #nested && false {}); - snapshot!(tokens as Expr, @r#" - Expr::If { - cond: Expr::Binary { - left: Expr::Group { - expr: Expr::Binary { - left: Expr::Path { - path: Path { - segments: [ - PathSegment { - ident: "a", - }, - Token![::], - PathSegment { - ident: "b", - }, - ], - }, - }, - op: BinOp::Or, - right: Expr::Lit { - lit: Lit::Bool { - value: true, - }, - }, - }, - }, - op: BinOp::And, - right: Expr::Lit { - lit: Lit::Bool { - value: false, - }, - }, - }, - then_branch: Block { - stmts: [], - }, - } - "#); -} - -#[test] -fn test_tuple_comma() { - let mut expr = ExprTuple { - attrs: Vec::new(), - paren_token: token::Paren::default(), - elems: Punctuated::new(), - }; - snapshot!(expr.to_token_stream() as Expr, @"Expr::Tuple"); - - expr.elems.push_value(parse_quote!(continue)); - // Must not parse to Expr::Paren - snapshot!(expr.to_token_stream() as Expr, @r#" - Expr::Tuple { - elems: [ - Expr::Continue, - Token![,], - ], - } - "#); - - expr.elems.push_punct(<Token![,]>::default()); - snapshot!(expr.to_token_stream() as Expr, @r#" - Expr::Tuple { - elems: [ - Expr::Continue, - Token![,], - ], - } - "#); - - expr.elems.push_value(parse_quote!(continue)); - snapshot!(expr.to_token_stream() as Expr, @r#" - Expr::Tuple { - elems: [ - Expr::Continue, - Token![,], - Expr::Continue, - ], - } - "#); - - expr.elems.push_punct(<Token![,]>::default()); - snapshot!(expr.to_token_stream() as Expr, @r#" - Expr::Tuple { - elems: [ - Expr::Continue, - Token![,], - Expr::Continue, - Token![,], - ], - } - "#); -} - -#[test] -fn test_binop_associativity() { - // Left to right. - snapshot!("() + () + ()" as Expr, @r#" - Expr::Binary { - left: Expr::Binary { - left: Expr::Tuple, - op: BinOp::Add, - right: Expr::Tuple, - }, - op: BinOp::Add, - right: Expr::Tuple, - } - "#); - - // Right to left. - snapshot!("() += () += ()" as Expr, @r#" - Expr::Binary { - left: Expr::Tuple, - op: BinOp::AddAssign, - right: Expr::Binary { - left: Expr::Tuple, - op: BinOp::AddAssign, - right: Expr::Tuple, - }, - } - "#); - - // Parenthesization is required. - syn::parse_str::<Expr>("() == () == ()").unwrap_err(); -} - -#[test] -fn test_assign_range_precedence() { - // Range has higher precedence as the right-hand of an assignment, but - // ambiguous precedence as the left-hand of an assignment. - snapshot!("() = () .. ()" as Expr, @r#" - Expr::Assign { - left: Expr::Tuple, - right: Expr::Range { - start: Some(Expr::Tuple), - limits: RangeLimits::HalfOpen, - end: Some(Expr::Tuple), - }, - } - "#); - - snapshot!("() += () .. ()" as Expr, @r#" - Expr::Binary { - left: Expr::Tuple, - op: BinOp::AddAssign, - right: Expr::Range { - start: Some(Expr::Tuple), - limits: RangeLimits::HalfOpen, - end: Some(Expr::Tuple), - }, - } - "#); - - syn::parse_str::<Expr>("() .. () = ()").unwrap_err(); - syn::parse_str::<Expr>("() .. () += ()").unwrap_err(); -} - -#[test] -fn test_chained_comparison() { - // https://github.com/dtolnay/syn/issues/1738 - let _ = syn::parse_str::<Expr>("a = a < a <"); - let _ = syn::parse_str::<Expr>("a = a .. a .."); - let _ = syn::parse_str::<Expr>("a = a .. a +="); - - let err = syn::parse_str::<Expr>("a < a < a").unwrap_err(); - assert_eq!("comparison operators cannot be chained", err.to_string()); - - let err = syn::parse_str::<Expr>("a .. a .. a").unwrap_err(); - assert_eq!("unexpected token", err.to_string()); - - let err = syn::parse_str::<Expr>("a .. a += a").unwrap_err(); - assert_eq!("unexpected token", err.to_string()); -} - -#[test] -fn test_fixup() { - for tokens in [ - quote! { 2 * (1 + 1) }, - quote! { 0 + (0 + 0) }, - quote! { (a = b) = c }, - quote! { (x as i32) < 0 }, - quote! { 1 + (x as i32) < 0 }, - quote! { (1 + 1).abs() }, - quote! { (lo..hi)[..] }, - quote! { (a..b)..(c..d) }, - quote! { (x > ..) > x }, - quote! { (&mut fut).await }, - quote! { &mut (x as i32) }, - quote! { -(x as i32) }, - quote! { if (S {}) == 1 {} }, - quote! { { (m! {}) - 1 } }, - quote! { match m { _ => ({}) - 1 } }, - quote! { if let _ = (a && b) && c {} }, - quote! { if let _ = (S {}) {} }, - quote! { if (S {}) == 0 && let Some(_) = x {} }, - quote! { break ('a: loop { break 'a 1 } + 1) }, - quote! { a + (|| b) + c }, - quote! { if let _ = ((break) - 1 || true) {} }, - quote! { if let _ = (break + 1 || true) {} }, - quote! { if break (break) {} }, - quote! { if break break {} {} }, - quote! { if return (..) {} }, - quote! { if return .. {} {} }, - quote! { if || (Struct {}) {} }, - quote! { if || (Struct {}).await {} }, - quote! { if break || Struct {}.await {} }, - quote! { if break 'outer 'block: {} {} }, - quote! { if ..'block: {} {} }, - quote! { if break ({}).await {} }, - quote! { (break)() }, - quote! { (..) = () }, - quote! { (..) += () }, - quote! { (1 < 2) == (3 < 4) }, - quote! { { (let _ = ()) } }, - quote! { (#[attr] thing).field }, - quote! { #[attr] (1 + 1) }, - quote! { #[attr] (x = 1) }, - quote! { #[attr] (x += 1) }, - quote! { #[attr] (1 as T) }, - quote! { (return #[attr] (x + ..)).field }, - quote! { (self.f)() }, - quote! { (return)..=return }, - quote! { 1 + (return)..=1 + return }, - quote! { .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. }, - ] { - let original: Expr = syn::parse2(tokens).unwrap(); - - let mut flat = original.clone(); - FlattenParens::combine_attrs().visit_expr_mut(&mut flat); - let reconstructed: Expr = match syn::parse2(flat.to_token_stream()) { - Ok(reconstructed) => reconstructed, - Err(err) => panic!("failed to parse `{}`: {}", flat.to_token_stream(), err), - }; - - assert!( - original == reconstructed, - "original: {}\n{:#?}\nreconstructed: {}\n{:#?}", - original.to_token_stream(), - crate::macros::debug::Lite(&original), - reconstructed.to_token_stream(), - crate::macros::debug::Lite(&reconstructed), - ); - } -} - -#[test] -fn test_permutations() -> ExitCode { - fn iter(depth: usize, f: &mut dyn FnMut(Expr)) { - let span = Span::call_site(); - - // Expr::Path - f(Expr::Path(ExprPath { - // `x` - attrs: Vec::new(), - qself: None, - path: Path::from(Ident::new("x", span)), - })); - if false { - f(Expr::Path(ExprPath { - // `x::<T>` - attrs: Vec::new(), - qself: None, - path: Path { - leading_colon: None, - segments: Punctuated::from_iter([PathSegment { - ident: Ident::new("x", span), - arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { - colon2_token: Some(Token), - lt_token: Token, - args: Punctuated::from_iter([GenericArgument::Type(Type::Path( - TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - }, - ))]), - gt_token: Token, - }), - }]), - }, - })); - f(Expr::Path(ExprPath { - // `<T as Trait>::CONST` - attrs: Vec::new(), - qself: Some(QSelf { - lt_token: Token, - ty: Box::new(Type::Path(TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - })), - position: 1, - as_token: Some(Token), - gt_token: Token, - }), - path: Path { - leading_colon: None, - segments: Punctuated::from_iter([ - PathSegment::from(Ident::new("Trait", span)), - PathSegment::from(Ident::new("CONST", span)), - ]), - }, - })); - } - - let Some(depth) = depth.checked_sub(1) else { - return; - }; - - // Expr::Assign - iter(depth, &mut |expr| { - iter(0, &mut |simple| { - f(Expr::Assign(ExprAssign { - // `x = $expr` - attrs: Vec::new(), - left: Box::new(simple.clone()), - eq_token: Token, - right: Box::new(expr.clone()), - })); - f(Expr::Assign(ExprAssign { - // `$expr = x` - attrs: Vec::new(), - left: Box::new(expr.clone()), - eq_token: Token, - right: Box::new(simple), - })); - }); - }); - - // Expr::Binary - iter(depth, &mut |expr| { - iter(0, &mut |simple| { - for op in [ - BinOp::Add(Token), - //BinOp::Sub(Token), - //BinOp::Mul(Token), - //BinOp::Div(Token), - //BinOp::Rem(Token), - //BinOp::And(Token), - //BinOp::Or(Token), - //BinOp::BitXor(Token), - //BinOp::BitAnd(Token), - //BinOp::BitOr(Token), - //BinOp::Shl(Token), - //BinOp::Shr(Token), - //BinOp::Eq(Token), - BinOp::Lt(Token), - //BinOp::Le(Token), - //BinOp::Ne(Token), - //BinOp::Ge(Token), - //BinOp::Gt(Token), - BinOp::ShlAssign(Token), - ] { - f(Expr::Binary(ExprBinary { - // `x + $expr` - attrs: Vec::new(), - left: Box::new(simple.clone()), - op, - right: Box::new(expr.clone()), - })); - f(Expr::Binary(ExprBinary { - // `$expr + x` - attrs: Vec::new(), - left: Box::new(expr.clone()), - op, - right: Box::new(simple.clone()), - })); - } - }); - }); - - // Expr::Block - f(Expr::Block(ExprBlock { - // `{}` - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Break - f(Expr::Break(ExprBreak { - // `break` - attrs: Vec::new(), - break_token: Token, - label: None, - expr: None, - })); - iter(depth, &mut |expr| { - f(Expr::Break(ExprBreak { - // `break $expr` - attrs: Vec::new(), - break_token: Token, - label: None, - expr: Some(Box::new(expr)), - })); - }); - - // Expr::Call - iter(depth, &mut |expr| { - f(Expr::Call(ExprCall { - // `$expr()` - attrs: Vec::new(), - func: Box::new(expr), - paren_token: token::Paren(span), - args: Punctuated::new(), - })); - }); - - // Expr::Cast - iter(depth, &mut |expr| { - f(Expr::Cast(ExprCast { - // `$expr as T` - attrs: Vec::new(), - expr: Box::new(expr), - as_token: Token, - ty: Box::new(Type::Path(TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - })), - })); - }); - - // Expr::Closure - iter(depth, &mut |expr| { - f(Expr::Closure(ExprClosure { - // `|| $expr` - attrs: Vec::new(), - lifetimes: None, - constness: None, - movability: None, - asyncness: None, - capture: None, - or1_token: Token, - inputs: Punctuated::new(), - or2_token: Token, - output: ReturnType::Default, - body: Box::new(expr), - })); - }); - - // Expr::Field - iter(depth, &mut |expr| { - f(Expr::Field(ExprField { - // `$expr.field` - attrs: Vec::new(), - base: Box::new(expr), - dot_token: Token, - member: Member::Named(Ident::new("field", span)), - })); - }); - - // Expr::If - iter(depth, &mut |expr| { - f(Expr::If(ExprIf { - // `if $expr {}` - attrs: Vec::new(), - if_token: Token, - cond: Box::new(expr), - then_branch: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - else_branch: None, - })); - }); - - // Expr::Let - iter(depth, &mut |expr| { - f(Expr::Let(ExprLet { - attrs: Vec::new(), - let_token: Token, - pat: Box::new(Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token, - })), - eq_token: Token, - expr: Box::new(expr), - })); - }); - - // Expr::Range - f(Expr::Range(ExprRange { - // `..` - attrs: Vec::new(), - start: None, - limits: RangeLimits::HalfOpen(Token), - end: None, - })); - iter(depth, &mut |expr| { - f(Expr::Range(ExprRange { - // `..$expr` - attrs: Vec::new(), - start: None, - limits: RangeLimits::HalfOpen(Token), - end: Some(Box::new(expr.clone())), - })); - f(Expr::Range(ExprRange { - // `$expr..` - attrs: Vec::new(), - start: Some(Box::new(expr)), - limits: RangeLimits::HalfOpen(Token), - end: None, - })); - }); - - // Expr::Reference - iter(depth, &mut |expr| { - f(Expr::Reference(ExprReference { - // `&$expr` - attrs: Vec::new(), - and_token: Token, - mutability: None, - expr: Box::new(expr), - })); - }); - - // Expr::Return - f(Expr::Return(ExprReturn { - // `return` - attrs: Vec::new(), - return_token: Token, - expr: None, - })); - iter(depth, &mut |expr| { - f(Expr::Return(ExprReturn { - // `return $expr` - attrs: Vec::new(), - return_token: Token, - expr: Some(Box::new(expr)), - })); - }); - - // Expr::Try - iter(depth, &mut |expr| { - f(Expr::Try(ExprTry { - // `$expr?` - attrs: Vec::new(), - expr: Box::new(expr), - question_token: Token, - })); - }); - - // Expr::Unary - iter(depth, &mut |expr| { - for op in [ - UnOp::Deref(Token), - //UnOp::Not(Token), - //UnOp::Neg(Token), - ] { - f(Expr::Unary(ExprUnary { - // `*$expr` - attrs: Vec::new(), - op, - expr: Box::new(expr.clone()), - })); - } - }); - - if false { - // Expr::Array - f(Expr::Array(ExprArray { - // `[]` - attrs: Vec::new(), - bracket_token: token::Bracket(span), - elems: Punctuated::new(), - })); - - // Expr::Async - f(Expr::Async(ExprAsync { - // `async {}` - attrs: Vec::new(), - async_token: Token, - capture: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Await - iter(depth, &mut |expr| { - f(Expr::Await(ExprAwait { - // `$expr.await` - attrs: Vec::new(), - base: Box::new(expr), - dot_token: Token, - await_token: Token, - })); - }); - - // Expr::Block - f(Expr::Block(ExprBlock { - // `'a: {}` - attrs: Vec::new(), - label: Some(Label { - name: Lifetime::new("'a", span), - colon_token: Token, - }), - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - iter(depth, &mut |expr| { - f(Expr::Block(ExprBlock { - // `{ $expr }` - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::from([Stmt::Expr(expr.clone(), None)]), - }, - })); - f(Expr::Block(ExprBlock { - // `{ $expr; }` - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::from([Stmt::Expr(expr, Some(Token))]), - }, - })); - }); - - // Expr::Break - f(Expr::Break(ExprBreak { - // `break 'a` - attrs: Vec::new(), - break_token: Token, - label: Some(Lifetime::new("'a", span)), - expr: None, - })); - iter(depth, &mut |expr| { - f(Expr::Break(ExprBreak { - // `break 'a $expr` - attrs: Vec::new(), - break_token: Token, - label: Some(Lifetime::new("'a", span)), - expr: Some(Box::new(expr)), - })); - }); - - // Expr::Closure - f(Expr::Closure(ExprClosure { - // `|| -> T {}` - attrs: Vec::new(), - lifetimes: None, - constness: None, - movability: None, - asyncness: None, - capture: None, - or1_token: Token, - inputs: Punctuated::new(), - or2_token: Token, - output: ReturnType::Type( - Token, - Box::new(Type::Path(TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - })), - ), - body: Box::new(Expr::Block(ExprBlock { - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })), - })); - - // Expr::Const - f(Expr::Const(ExprConst { - // `const {}` - attrs: Vec::new(), - const_token: Token, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Continue - f(Expr::Continue(ExprContinue { - // `continue` - attrs: Vec::new(), - continue_token: Token, - label: None, - })); - f(Expr::Continue(ExprContinue { - // `continue 'a` - attrs: Vec::new(), - continue_token: Token, - label: Some(Lifetime::new("'a", span)), - })); - - // Expr::ForLoop - iter(depth, &mut |expr| { - f(Expr::ForLoop(ExprForLoop { - // `for _ in $expr {}` - attrs: Vec::new(), - label: None, - for_token: Token, - pat: Box::new(Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token, - })), - in_token: Token, - expr: Box::new(expr.clone()), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - f(Expr::ForLoop(ExprForLoop { - // `'a: for _ in $expr {}` - attrs: Vec::new(), - label: Some(Label { - name: Lifetime::new("'a", span), - colon_token: Token, - }), - for_token: Token, - pat: Box::new(Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token, - })), - in_token: Token, - expr: Box::new(expr), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - }); - - // Expr::Index - iter(depth, &mut |expr| { - f(Expr::Index(ExprIndex { - // `$expr[0]` - attrs: Vec::new(), - expr: Box::new(expr), - bracket_token: token::Bracket(span), - index: Box::new(Expr::Lit(ExprLit { - attrs: Vec::new(), - lit: Lit::Int(LitInt::new("0", span)), - })), - })); - }); - - // Expr::Loop - f(Expr::Loop(ExprLoop { - // `loop {}` - attrs: Vec::new(), - label: None, - loop_token: Token, - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - f(Expr::Loop(ExprLoop { - // `'a: loop {}` - attrs: Vec::new(), - label: Some(Label { - name: Lifetime::new("'a", span), - colon_token: Token, - }), - loop_token: Token, - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Macro - f(Expr::Macro(ExprMacro { - // `m!()` - attrs: Vec::new(), - mac: Macro { - path: Path::from(Ident::new("m", span)), - bang_token: Token, - delimiter: MacroDelimiter::Paren(token::Paren(span)), - tokens: TokenStream::new(), - }, - })); - f(Expr::Macro(ExprMacro { - // `m! {}` - attrs: Vec::new(), - mac: Macro { - path: Path::from(Ident::new("m", span)), - bang_token: Token, - delimiter: MacroDelimiter::Brace(token::Brace(span)), - tokens: TokenStream::new(), - }, - })); - - // Expr::Match - iter(depth, &mut |expr| { - f(Expr::Match(ExprMatch { - // `match $expr {}` - attrs: Vec::new(), - match_token: Token, - expr: Box::new(expr.clone()), - brace_token: token::Brace(span), - arms: Vec::new(), - })); - f(Expr::Match(ExprMatch { - // `match x { _ => $expr }` - attrs: Vec::new(), - match_token: Token, - expr: Box::new(Expr::Path(ExprPath { - attrs: Vec::new(), - qself: None, - path: Path::from(Ident::new("x", span)), - })), - brace_token: token::Brace(span), - arms: Vec::from([Arm { - attrs: Vec::new(), - pat: Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token, - }), - guard: None, - fat_arrow_token: Token, - body: Box::new(expr.clone()), - comma: None, - }]), - })); - f(Expr::Match(ExprMatch { - // `match x { _ if $expr => {} }` - attrs: Vec::new(), - match_token: Token, - expr: Box::new(Expr::Path(ExprPath { - attrs: Vec::new(), - qself: None, - path: Path::from(Ident::new("x", span)), - })), - brace_token: token::Brace(span), - arms: Vec::from([Arm { - attrs: Vec::new(), - pat: Pat::Wild(PatWild { - attrs: Vec::new(), - underscore_token: Token, - }), - guard: Some((Token, Box::new(expr))), - fat_arrow_token: Token, - body: Box::new(Expr::Block(ExprBlock { - attrs: Vec::new(), - label: None, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })), - comma: None, - }]), - })); - }); - - // Expr::MethodCall - iter(depth, &mut |expr| { - f(Expr::MethodCall(ExprMethodCall { - // `$expr.method()` - attrs: Vec::new(), - receiver: Box::new(expr.clone()), - dot_token: Token, - method: Ident::new("method", span), - turbofish: None, - paren_token: token::Paren(span), - args: Punctuated::new(), - })); - f(Expr::MethodCall(ExprMethodCall { - // `$expr.method::<T>()` - attrs: Vec::new(), - receiver: Box::new(expr), - dot_token: Token, - method: Ident::new("method", span), - turbofish: Some(AngleBracketedGenericArguments { - colon2_token: Some(Token), - lt_token: Token, - args: Punctuated::from_iter([GenericArgument::Type(Type::Path( - TypePath { - qself: None, - path: Path::from(Ident::new("T", span)), - }, - ))]), - gt_token: Token, - }), - paren_token: token::Paren(span), - args: Punctuated::new(), - })); - }); - - // Expr::RawAddr - iter(depth, &mut |expr| { - f(Expr::RawAddr(ExprRawAddr { - // `&raw const $expr` - attrs: Vec::new(), - and_token: Token, - raw: Token, - mutability: PointerMutability::Const(Token), - expr: Box::new(expr), - })); - }); - - // Expr::Struct - f(Expr::Struct(ExprStruct { - // `Struct {}` - attrs: Vec::new(), - qself: None, - path: Path::from(Ident::new("Struct", span)), - brace_token: token::Brace(span), - fields: Punctuated::new(), - dot2_token: None, - rest: None, - })); - - // Expr::TryBlock - f(Expr::TryBlock(ExprTryBlock { - // `try {}` - attrs: Vec::new(), - try_token: Token, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::Unsafe - f(Expr::Unsafe(ExprUnsafe { - // `unsafe {}` - attrs: Vec::new(), - unsafe_token: Token, - block: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - - // Expr::While - iter(depth, &mut |expr| { - f(Expr::While(ExprWhile { - // `while $expr {}` - attrs: Vec::new(), - label: None, - while_token: Token, - cond: Box::new(expr.clone()), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - f(Expr::While(ExprWhile { - // `'a: while $expr {}` - attrs: Vec::new(), - label: Some(Label { - name: Lifetime::new("'a", span), - colon_token: Token, - }), - while_token: Token, - cond: Box::new(expr), - body: Block { - brace_token: token::Brace(span), - stmts: Vec::new(), - }, - })); - }); - - // Expr::Yield - f(Expr::Yield(ExprYield { - // `yield` - attrs: Vec::new(), - yield_token: Token, - expr: None, - })); - iter(depth, &mut |expr| { - f(Expr::Yield(ExprYield { - // `yield $expr` - attrs: Vec::new(), - yield_token: Token, - expr: Some(Box::new(expr)), - })); - }); - } - } - - let mut failures = 0; - macro_rules! fail { - ($($message:tt)*) => {{ - eprintln!($($message)*); - failures += 1; - return; - }}; - } - let mut assert = |mut original: Expr| { - let tokens = original.to_token_stream(); - let Ok(mut parsed) = syn::parse2::<Expr>(tokens.clone()) else { - fail!( - "failed to parse: {}\n{:#?}", - tokens, - crate::macros::debug::Lite(&original), - ); - }; - AsIfPrinted.visit_expr_mut(&mut original); - FlattenParens::combine_attrs().visit_expr_mut(&mut parsed); - if original != parsed { - fail!( - "before: {}\n{:#?}\nafter: {}\n{:#?}", - tokens, - crate::macros::debug::Lite(&original), - parsed.to_token_stream(), - crate::macros::debug::Lite(&parsed), - ); - } - let mut tokens_no_paren = tokens.clone(); - FlattenParens::visit_token_stream_mut(&mut tokens_no_paren); - if tokens.to_string() != tokens_no_paren.to_string() { - if let Ok(mut parsed2) = syn::parse2::<Expr>(tokens_no_paren) { - FlattenParens::combine_attrs().visit_expr_mut(&mut parsed2); - if original == parsed2 { - fail!("redundant parens: {}", tokens); - } - } - } - }; - - iter(4, &mut assert); - if failures > 0 { - eprintln!("FAILURES: {failures}"); - ExitCode::FAILURE - } else { - ExitCode::SUCCESS - } -} |
