]> git.lizzy.rs Git - rust.git/blob - crates/parser/src/grammar/type_params.rs
Replace SyntaxKind usage with T! macro where applicable
[rust.git] / crates / parser / src / grammar / type_params.rs
1 //! FIXME: write short doc here
2
3 use super::*;
4
5 pub(super) fn opt_generic_param_list(p: &mut Parser) {
6     if !p.at(T![<]) {
7         return;
8     }
9     generic_param_list(p);
10 }
11
12 fn generic_param_list(p: &mut Parser) {
13     assert!(p.at(T![<]));
14     let m = p.start();
15     p.bump(T![<]);
16
17     while !p.at(EOF) && !p.at(T![>]) {
18         let m = p.start();
19
20         // test generic_lifetime_type_attribute
21         // fn foo<#[derive(Lifetime)] 'a, #[derive(Type)] T>(_: &'a T) {
22         // }
23         attributes::outer_attrs(p);
24
25         match p.current() {
26             LIFETIME_IDENT => lifetime_param(p, m),
27             IDENT => type_param(p, m),
28             T![const] => const_param(p, m),
29             _ => {
30                 m.abandon(p);
31                 p.err_and_bump("expected type parameter")
32             }
33         }
34         if !p.at(T![>]) && !p.expect(T![,]) {
35             break;
36         }
37     }
38     p.expect(T![>]);
39     m.complete(p, GENERIC_PARAM_LIST);
40 }
41
42 fn lifetime_param(p: &mut Parser, m: Marker) {
43     assert!(p.at(LIFETIME_IDENT));
44     lifetime(p);
45     if p.at(T![:]) {
46         lifetime_bounds(p);
47     }
48     m.complete(p, LIFETIME_PARAM);
49 }
50
51 fn type_param(p: &mut Parser, m: Marker) {
52     assert!(p.at(IDENT));
53     name(p);
54     if p.at(T![:]) {
55         bounds(p);
56     }
57     // test type_param_default
58     // struct S<T = i32>;
59     if p.at(T![=]) {
60         p.bump(T![=]);
61         types::type_(p)
62     }
63     m.complete(p, TYPE_PARAM);
64 }
65
66 // test const_param
67 // struct S<const N: u32>;
68 fn const_param(p: &mut Parser, m: Marker) {
69     assert!(p.at(T![const]));
70     p.bump(T![const]);
71     name(p);
72     types::ascription(p);
73     m.complete(p, CONST_PARAM);
74 }
75
76 // test type_param_bounds
77 // struct S<T: 'a + ?Sized + (Copy)>;
78 pub(super) fn bounds(p: &mut Parser) {
79     assert!(p.at(T![:]));
80     p.bump(T![:]);
81     bounds_without_colon(p);
82 }
83
84 fn lifetime_bounds(p: &mut Parser) {
85     assert!(p.at(T![:]));
86     p.bump(T![:]);
87     while p.at(LIFETIME_IDENT) {
88         lifetime(p);
89         if !p.eat(T![+]) {
90             break;
91         }
92     }
93 }
94
95 pub(super) fn bounds_without_colon_m(p: &mut Parser, marker: Marker) -> CompletedMarker {
96     while type_bound(p) {
97         if !p.eat(T![+]) {
98             break;
99         }
100     }
101
102     marker.complete(p, TYPE_BOUND_LIST)
103 }
104
105 pub(super) fn bounds_without_colon(p: &mut Parser) {
106     let m = p.start();
107     bounds_without_colon_m(p, m);
108 }
109
110 fn type_bound(p: &mut Parser) -> bool {
111     let m = p.start();
112     let has_paren = p.eat(T!['(']);
113     p.eat(T![?]);
114     match p.current() {
115         LIFETIME_IDENT => lifetime(p),
116         T![for] => types::for_type(p, false),
117         _ if paths::is_use_path_start(p) => types::path_type_(p, false),
118         _ => {
119             m.abandon(p);
120             return false;
121         }
122     }
123     if has_paren {
124         p.expect(T![')']);
125     }
126     m.complete(p, TYPE_BOUND);
127
128     true
129 }
130
131 // test where_clause
132 // fn foo()
133 // where
134 //    'a: 'b + 'c,
135 //    T: Clone + Copy + 'static,
136 //    Iterator::Item: 'a,
137 //    <T as Iterator>::Item: 'a
138 // {}
139 pub(super) fn opt_where_clause(p: &mut Parser) {
140     if !p.at(T![where]) {
141         return;
142     }
143     let m = p.start();
144     p.bump(T![where]);
145
146     while is_where_predicate(p) {
147         where_predicate(p);
148
149         let comma = p.eat(T![,]);
150
151         if is_where_clause_end(p) {
152             break;
153         }
154
155         if !comma {
156             p.error("expected comma");
157         }
158     }
159
160     m.complete(p, WHERE_CLAUSE);
161 }
162
163 fn is_where_predicate(p: &mut Parser) -> bool {
164     match p.current() {
165         LIFETIME_IDENT => true,
166         T![impl] => false,
167         token => types::TYPE_FIRST.contains(token),
168     }
169 }
170
171 fn is_where_clause_end(p: &mut Parser) -> bool {
172     matches!(p.current(), T!['{'] | T![;] | T![=])
173 }
174
175 fn where_predicate(p: &mut Parser) {
176     let m = p.start();
177     match p.current() {
178         LIFETIME_IDENT => {
179             lifetime(p);
180             if p.at(T![:]) {
181                 bounds(p);
182             } else {
183                 p.error("expected colon");
184             }
185         }
186         T![impl] => {
187             p.error("expected lifetime or type");
188         }
189         _ => {
190             // test where_pred_for
191             // fn for_trait<F>()
192             // where
193             //    for<'a> F: Fn(&'a str)
194             // { }
195             if p.at(T![for]) {
196                 types::for_binder(p);
197             }
198
199             types::type_(p);
200
201             if p.at(T![:]) {
202                 bounds(p);
203             } else {
204                 p.error("expected colon");
205             }
206         }
207     }
208     m.complete(p, WHERE_PRED);
209 }