test_ty.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. #[macro_use]
  2. mod macros;
  3. use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
  4. use quote::quote;
  5. use std::iter::FromIterator;
  6. use syn::Type;
  7. #[test]
  8. fn test_mut_self() {
  9. syn::parse_str::<Type>("fn(mut self)").unwrap();
  10. syn::parse_str::<Type>("fn(mut self,)").unwrap();
  11. syn::parse_str::<Type>("fn(mut self: ())").unwrap();
  12. syn::parse_str::<Type>("fn(mut self: ...)").unwrap_err();
  13. syn::parse_str::<Type>("fn(mut self: mut self)").unwrap_err();
  14. syn::parse_str::<Type>("fn(mut self::T)").unwrap_err();
  15. }
  16. #[test]
  17. fn test_macro_variable_type() {
  18. // mimics the token stream corresponding to `$ty<T>`
  19. let tokens = TokenStream::from_iter(vec![
  20. TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
  21. TokenTree::Punct(Punct::new('<', Spacing::Alone)),
  22. TokenTree::Ident(Ident::new("T", Span::call_site())),
  23. TokenTree::Punct(Punct::new('>', Spacing::Alone)),
  24. ]);
  25. snapshot!(tokens as Type, @r###"
  26. Type::Path {
  27. path: Path {
  28. segments: [
  29. PathSegment {
  30. ident: "ty",
  31. arguments: PathArguments::AngleBracketed {
  32. args: [
  33. Type(Type::Path {
  34. path: Path {
  35. segments: [
  36. PathSegment {
  37. ident: "T",
  38. arguments: None,
  39. },
  40. ],
  41. },
  42. }),
  43. ],
  44. },
  45. },
  46. ],
  47. },
  48. }
  49. "###);
  50. // mimics the token stream corresponding to `$ty::<T>`
  51. let tokens = TokenStream::from_iter(vec![
  52. TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
  53. TokenTree::Punct(Punct::new(':', Spacing::Joint)),
  54. TokenTree::Punct(Punct::new(':', Spacing::Alone)),
  55. TokenTree::Punct(Punct::new('<', Spacing::Alone)),
  56. TokenTree::Ident(Ident::new("T", Span::call_site())),
  57. TokenTree::Punct(Punct::new('>', Spacing::Alone)),
  58. ]);
  59. snapshot!(tokens as Type, @r###"
  60. Type::Path {
  61. path: Path {
  62. segments: [
  63. PathSegment {
  64. ident: "ty",
  65. arguments: PathArguments::AngleBracketed {
  66. colon2_token: Some,
  67. args: [
  68. Type(Type::Path {
  69. path: Path {
  70. segments: [
  71. PathSegment {
  72. ident: "T",
  73. arguments: None,
  74. },
  75. ],
  76. },
  77. }),
  78. ],
  79. },
  80. },
  81. ],
  82. },
  83. }
  84. "###);
  85. }
  86. #[test]
  87. fn test_group_angle_brackets() {
  88. // mimics the token stream corresponding to `Option<$ty>`
  89. let tokens = TokenStream::from_iter(vec![
  90. TokenTree::Ident(Ident::new("Option", Span::call_site())),
  91. TokenTree::Punct(Punct::new('<', Spacing::Alone)),
  92. TokenTree::Group(Group::new(Delimiter::None, quote! { Vec<u8> })),
  93. TokenTree::Punct(Punct::new('>', Spacing::Alone)),
  94. ]);
  95. snapshot!(tokens as Type, @r###"
  96. Type::Path {
  97. path: Path {
  98. segments: [
  99. PathSegment {
  100. ident: "Option",
  101. arguments: PathArguments::AngleBracketed {
  102. args: [
  103. Type(Type::Group {
  104. elem: Type::Path {
  105. path: Path {
  106. segments: [
  107. PathSegment {
  108. ident: "Vec",
  109. arguments: PathArguments::AngleBracketed {
  110. args: [
  111. Type(Type::Path {
  112. path: Path {
  113. segments: [
  114. PathSegment {
  115. ident: "u8",
  116. arguments: None,
  117. },
  118. ],
  119. },
  120. }),
  121. ],
  122. },
  123. },
  124. ],
  125. },
  126. },
  127. }),
  128. ],
  129. },
  130. },
  131. ],
  132. },
  133. }
  134. "###);
  135. }
  136. #[test]
  137. fn test_group_colons() {
  138. // mimics the token stream corresponding to `$ty::Item`
  139. let tokens = TokenStream::from_iter(vec![
  140. TokenTree::Group(Group::new(Delimiter::None, quote! { Vec<u8> })),
  141. TokenTree::Punct(Punct::new(':', Spacing::Joint)),
  142. TokenTree::Punct(Punct::new(':', Spacing::Alone)),
  143. TokenTree::Ident(Ident::new("Item", Span::call_site())),
  144. ]);
  145. snapshot!(tokens as Type, @r###"
  146. Type::Path {
  147. path: Path {
  148. segments: [
  149. PathSegment {
  150. ident: "Vec",
  151. arguments: PathArguments::AngleBracketed {
  152. args: [
  153. Type(Type::Path {
  154. path: Path {
  155. segments: [
  156. PathSegment {
  157. ident: "u8",
  158. arguments: None,
  159. },
  160. ],
  161. },
  162. }),
  163. ],
  164. },
  165. },
  166. PathSegment {
  167. ident: "Item",
  168. arguments: None,
  169. },
  170. ],
  171. },
  172. }
  173. "###);
  174. let tokens = TokenStream::from_iter(vec![
  175. TokenTree::Group(Group::new(Delimiter::None, quote! { [T] })),
  176. TokenTree::Punct(Punct::new(':', Spacing::Joint)),
  177. TokenTree::Punct(Punct::new(':', Spacing::Alone)),
  178. TokenTree::Ident(Ident::new("Element", Span::call_site())),
  179. ]);
  180. snapshot!(tokens as Type, @r###"
  181. Type::Path {
  182. qself: Some(QSelf {
  183. ty: Type::Slice {
  184. elem: Type::Path {
  185. path: Path {
  186. segments: [
  187. PathSegment {
  188. ident: "T",
  189. arguments: None,
  190. },
  191. ],
  192. },
  193. },
  194. },
  195. position: 0,
  196. }),
  197. path: Path {
  198. leading_colon: Some,
  199. segments: [
  200. PathSegment {
  201. ident: "Element",
  202. arguments: None,
  203. },
  204. ],
  205. },
  206. }
  207. "###);
  208. }
  209. #[test]
  210. fn test_trait_object() {
  211. let tokens = quote!(dyn for<'a> Trait<'a> + 'static);
  212. snapshot!(tokens as Type, @r###"
  213. Type::TraitObject {
  214. dyn_token: Some,
  215. bounds: [
  216. Trait(TraitBound {
  217. modifier: None,
  218. lifetimes: Some(BoundLifetimes {
  219. lifetimes: [
  220. LifetimeDef {
  221. lifetime: Lifetime {
  222. ident: "a",
  223. },
  224. },
  225. ],
  226. }),
  227. path: Path {
  228. segments: [
  229. PathSegment {
  230. ident: "Trait",
  231. arguments: PathArguments::AngleBracketed {
  232. args: [
  233. Lifetime(Lifetime {
  234. ident: "a",
  235. }),
  236. ],
  237. },
  238. },
  239. ],
  240. },
  241. }),
  242. Lifetime(Lifetime {
  243. ident: "static",
  244. }),
  245. ],
  246. }
  247. "###);
  248. let tokens = quote!(dyn 'a + Trait);
  249. snapshot!(tokens as Type, @r###"
  250. Type::TraitObject {
  251. dyn_token: Some,
  252. bounds: [
  253. Lifetime(Lifetime {
  254. ident: "a",
  255. }),
  256. Trait(TraitBound {
  257. modifier: None,
  258. path: Path {
  259. segments: [
  260. PathSegment {
  261. ident: "Trait",
  262. arguments: None,
  263. },
  264. ],
  265. },
  266. }),
  267. ],
  268. }
  269. "###);
  270. // None of the following are valid Rust types.
  271. syn::parse_str::<Type>("for<'a> dyn Trait<'a>").unwrap_err();
  272. syn::parse_str::<Type>("dyn for<'a> 'a + Trait").unwrap_err();
  273. }
  274. #[test]
  275. fn test_trailing_plus() {
  276. #[rustfmt::skip]
  277. let tokens = quote!(impl Trait +);
  278. snapshot!(tokens as Type, @r###"
  279. Type::ImplTrait {
  280. bounds: [
  281. Trait(TraitBound {
  282. modifier: None,
  283. path: Path {
  284. segments: [
  285. PathSegment {
  286. ident: "Trait",
  287. arguments: None,
  288. },
  289. ],
  290. },
  291. }),
  292. ],
  293. }
  294. "###);
  295. #[rustfmt::skip]
  296. let tokens = quote!(dyn Trait +);
  297. snapshot!(tokens as Type, @r###"
  298. Type::TraitObject {
  299. dyn_token: Some,
  300. bounds: [
  301. Trait(TraitBound {
  302. modifier: None,
  303. path: Path {
  304. segments: [
  305. PathSegment {
  306. ident: "Trait",
  307. arguments: None,
  308. },
  309. ],
  310. },
  311. }),
  312. ],
  313. }
  314. "###);
  315. #[rustfmt::skip]
  316. let tokens = quote!(Trait +);
  317. snapshot!(tokens as Type, @r###"
  318. Type::TraitObject {
  319. bounds: [
  320. Trait(TraitBound {
  321. modifier: None,
  322. path: Path {
  323. segments: [
  324. PathSegment {
  325. ident: "Trait",
  326. arguments: None,
  327. },
  328. ],
  329. },
  330. }),
  331. ],
  332. }
  333. "###);
  334. }