blob: d3b33ed784a817f9994640d6820ad669cc898cd9 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
Alex Crichton2e0229c2017-05-23 09:34:50 -07009#![cfg(feature = "extra-traits")]
David Tolnayecd024d2018-07-21 09:07:56 -070010#![recursion_limit = "1024"]
Nika Layzella2a1a4a2017-11-19 11:33:17 -050011#![feature(rustc_private)]
12
David Tolnayb153dbc2016-10-04 23:39:10 -070013extern crate syn;
14use syn::*;
15
David Tolnaye7678922016-10-13 20:44:03 -070016#[macro_use]
17extern crate quote;
David Tolnayb153dbc2016-10-04 23:39:10 -070018
Alex Crichton605643b2017-07-05 18:35:14 -070019extern crate proc_macro2;
David Tolnay65fb5662018-05-20 20:02:28 -070020use proc_macro2::{Ident, Span, TokenStream};
Alex Crichton605643b2017-07-05 18:35:14 -070021
David Tolnaydd125562017-12-31 02:16:22 -050022#[macro_use]
23mod macros;
24
David Tolnayc7a5d3d2017-06-04 12:11:05 -070025mod common;
26
Alex Crichtoneed4bc72018-05-17 10:59:15 -070027fn ident(s: &str) -> Ident {
28 Ident::new(s, Span::call_site())
29}
30
David Tolnayb153dbc2016-10-04 23:39:10 -070031#[test]
32fn test_split_for_impl() {
David Tolnaye7678922016-10-13 20:44:03 -070033 // <'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug
David Tolnayc2f1aba2017-11-12 20:29:22 -080034 let generics = Generics {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070035 gt_token: Some(Default::default()),
36 lt_token: Some(Default::default()),
David Tolnayf2cfd722017-12-31 18:02:51 -050037 params: punctuated![
David Tolnayc2f1aba2017-11-12 20:29:22 -080038 GenericParam::Lifetime(LifetimeDef {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070039 attrs: Default::default(),
David Tolnaye2099f32018-03-31 18:42:43 +020040 lifetime: Lifetime::new("'a", Span::call_site()),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070041 bounds: Default::default(),
42 colon_token: None,
David Tolnayc2f1aba2017-11-12 20:29:22 -080043 }),
44 GenericParam::Lifetime(LifetimeDef {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070045 attrs: Default::default(),
David Tolnaye2099f32018-03-31 18:42:43 +020046 lifetime: Lifetime::new("'b", Span::call_site()),
47 bounds: punctuated![Lifetime::new("'a", Span::call_site())],
David Tolnay42eaae12017-12-26 23:05:18 -050048 colon_token: Some(token::Colon::default()),
David Tolnayc2f1aba2017-11-12 20:29:22 -080049 }),
50 GenericParam::Type(TypeParam {
David Tolnay94d2b792018-04-29 12:26:10 -070051 attrs: vec![Attribute {
52 bracket_token: Default::default(),
53 pound_token: Default::default(),
54 style: AttrStyle::Outer,
Alex Crichtoneed4bc72018-05-17 10:59:15 -070055 path: ident("may_dangle").into(),
hcplaa511792018-05-29 07:13:01 +030056 tts: TokenStream::new(),
David Tolnay94d2b792018-04-29 12:26:10 -070057 }],
Alex Crichtoneed4bc72018-05-17 10:59:15 -070058 ident: ident("T"),
David Tolnay94d2b792018-04-29 12:26:10 -070059 bounds: punctuated![TypeParamBound::Lifetime(Lifetime::new(
60 "'a",
61 Span::call_site()
62 )),],
David Tolnay51382052017-12-27 13:46:21 -050063 default: Some(
64 TypeTuple {
David Tolnayeadbda32017-12-29 02:33:47 -050065 elems: Default::default(),
David Tolnay51382052017-12-27 13:46:21 -050066 paren_token: Default::default(),
67 }.into(),
68 ),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070069 colon_token: Some(Default::default()),
70 eq_token: Default::default(),
David Tolnayc2f1aba2017-11-12 20:29:22 -080071 }),
David Tolnaydd125562017-12-31 02:16:22 -050072 ],
David Tolnayac997dd2017-12-27 23:18:22 -050073 where_clause: Some(WhereClause {
74 where_token: Default::default(),
David Tolnay94d2b792018-04-29 12:26:10 -070075 predicates: punctuated![WherePredicate::Type(PredicateType {
76 lifetimes: None,
77 colon_token: Default::default(),
78 bounded_ty: TypePath {
79 qself: None,
Alex Crichtoneed4bc72018-05-17 10:59:15 -070080 path: ident("T").into(),
David Tolnay94d2b792018-04-29 12:26:10 -070081 }.into(),
82 bounds: punctuated![TypeParamBound::Trait(TraitBound {
83 paren_token: None,
84 modifier: TraitBoundModifier::None,
David Tolnay40fb8ce2018-01-02 10:53:46 -080085 lifetimes: None,
Alex Crichtoneed4bc72018-05-17 10:59:15 -070086 path: ident("Debug").into(),
David Tolnay94d2b792018-04-29 12:26:10 -070087 }),],
88 }),],
David Tolnayac997dd2017-12-27 23:18:22 -050089 }),
David Tolnayb153dbc2016-10-04 23:39:10 -070090 };
91
92 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
David Tolnaye7678922016-10-13 20:44:03 -070093 let tokens = quote! {
94 impl #impl_generics MyTrait for Test #ty_generics #where_clause {}
David Tolnayb153dbc2016-10-04 23:39:10 -070095 };
David Tolnay51382052017-12-27 13:46:21 -050096 let expected = concat!(
97 "impl < 'a , 'b : 'a , # [ may_dangle ] T : 'a > ",
98 "MyTrait for Test < 'a , 'b , T > ",
99 "where T : Debug { }"
100 );
David Tolnayc879a502017-01-25 15:51:32 -0800101 assert_eq!(expected, tokens.to_string());
David Tolnayb153dbc2016-10-04 23:39:10 -0700102
David Tolnayc879a502017-01-25 15:51:32 -0800103 let turbofish = ty_generics.as_turbofish();
104 let tokens = quote! {
105 Test #turbofish
106 };
107 let expected = "Test :: < 'a , 'b , T >";
David Tolnaye7678922016-10-13 20:44:03 -0700108 assert_eq!(expected, tokens.to_string());
David Tolnayb153dbc2016-10-04 23:39:10 -0700109}
David Tolnay23d83f92017-01-25 15:41:47 -0800110
111#[test]
112fn test_ty_param_bound() {
113 let tokens = quote!('a);
David Tolnaye2099f32018-03-31 18:42:43 +0200114 let expected = TypeParamBound::Lifetime(Lifetime::new("'a", Span::call_site()));
David Tolnay73b7ca12018-08-30 21:05:13 -0700115 assert_eq!(expected, syn::parse2::<TypeParamBound>(tokens).unwrap());
David Tolnay23d83f92017-01-25 15:41:47 -0800116
Bastien Orivel340553a2018-02-15 23:57:38 +0100117 let tokens = quote!('_);
Alex Crichtoneed4bc72018-05-17 10:59:15 -0700118 println!("{:?}", tokens);
David Tolnaye2099f32018-03-31 18:42:43 +0200119 let expected = TypeParamBound::Lifetime(Lifetime::new("'_", Span::call_site()));
David Tolnay73b7ca12018-08-30 21:05:13 -0700120 assert_eq!(expected, syn::parse2::<TypeParamBound>(tokens).unwrap());
Bastien Orivel340553a2018-02-15 23:57:38 +0100121
David Tolnay23d83f92017-01-25 15:41:47 -0800122 let tokens = quote!(Debug);
David Tolnay40fb8ce2018-01-02 10:53:46 -0800123 let expected = TypeParamBound::Trait(TraitBound {
David Tolnayc1f5d5d2018-03-31 22:17:56 +0200124 paren_token: None,
David Tolnay40fb8ce2018-01-02 10:53:46 -0800125 modifier: TraitBoundModifier::None,
126 lifetimes: None,
Alex Crichtoneed4bc72018-05-17 10:59:15 -0700127 path: ident("Debug").into(),
David Tolnay40fb8ce2018-01-02 10:53:46 -0800128 });
David Tolnay73b7ca12018-08-30 21:05:13 -0700129 assert_eq!(expected, syn::parse2::<TypeParamBound>(tokens).unwrap());
David Tolnay23d83f92017-01-25 15:41:47 -0800130
131 let tokens = quote!(?Sized);
David Tolnay40fb8ce2018-01-02 10:53:46 -0800132 let expected = TypeParamBound::Trait(TraitBound {
David Tolnayc1f5d5d2018-03-31 22:17:56 +0200133 paren_token: None,
David Tolnay40fb8ce2018-01-02 10:53:46 -0800134 modifier: TraitBoundModifier::Maybe(Default::default()),
135 lifetimes: None,
Alex Crichtoneed4bc72018-05-17 10:59:15 -0700136 path: ident("Sized").into(),
David Tolnay40fb8ce2018-01-02 10:53:46 -0800137 });
David Tolnay73b7ca12018-08-30 21:05:13 -0700138 assert_eq!(expected, syn::parse2::<TypeParamBound>(tokens).unwrap());
David Tolnay23d83f92017-01-25 15:41:47 -0800139}
Geoffry Songac02b182018-05-19 22:11:31 -0700140
141#[test]
142fn test_fn_precedence_in_where_clause() {
143 // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not `FnOnce() -> (i32 + Send)`.
David Tolnay65fb5662018-05-20 20:02:28 -0700144 let sig = quote! {
145 fn f<G>()
146 where
147 G: FnOnce() -> i32 + Send,
148 {
149 }
150 };
David Tolnay59ffad92018-08-30 21:01:04 -0700151 let fun = syn::parse2::<ItemFn>(sig).unwrap();
Geoffry Songac02b182018-05-19 22:11:31 -0700152 let where_clause = fun.decl.generics.where_clause.as_ref().unwrap();
153 assert_eq!(where_clause.predicates.len(), 1);
154 let predicate = match where_clause.predicates[0] {
155 WherePredicate::Type(ref pred) => pred,
156 _ => panic!("wrong predicate kind"),
157 };
158 assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds);
159 let first_bound = &predicate.bounds[0];
160 assert_eq!(quote!(#first_bound).to_string(), "FnOnce ( ) -> i32");
161 let second_bound = &predicate.bounds[1];
162 assert_eq!(quote!(#second_bound).to_string(), "Send");
163}