blob: 4efa1b787e0057feaa5df6d56a0bf398f870c16c [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")]
Nika Layzella2a1a4a2017-11-19 11:33:17 -050010#![feature(rustc_private)]
11
David Tolnayb153dbc2016-10-04 23:39:10 -070012extern crate syn;
13use syn::*;
14
David Tolnaye7678922016-10-13 20:44:03 -070015#[macro_use]
16extern crate quote;
David Tolnayb153dbc2016-10-04 23:39:10 -070017
Alex Crichton605643b2017-07-05 18:35:14 -070018extern crate proc_macro2;
David Tolnaye2099f32018-03-31 18:42:43 +020019use proc_macro2::{Span, TokenStream};
Alex Crichton605643b2017-07-05 18:35:14 -070020
David Tolnaydd125562017-12-31 02:16:22 -050021#[macro_use]
22mod macros;
23
David Tolnayc7a5d3d2017-06-04 12:11:05 -070024mod common;
25
David Tolnayb153dbc2016-10-04 23:39:10 -070026#[test]
27fn test_split_for_impl() {
David Tolnaye7678922016-10-13 20:44:03 -070028 // <'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug
David Tolnayc2f1aba2017-11-12 20:29:22 -080029 let generics = Generics {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070030 gt_token: Some(Default::default()),
31 lt_token: Some(Default::default()),
David Tolnayf2cfd722017-12-31 18:02:51 -050032 params: punctuated![
David Tolnayc2f1aba2017-11-12 20:29:22 -080033 GenericParam::Lifetime(LifetimeDef {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070034 attrs: Default::default(),
David Tolnaye2099f32018-03-31 18:42:43 +020035 lifetime: Lifetime::new("'a", Span::call_site()),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070036 bounds: Default::default(),
37 colon_token: None,
David Tolnayc2f1aba2017-11-12 20:29:22 -080038 }),
39 GenericParam::Lifetime(LifetimeDef {
Alex Crichtonccbb45d2017-05-23 10:58:24 -070040 attrs: Default::default(),
David Tolnaye2099f32018-03-31 18:42:43 +020041 lifetime: Lifetime::new("'b", Span::call_site()),
42 bounds: punctuated![Lifetime::new("'a", Span::call_site())],
David Tolnay42eaae12017-12-26 23:05:18 -050043 colon_token: Some(token::Colon::default()),
David Tolnayc2f1aba2017-11-12 20:29:22 -080044 }),
45 GenericParam::Type(TypeParam {
David Tolnay94d2b792018-04-29 12:26:10 -070046 attrs: vec![Attribute {
47 bracket_token: Default::default(),
48 pound_token: Default::default(),
49 style: AttrStyle::Outer,
50 path: "may_dangle".into(),
51 tts: TokenStream::empty(),
52 is_sugared_doc: false,
53 }],
Alex Crichtonccbb45d2017-05-23 10:58:24 -070054 ident: "T".into(),
David Tolnay94d2b792018-04-29 12:26:10 -070055 bounds: punctuated![TypeParamBound::Lifetime(Lifetime::new(
56 "'a",
57 Span::call_site()
58 )),],
David Tolnay51382052017-12-27 13:46:21 -050059 default: Some(
60 TypeTuple {
David Tolnayeadbda32017-12-29 02:33:47 -050061 elems: Default::default(),
David Tolnay51382052017-12-27 13:46:21 -050062 paren_token: Default::default(),
63 }.into(),
64 ),
Alex Crichtonccbb45d2017-05-23 10:58:24 -070065 colon_token: Some(Default::default()),
66 eq_token: Default::default(),
David Tolnayc2f1aba2017-11-12 20:29:22 -080067 }),
David Tolnaydd125562017-12-31 02:16:22 -050068 ],
David Tolnayac997dd2017-12-27 23:18:22 -050069 where_clause: Some(WhereClause {
70 where_token: Default::default(),
David Tolnay94d2b792018-04-29 12:26:10 -070071 predicates: punctuated![WherePredicate::Type(PredicateType {
72 lifetimes: None,
73 colon_token: Default::default(),
74 bounded_ty: TypePath {
75 qself: None,
76 path: "T".into(),
77 }.into(),
78 bounds: punctuated![TypeParamBound::Trait(TraitBound {
79 paren_token: None,
80 modifier: TraitBoundModifier::None,
David Tolnay40fb8ce2018-01-02 10:53:46 -080081 lifetimes: None,
David Tolnay94d2b792018-04-29 12:26:10 -070082 path: "Debug".into(),
83 }),],
84 }),],
David Tolnayac997dd2017-12-27 23:18:22 -050085 }),
David Tolnayb153dbc2016-10-04 23:39:10 -070086 };
87
88 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
David Tolnaye7678922016-10-13 20:44:03 -070089 let tokens = quote! {
90 impl #impl_generics MyTrait for Test #ty_generics #where_clause {}
David Tolnayb153dbc2016-10-04 23:39:10 -070091 };
David Tolnay51382052017-12-27 13:46:21 -050092 let expected = concat!(
93 "impl < 'a , 'b : 'a , # [ may_dangle ] T : 'a > ",
94 "MyTrait for Test < 'a , 'b , T > ",
95 "where T : Debug { }"
96 );
David Tolnayc879a502017-01-25 15:51:32 -080097 assert_eq!(expected, tokens.to_string());
David Tolnayb153dbc2016-10-04 23:39:10 -070098
David Tolnayc879a502017-01-25 15:51:32 -080099 let turbofish = ty_generics.as_turbofish();
100 let tokens = quote! {
101 Test #turbofish
102 };
103 let expected = "Test :: < 'a , 'b , T >";
David Tolnaye7678922016-10-13 20:44:03 -0700104 assert_eq!(expected, tokens.to_string());
David Tolnayb153dbc2016-10-04 23:39:10 -0700105}
David Tolnay23d83f92017-01-25 15:41:47 -0800106
107#[test]
108fn test_ty_param_bound() {
109 let tokens = quote!('a);
David Tolnaye2099f32018-03-31 18:42:43 +0200110 let expected = TypeParamBound::Lifetime(Lifetime::new("'a", Span::call_site()));
David Tolnay51382052017-12-27 13:46:21 -0500111 assert_eq!(
112 expected,
113 common::parse::syn::<TypeParamBound>(tokens.into())
114 );
David Tolnay23d83f92017-01-25 15:41:47 -0800115
Bastien Orivel340553a2018-02-15 23:57:38 +0100116 let tokens = quote!('_);
David Tolnaye2099f32018-03-31 18:42:43 +0200117 let expected = TypeParamBound::Lifetime(Lifetime::new("'_", Span::call_site()));
Bastien Orivel340553a2018-02-15 23:57:38 +0100118 assert_eq!(
119 expected,
120 common::parse::syn::<TypeParamBound>(tokens.into())
121 );
122
David Tolnay23d83f92017-01-25 15:41:47 -0800123 let tokens = quote!(Debug);
David Tolnay40fb8ce2018-01-02 10:53:46 -0800124 let expected = TypeParamBound::Trait(TraitBound {
David Tolnayc1f5d5d2018-03-31 22:17:56 +0200125 paren_token: None,
David Tolnay40fb8ce2018-01-02 10:53:46 -0800126 modifier: TraitBoundModifier::None,
127 lifetimes: None,
128 path: "Debug".into(),
129 });
David Tolnay51382052017-12-27 13:46:21 -0500130 assert_eq!(
131 expected,
132 common::parse::syn::<TypeParamBound>(tokens.into())
133 );
David Tolnay23d83f92017-01-25 15:41:47 -0800134
135 let tokens = quote!(?Sized);
David Tolnay40fb8ce2018-01-02 10:53:46 -0800136 let expected = TypeParamBound::Trait(TraitBound {
David Tolnayc1f5d5d2018-03-31 22:17:56 +0200137 paren_token: None,
David Tolnay40fb8ce2018-01-02 10:53:46 -0800138 modifier: TraitBoundModifier::Maybe(Default::default()),
139 lifetimes: None,
140 path: "Sized".into(),
141 });
David Tolnay51382052017-12-27 13:46:21 -0500142 assert_eq!(
143 expected,
144 common::parse::syn::<TypeParamBound>(tokens.into())
145 );
David Tolnay23d83f92017-01-25 15:41:47 -0800146}
Geoffry Songac02b182018-05-19 22:11:31 -0700147
148#[test]
149fn test_fn_precedence_in_where_clause() {
150 // This should parse as two separate bounds, `FnOnce() -> i32` and `Send` - not `FnOnce() -> (i32 + Send)`.
151 let sig = quote!(fn f<G>() where G: FnOnce() -> i32 + Send {});
152 let fun = common::parse::syn::<ItemFn>(sig.into());
153 let where_clause = fun.decl.generics.where_clause.as_ref().unwrap();
154 assert_eq!(where_clause.predicates.len(), 1);
155 let predicate = match where_clause.predicates[0] {
156 WherePredicate::Type(ref pred) => pred,
157 _ => panic!("wrong predicate kind"),
158 };
159 assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds);
160 let first_bound = &predicate.bounds[0];
161 assert_eq!(quote!(#first_bound).to_string(), "FnOnce ( ) -> i32");
162 let second_bound = &predicate.bounds[1];
163 assert_eq!(quote!(#second_bound).to_string(), "Send");
164}