blob: 74771d586a940c5de7fe60c1e61fd55e553a287b [file] [log] [blame]
David Tolnayf83b6c92019-03-09 22:58:26 -08001#![cfg(not(syn_disable_nightly_tests))]
David Tolnayecd024d2018-07-21 09:07:56 -07002#![recursion_limit = "1024"]
Nika Layzella2a1a4a2017-11-19 11:33:17 -05003#![feature(rustc_private)]
4
David Tolnayb153dbc2016-10-04 23:39:10 -07005extern crate syn;
6use syn::*;
7
David Tolnaye7678922016-10-13 20:44:03 -07008#[macro_use]
9extern crate quote;
David Tolnayb153dbc2016-10-04 23:39:10 -070010
Alex Crichton605643b2017-07-05 18:35:14 -070011extern crate proc_macro2;
David Tolnay65fb5662018-05-20 20:02:28 -070012use proc_macro2::{Ident, Span, TokenStream};
Alex Crichton605643b2017-07-05 18:35:14 -070013
David Tolnaydd125562017-12-31 02:16:22 -050014#[macro_use]
15mod macros;
16
David Tolnayc7a5d3d2017-06-04 12:11:05 -070017mod common;
David Tolnayc3f98562018-11-02 08:55:05 -070018mod features;
David Tolnayc7a5d3d2017-06-04 12:11:05 -070019
Alex Crichtoneed4bc72018-05-17 10:59:15 -070020fn ident(s: &str) -> Ident {
21 Ident::new(s, Span::call_site())
22}
23
David Tolnayb153dbc2016-10-04 23:39:10 -070024#[test]
25fn test_split_for_impl() {
David Tolnaye7678922016-10-13 20:44:03 -070026 // <'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug
David Tolnayc2f1aba2017-11-12 20:29:22 -080027 let generics = Generics {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070028 gt_token: Some(Default::default()),
29 lt_token: Some(Default::default()),
David Tolnayf2cfd722017-12-31 18:02:51 -050030 params: punctuated![
David Tolnayc2f1aba2017-11-12 20:29:22 -080031 GenericParam::Lifetime(LifetimeDef {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070032 attrs: Default::default(),
David Tolnaye2099f32018-03-31 18:42:43 +020033 lifetime: Lifetime::new("'a", Span::call_site()),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070034 bounds: Default::default(),
35 colon_token: None,
David Tolnayc2f1aba2017-11-12 20:29:22 -080036 }),
37 GenericParam::Lifetime(LifetimeDef {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070038 attrs: Default::default(),
David Tolnaye2099f32018-03-31 18:42:43 +020039 lifetime: Lifetime::new("'b", Span::call_site()),
40 bounds: punctuated![Lifetime::new("'a", Span::call_site())],
David Tolnay42eaae12017-12-26 23:05:18 -050041 colon_token: Some(token::Colon::default()),
David Tolnayc2f1aba2017-11-12 20:29:22 -080042 }),
43 GenericParam::Type(TypeParam {
David Tolnay94d2b792018-04-29 12:26:10 -070044 attrs: vec![Attribute {
45 bracket_token: Default::default(),
46 pound_token: Default::default(),
47 style: AttrStyle::Outer,
Alex Crichtoneed4bc72018-05-17 10:59:15 -070048 path: ident("may_dangle").into(),
hcplaa511792018-05-29 07:13:01 +030049 tts: TokenStream::new(),
David Tolnay94d2b792018-04-29 12:26:10 -070050 }],
Alex Crichtoneed4bc72018-05-17 10:59:15 -070051 ident: ident("T"),
David Tolnay94d2b792018-04-29 12:26:10 -070052 bounds: punctuated![TypeParamBound::Lifetime(Lifetime::new(
53 "'a",
54 Span::call_site()
55 )),],
David Tolnay51382052017-12-27 13:46:21 -050056 default: Some(
57 TypeTuple {
David Tolnayeadbda32017-12-29 02:33:47 -050058 elems: Default::default(),
David Tolnay51382052017-12-27 13:46:21 -050059 paren_token: Default::default(),
David Tolnayfb84fc02018-10-02 21:01:30 -070060 }
61 .into(),
David Tolnay51382052017-12-27 13:46:21 -050062 ),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070063 colon_token: Some(Default::default()),
64 eq_token: Default::default(),
David Tolnayc2f1aba2017-11-12 20:29:22 -080065 }),
David Tolnaydd125562017-12-31 02:16:22 -050066 ],
David Tolnayac997dd2017-12-27 23:18:22 -050067 where_clause: Some(WhereClause {
68 where_token: Default::default(),
David Tolnay94d2b792018-04-29 12:26:10 -070069 predicates: punctuated![WherePredicate::Type(PredicateType {
70 lifetimes: None,
71 colon_token: Default::default(),
72 bounded_ty: TypePath {
73 qself: None,
Alex Crichtoneed4bc72018-05-17 10:59:15 -070074 path: ident("T").into(),
David Tolnayfb84fc02018-10-02 21:01:30 -070075 }
76 .into(),
David Tolnay94d2b792018-04-29 12:26:10 -070077 bounds: punctuated![TypeParamBound::Trait(TraitBound {
78 paren_token: None,
79 modifier: TraitBoundModifier::None,
David Tolnay40fb8ce2018-01-02 10:53:46 -080080 lifetimes: None,
Alex Crichtoneed4bc72018-05-17 10:59:15 -070081 path: ident("Debug").into(),
David Tolnay94d2b792018-04-29 12:26:10 -070082 }),],
83 }),],
David Tolnayac997dd2017-12-27 23:18:22 -050084 }),
David Tolnayb153dbc2016-10-04 23:39:10 -070085 };
86
87 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
David Tolnaye7678922016-10-13 20:44:03 -070088 let tokens = quote! {
89 impl #impl_generics MyTrait for Test #ty_generics #where_clause {}
David Tolnayb153dbc2016-10-04 23:39:10 -070090 };
David Tolnay51382052017-12-27 13:46:21 -050091 let expected = concat!(
92 "impl < 'a , 'b : 'a , # [ may_dangle ] T : 'a > ",
93 "MyTrait for Test < 'a , 'b , T > ",
94 "where T : Debug { }"
95 );
David Tolnayc879a502017-01-25 15:51:32 -080096 assert_eq!(expected, tokens.to_string());
David Tolnayb153dbc2016-10-04 23:39:10 -070097
David Tolnayc879a502017-01-25 15:51:32 -080098 let turbofish = ty_generics.as_turbofish();
99 let tokens = quote! {
100 Test #turbofish
101 };
102 let expected = "Test :: < 'a , 'b , T >";
David Tolnaye7678922016-10-13 20:44:03 -0700103 assert_eq!(expected, tokens.to_string());
David Tolnayb153dbc2016-10-04 23:39:10 -0700104}
David Tolnay23d83f92017-01-25 15:41:47 -0800105
106#[test]
107fn test_ty_param_bound() {
108 let tokens = quote!('a);
David Tolnaye2099f32018-03-31 18:42:43 +0200109 let expected = TypeParamBound::Lifetime(Lifetime::new("'a", Span::call_site()));
David Tolnay73b7ca12018-08-30 21:05:13 -0700110 assert_eq!(expected, syn::parse2::<TypeParamBound>(tokens).unwrap());
David Tolnay23d83f92017-01-25 15:41:47 -0800111
Bastien Orivel340553a2018-02-15 23:57:38 +0100112 let tokens = quote!('_);
Alex Crichtoneed4bc72018-05-17 10:59:15 -0700113 println!("{:?}", tokens);
David Tolnaye2099f32018-03-31 18:42:43 +0200114 let expected = TypeParamBound::Lifetime(Lifetime::new("'_", Span::call_site()));
David Tolnay73b7ca12018-08-30 21:05:13 -0700115 assert_eq!(expected, syn::parse2::<TypeParamBound>(tokens).unwrap());
Bastien Orivel340553a2018-02-15 23:57:38 +0100116
David Tolnay23d83f92017-01-25 15:41:47 -0800117 let tokens = quote!(Debug);
David Tolnay40fb8ce2018-01-02 10:53:46 -0800118 let expected = TypeParamBound::Trait(TraitBound {
David Tolnayc1f5d5d2018-03-31 22:17:56 +0200119 paren_token: None,
David Tolnay40fb8ce2018-01-02 10:53:46 -0800120 modifier: TraitBoundModifier::None,
121 lifetimes: None,
Alex Crichtoneed4bc72018-05-17 10:59:15 -0700122 path: ident("Debug").into(),
David Tolnay40fb8ce2018-01-02 10:53:46 -0800123 });
David Tolnay73b7ca12018-08-30 21:05:13 -0700124 assert_eq!(expected, syn::parse2::<TypeParamBound>(tokens).unwrap());
David Tolnay23d83f92017-01-25 15:41:47 -0800125
126 let tokens = quote!(?Sized);
David Tolnay40fb8ce2018-01-02 10:53:46 -0800127 let expected = TypeParamBound::Trait(TraitBound {
David Tolnayc1f5d5d2018-03-31 22:17:56 +0200128 paren_token: None,
David Tolnay40fb8ce2018-01-02 10:53:46 -0800129 modifier: TraitBoundModifier::Maybe(Default::default()),
130 lifetimes: None,
Alex Crichtoneed4bc72018-05-17 10:59:15 -0700131 path: ident("Sized").into(),
David Tolnay40fb8ce2018-01-02 10:53:46 -0800132 });
David Tolnay73b7ca12018-08-30 21:05:13 -0700133 assert_eq!(expected, syn::parse2::<TypeParamBound>(tokens).unwrap());
David Tolnay23d83f92017-01-25 15:41:47 -0800134}
Geoffry Songac02b182018-05-19 22:11:31 -0700135
136#[test]
137fn test_fn_precedence_in_where_clause() {
David Tolnayc8b0e0f2019-03-07 22:46:32 -0800138 // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not
139 // `FnOnce() -> (i32 + Send)`.
David Tolnay65fb5662018-05-20 20:02:28 -0700140 let sig = quote! {
141 fn f<G>()
142 where
143 G: FnOnce() -> i32 + Send,
144 {
145 }
146 };
David Tolnay59ffad92018-08-30 21:01:04 -0700147 let fun = syn::parse2::<ItemFn>(sig).unwrap();
Geoffry Songac02b182018-05-19 22:11:31 -0700148 let where_clause = fun.decl.generics.where_clause.as_ref().unwrap();
149 assert_eq!(where_clause.predicates.len(), 1);
150 let predicate = match where_clause.predicates[0] {
151 WherePredicate::Type(ref pred) => pred,
152 _ => panic!("wrong predicate kind"),
153 };
154 assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds);
155 let first_bound = &predicate.bounds[0];
156 assert_eq!(quote!(#first_bound).to_string(), "FnOnce ( ) -> i32");
157 let second_bound = &predicate.bounds[1];
158 assert_eq!(quote!(#second_bound).to_string(), "Send");
159}
David Tolnay38012de2018-09-02 13:32:47 -0700160
161#[test]
162fn test_where_clause_at_end_of_input() {
163 let tokens = quote! {
164 where
165 };
166 let where_clause = syn::parse2::<WhereClause>(tokens).unwrap();
167 assert_eq!(where_clause.predicates.len(), 0);
168}