test_generics.rs 9.0 KB

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