1fad3a1d3Sopenharmony_ci#![allow( 2fad3a1d3Sopenharmony_ci clippy::manual_let_else, 3fad3a1d3Sopenharmony_ci clippy::too_many_lines, 4fad3a1d3Sopenharmony_ci clippy::uninlined_format_args 5fad3a1d3Sopenharmony_ci)] 6fad3a1d3Sopenharmony_ci 7fad3a1d3Sopenharmony_ci#[macro_use] 8fad3a1d3Sopenharmony_cimod macros; 9fad3a1d3Sopenharmony_ci 10fad3a1d3Sopenharmony_ciuse quote::quote; 11fad3a1d3Sopenharmony_ciuse syn::{DeriveInput, ItemFn, TypeParamBound, WhereClause, WherePredicate}; 12fad3a1d3Sopenharmony_ci 13fad3a1d3Sopenharmony_ci#[test] 14fad3a1d3Sopenharmony_cifn test_split_for_impl() { 15fad3a1d3Sopenharmony_ci let input = quote! { 16fad3a1d3Sopenharmony_ci struct S<'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug; 17fad3a1d3Sopenharmony_ci }; 18fad3a1d3Sopenharmony_ci 19fad3a1d3Sopenharmony_ci snapshot!(input as DeriveInput, @r###" 20fad3a1d3Sopenharmony_ci DeriveInput { 21fad3a1d3Sopenharmony_ci vis: Visibility::Inherited, 22fad3a1d3Sopenharmony_ci ident: "S", 23fad3a1d3Sopenharmony_ci generics: Generics { 24fad3a1d3Sopenharmony_ci lt_token: Some, 25fad3a1d3Sopenharmony_ci params: [ 26fad3a1d3Sopenharmony_ci GenericParam::Lifetime(LifetimeParam { 27fad3a1d3Sopenharmony_ci lifetime: Lifetime { 28fad3a1d3Sopenharmony_ci ident: "a", 29fad3a1d3Sopenharmony_ci }, 30fad3a1d3Sopenharmony_ci }), 31fad3a1d3Sopenharmony_ci Token![,], 32fad3a1d3Sopenharmony_ci GenericParam::Lifetime(LifetimeParam { 33fad3a1d3Sopenharmony_ci lifetime: Lifetime { 34fad3a1d3Sopenharmony_ci ident: "b", 35fad3a1d3Sopenharmony_ci }, 36fad3a1d3Sopenharmony_ci colon_token: Some, 37fad3a1d3Sopenharmony_ci bounds: [ 38fad3a1d3Sopenharmony_ci Lifetime { 39fad3a1d3Sopenharmony_ci ident: "a", 40fad3a1d3Sopenharmony_ci }, 41fad3a1d3Sopenharmony_ci ], 42fad3a1d3Sopenharmony_ci }), 43fad3a1d3Sopenharmony_ci Token![,], 44fad3a1d3Sopenharmony_ci GenericParam::Type(TypeParam { 45fad3a1d3Sopenharmony_ci attrs: [ 46fad3a1d3Sopenharmony_ci Attribute { 47fad3a1d3Sopenharmony_ci style: AttrStyle::Outer, 48fad3a1d3Sopenharmony_ci meta: Meta::Path { 49fad3a1d3Sopenharmony_ci segments: [ 50fad3a1d3Sopenharmony_ci PathSegment { 51fad3a1d3Sopenharmony_ci ident: "may_dangle", 52fad3a1d3Sopenharmony_ci }, 53fad3a1d3Sopenharmony_ci ], 54fad3a1d3Sopenharmony_ci }, 55fad3a1d3Sopenharmony_ci }, 56fad3a1d3Sopenharmony_ci ], 57fad3a1d3Sopenharmony_ci ident: "T", 58fad3a1d3Sopenharmony_ci colon_token: Some, 59fad3a1d3Sopenharmony_ci bounds: [ 60fad3a1d3Sopenharmony_ci TypeParamBound::Lifetime { 61fad3a1d3Sopenharmony_ci ident: "a", 62fad3a1d3Sopenharmony_ci }, 63fad3a1d3Sopenharmony_ci ], 64fad3a1d3Sopenharmony_ci eq_token: Some, 65fad3a1d3Sopenharmony_ci default: Some(Type::Tuple), 66fad3a1d3Sopenharmony_ci }), 67fad3a1d3Sopenharmony_ci ], 68fad3a1d3Sopenharmony_ci gt_token: Some, 69fad3a1d3Sopenharmony_ci where_clause: Some(WhereClause { 70fad3a1d3Sopenharmony_ci predicates: [ 71fad3a1d3Sopenharmony_ci WherePredicate::Type(PredicateType { 72fad3a1d3Sopenharmony_ci bounded_ty: Type::Path { 73fad3a1d3Sopenharmony_ci path: Path { 74fad3a1d3Sopenharmony_ci segments: [ 75fad3a1d3Sopenharmony_ci PathSegment { 76fad3a1d3Sopenharmony_ci ident: "T", 77fad3a1d3Sopenharmony_ci }, 78fad3a1d3Sopenharmony_ci ], 79fad3a1d3Sopenharmony_ci }, 80fad3a1d3Sopenharmony_ci }, 81fad3a1d3Sopenharmony_ci bounds: [ 82fad3a1d3Sopenharmony_ci TypeParamBound::Trait(TraitBound { 83fad3a1d3Sopenharmony_ci path: Path { 84fad3a1d3Sopenharmony_ci segments: [ 85fad3a1d3Sopenharmony_ci PathSegment { 86fad3a1d3Sopenharmony_ci ident: "Debug", 87fad3a1d3Sopenharmony_ci }, 88fad3a1d3Sopenharmony_ci ], 89fad3a1d3Sopenharmony_ci }, 90fad3a1d3Sopenharmony_ci }), 91fad3a1d3Sopenharmony_ci ], 92fad3a1d3Sopenharmony_ci }), 93fad3a1d3Sopenharmony_ci ], 94fad3a1d3Sopenharmony_ci }), 95fad3a1d3Sopenharmony_ci }, 96fad3a1d3Sopenharmony_ci data: Data::Struct { 97fad3a1d3Sopenharmony_ci fields: Fields::Unit, 98fad3a1d3Sopenharmony_ci semi_token: Some, 99fad3a1d3Sopenharmony_ci }, 100fad3a1d3Sopenharmony_ci } 101fad3a1d3Sopenharmony_ci "###); 102fad3a1d3Sopenharmony_ci 103fad3a1d3Sopenharmony_ci let generics = input.generics; 104fad3a1d3Sopenharmony_ci let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 105fad3a1d3Sopenharmony_ci 106fad3a1d3Sopenharmony_ci let generated = quote! { 107fad3a1d3Sopenharmony_ci impl #impl_generics MyTrait for Test #ty_generics #where_clause {} 108fad3a1d3Sopenharmony_ci }; 109fad3a1d3Sopenharmony_ci let expected = quote! { 110fad3a1d3Sopenharmony_ci impl<'a, 'b: 'a, #[may_dangle] T: 'a> MyTrait 111fad3a1d3Sopenharmony_ci for Test<'a, 'b, T> 112fad3a1d3Sopenharmony_ci where 113fad3a1d3Sopenharmony_ci T: Debug 114fad3a1d3Sopenharmony_ci {} 115fad3a1d3Sopenharmony_ci }; 116fad3a1d3Sopenharmony_ci assert_eq!(generated.to_string(), expected.to_string()); 117fad3a1d3Sopenharmony_ci 118fad3a1d3Sopenharmony_ci let turbofish = ty_generics.as_turbofish(); 119fad3a1d3Sopenharmony_ci let generated = quote! { 120fad3a1d3Sopenharmony_ci Test #turbofish 121fad3a1d3Sopenharmony_ci }; 122fad3a1d3Sopenharmony_ci let expected = quote! { 123fad3a1d3Sopenharmony_ci Test::<'a, 'b, T> 124fad3a1d3Sopenharmony_ci }; 125fad3a1d3Sopenharmony_ci assert_eq!(generated.to_string(), expected.to_string()); 126fad3a1d3Sopenharmony_ci} 127fad3a1d3Sopenharmony_ci 128fad3a1d3Sopenharmony_ci#[test] 129fad3a1d3Sopenharmony_cifn test_ty_param_bound() { 130fad3a1d3Sopenharmony_ci let tokens = quote!('a); 131fad3a1d3Sopenharmony_ci snapshot!(tokens as TypeParamBound, @r###" 132fad3a1d3Sopenharmony_ci TypeParamBound::Lifetime { 133fad3a1d3Sopenharmony_ci ident: "a", 134fad3a1d3Sopenharmony_ci } 135fad3a1d3Sopenharmony_ci "###); 136fad3a1d3Sopenharmony_ci 137fad3a1d3Sopenharmony_ci let tokens = quote!('_); 138fad3a1d3Sopenharmony_ci snapshot!(tokens as TypeParamBound, @r###" 139fad3a1d3Sopenharmony_ci TypeParamBound::Lifetime { 140fad3a1d3Sopenharmony_ci ident: "_", 141fad3a1d3Sopenharmony_ci } 142fad3a1d3Sopenharmony_ci "###); 143fad3a1d3Sopenharmony_ci 144fad3a1d3Sopenharmony_ci let tokens = quote!(Debug); 145fad3a1d3Sopenharmony_ci snapshot!(tokens as TypeParamBound, @r###" 146fad3a1d3Sopenharmony_ci TypeParamBound::Trait(TraitBound { 147fad3a1d3Sopenharmony_ci path: Path { 148fad3a1d3Sopenharmony_ci segments: [ 149fad3a1d3Sopenharmony_ci PathSegment { 150fad3a1d3Sopenharmony_ci ident: "Debug", 151fad3a1d3Sopenharmony_ci }, 152fad3a1d3Sopenharmony_ci ], 153fad3a1d3Sopenharmony_ci }, 154fad3a1d3Sopenharmony_ci }) 155fad3a1d3Sopenharmony_ci "###); 156fad3a1d3Sopenharmony_ci 157fad3a1d3Sopenharmony_ci let tokens = quote!(?Sized); 158fad3a1d3Sopenharmony_ci snapshot!(tokens as TypeParamBound, @r###" 159fad3a1d3Sopenharmony_ci TypeParamBound::Trait(TraitBound { 160fad3a1d3Sopenharmony_ci modifier: TraitBoundModifier::Maybe, 161fad3a1d3Sopenharmony_ci path: Path { 162fad3a1d3Sopenharmony_ci segments: [ 163fad3a1d3Sopenharmony_ci PathSegment { 164fad3a1d3Sopenharmony_ci ident: "Sized", 165fad3a1d3Sopenharmony_ci }, 166fad3a1d3Sopenharmony_ci ], 167fad3a1d3Sopenharmony_ci }, 168fad3a1d3Sopenharmony_ci }) 169fad3a1d3Sopenharmony_ci "###); 170fad3a1d3Sopenharmony_ci} 171fad3a1d3Sopenharmony_ci 172fad3a1d3Sopenharmony_ci#[test] 173fad3a1d3Sopenharmony_cifn test_fn_precedence_in_where_clause() { 174fad3a1d3Sopenharmony_ci // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not 175fad3a1d3Sopenharmony_ci // `FnOnce() -> (i32 + Send)`. 176fad3a1d3Sopenharmony_ci let input = quote! { 177fad3a1d3Sopenharmony_ci fn f<G>() 178fad3a1d3Sopenharmony_ci where 179fad3a1d3Sopenharmony_ci G: FnOnce() -> i32 + Send, 180fad3a1d3Sopenharmony_ci { 181fad3a1d3Sopenharmony_ci } 182fad3a1d3Sopenharmony_ci }; 183fad3a1d3Sopenharmony_ci 184fad3a1d3Sopenharmony_ci snapshot!(input as ItemFn, @r###" 185fad3a1d3Sopenharmony_ci ItemFn { 186fad3a1d3Sopenharmony_ci vis: Visibility::Inherited, 187fad3a1d3Sopenharmony_ci sig: Signature { 188fad3a1d3Sopenharmony_ci ident: "f", 189fad3a1d3Sopenharmony_ci generics: Generics { 190fad3a1d3Sopenharmony_ci lt_token: Some, 191fad3a1d3Sopenharmony_ci params: [ 192fad3a1d3Sopenharmony_ci GenericParam::Type(TypeParam { 193fad3a1d3Sopenharmony_ci ident: "G", 194fad3a1d3Sopenharmony_ci }), 195fad3a1d3Sopenharmony_ci ], 196fad3a1d3Sopenharmony_ci gt_token: Some, 197fad3a1d3Sopenharmony_ci where_clause: Some(WhereClause { 198fad3a1d3Sopenharmony_ci predicates: [ 199fad3a1d3Sopenharmony_ci WherePredicate::Type(PredicateType { 200fad3a1d3Sopenharmony_ci bounded_ty: Type::Path { 201fad3a1d3Sopenharmony_ci path: Path { 202fad3a1d3Sopenharmony_ci segments: [ 203fad3a1d3Sopenharmony_ci PathSegment { 204fad3a1d3Sopenharmony_ci ident: "G", 205fad3a1d3Sopenharmony_ci }, 206fad3a1d3Sopenharmony_ci ], 207fad3a1d3Sopenharmony_ci }, 208fad3a1d3Sopenharmony_ci }, 209fad3a1d3Sopenharmony_ci bounds: [ 210fad3a1d3Sopenharmony_ci TypeParamBound::Trait(TraitBound { 211fad3a1d3Sopenharmony_ci path: Path { 212fad3a1d3Sopenharmony_ci segments: [ 213fad3a1d3Sopenharmony_ci PathSegment { 214fad3a1d3Sopenharmony_ci ident: "FnOnce", 215fad3a1d3Sopenharmony_ci arguments: PathArguments::Parenthesized { 216fad3a1d3Sopenharmony_ci output: ReturnType::Type( 217fad3a1d3Sopenharmony_ci Type::Path { 218fad3a1d3Sopenharmony_ci path: Path { 219fad3a1d3Sopenharmony_ci segments: [ 220fad3a1d3Sopenharmony_ci PathSegment { 221fad3a1d3Sopenharmony_ci ident: "i32", 222fad3a1d3Sopenharmony_ci }, 223fad3a1d3Sopenharmony_ci ], 224fad3a1d3Sopenharmony_ci }, 225fad3a1d3Sopenharmony_ci }, 226fad3a1d3Sopenharmony_ci ), 227fad3a1d3Sopenharmony_ci }, 228fad3a1d3Sopenharmony_ci }, 229fad3a1d3Sopenharmony_ci ], 230fad3a1d3Sopenharmony_ci }, 231fad3a1d3Sopenharmony_ci }), 232fad3a1d3Sopenharmony_ci Token![+], 233fad3a1d3Sopenharmony_ci TypeParamBound::Trait(TraitBound { 234fad3a1d3Sopenharmony_ci path: Path { 235fad3a1d3Sopenharmony_ci segments: [ 236fad3a1d3Sopenharmony_ci PathSegment { 237fad3a1d3Sopenharmony_ci ident: "Send", 238fad3a1d3Sopenharmony_ci }, 239fad3a1d3Sopenharmony_ci ], 240fad3a1d3Sopenharmony_ci }, 241fad3a1d3Sopenharmony_ci }), 242fad3a1d3Sopenharmony_ci ], 243fad3a1d3Sopenharmony_ci }), 244fad3a1d3Sopenharmony_ci Token![,], 245fad3a1d3Sopenharmony_ci ], 246fad3a1d3Sopenharmony_ci }), 247fad3a1d3Sopenharmony_ci }, 248fad3a1d3Sopenharmony_ci output: ReturnType::Default, 249fad3a1d3Sopenharmony_ci }, 250fad3a1d3Sopenharmony_ci block: Block { 251fad3a1d3Sopenharmony_ci stmts: [], 252fad3a1d3Sopenharmony_ci }, 253fad3a1d3Sopenharmony_ci } 254fad3a1d3Sopenharmony_ci "###); 255fad3a1d3Sopenharmony_ci 256fad3a1d3Sopenharmony_ci let where_clause = input.sig.generics.where_clause.as_ref().unwrap(); 257fad3a1d3Sopenharmony_ci assert_eq!(where_clause.predicates.len(), 1); 258fad3a1d3Sopenharmony_ci 259fad3a1d3Sopenharmony_ci let predicate = match &where_clause.predicates[0] { 260fad3a1d3Sopenharmony_ci WherePredicate::Type(pred) => pred, 261fad3a1d3Sopenharmony_ci _ => panic!("wrong predicate kind"), 262fad3a1d3Sopenharmony_ci }; 263fad3a1d3Sopenharmony_ci 264fad3a1d3Sopenharmony_ci assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds); 265fad3a1d3Sopenharmony_ci 266fad3a1d3Sopenharmony_ci let first_bound = &predicate.bounds[0]; 267fad3a1d3Sopenharmony_ci assert_eq!(quote!(#first_bound).to_string(), "FnOnce () -> i32"); 268fad3a1d3Sopenharmony_ci 269fad3a1d3Sopenharmony_ci let second_bound = &predicate.bounds[1]; 270fad3a1d3Sopenharmony_ci assert_eq!(quote!(#second_bound).to_string(), "Send"); 271fad3a1d3Sopenharmony_ci} 272fad3a1d3Sopenharmony_ci 273fad3a1d3Sopenharmony_ci#[test] 274fad3a1d3Sopenharmony_cifn test_where_clause_at_end_of_input() { 275fad3a1d3Sopenharmony_ci let input = quote! { 276fad3a1d3Sopenharmony_ci where 277fad3a1d3Sopenharmony_ci }; 278fad3a1d3Sopenharmony_ci 279fad3a1d3Sopenharmony_ci snapshot!(input as WhereClause, @"WhereClause"); 280fad3a1d3Sopenharmony_ci 281fad3a1d3Sopenharmony_ci assert_eq!(input.predicates.len(), 0); 282fad3a1d3Sopenharmony_ci} 283