parser/grammar/
generic_params.rs1use crate::grammar::attributes::ATTRIBUTE_FIRST;
2
3use super::*;
4
5pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
6 if p.at(T![<]) {
7 generic_param_list(p);
8 }
9}
10
11pub(super) fn generic_param_list(p: &mut Parser<'_>) {
17 assert!(p.at(T![<]));
18 let m = p.start();
19 delimited(
20 p,
21 T![<],
22 T![>],
23 T![,],
24 || "expected generic parameter".into(),
25 GENERIC_PARAM_FIRST.union(ATTRIBUTE_FIRST),
26 |p| {
27 let m = p.start();
30 attributes::outer_attrs(p);
31 generic_param(p, m)
32 },
33 );
34
35 m.complete(p, GENERIC_PARAM_LIST);
36}
37
38const GENERIC_PARAM_FIRST: TokenSet = TokenSet::new(&[IDENT, LIFETIME_IDENT, T![const]]);
39
40fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool {
41 match p.current() {
42 LIFETIME_IDENT => lifetime_param(p, m),
43 IDENT => type_param(p, m),
44 T![const] => const_param(p, m),
45 _ => {
46 m.abandon(p);
47 p.err_and_bump("expected generic parameter");
48 return false;
49 }
50 }
51 true
52}
53
54fn lifetime_param(p: &mut Parser<'_>, m: Marker) {
57 assert!(p.at(LIFETIME_IDENT));
58 lifetime(p);
59 if p.eat(T![:]) {
60 lifetime_bounds(p);
61 }
62 m.complete(p, LIFETIME_PARAM);
63}
64
65fn type_param(p: &mut Parser<'_>, m: Marker) {
68 assert!(p.at(IDENT));
69 name(p);
70 if p.at(T![:]) {
71 bounds(p);
72 }
73 if p.at(T![=]) {
74 p.bump(T![=]);
77 types::type_(p);
78 }
79 m.complete(p, TYPE_PARAM);
80}
81
82fn const_param(p: &mut Parser<'_>, m: Marker) {
85 p.bump(T![const]);
86 name(p);
87 if p.at(T![:]) {
88 types::ascription(p);
89 } else {
90 p.error("missing type for const parameter");
91 }
92
93 if p.eat(T![=]) {
94 generic_args::const_arg(p);
103 }
104
105 m.complete(p, CONST_PARAM);
106}
107
108fn lifetime_bounds(p: &mut Parser<'_>) {
109 let marker = p.start();
110 while {
111 if !matches!(p.current(), LIFETIME_IDENT | T![>] | T![,]) {
112 p.error("expected lifetime");
113 }
114
115 type_bound(p)
116 } {
117 if !p.eat(T![+]) {
118 break;
119 }
120 }
121 marker.complete(p, TYPE_BOUND_LIST);
122}
123
124pub(super) fn bounds(p: &mut Parser<'_>) {
127 p.expect(T![:]);
128 bounds_without_colon(p);
129}
130
131pub(super) fn bounds_without_colon(p: &mut Parser<'_>) {
132 let m = p.start();
133 bounds_without_colon_m(p, m);
134}
135
136pub(super) fn bounds_without_colon_m(p: &mut Parser<'_>, marker: Marker) -> CompletedMarker {
137 while type_bound(p) {
138 if !p.eat(T![+]) {
139 break;
140 }
141 }
142 marker.complete(p, TYPE_BOUND_LIST)
143}
144
145fn type_bound(p: &mut Parser<'_>) -> bool {
146 let m = p.start();
147 let has_paren = p.eat(T!['(']);
148 match p.current() {
149 LIFETIME_IDENT => lifetime(p),
150 T![for] => {
153 types::for_binder(p);
154 if path_type_bound(p).is_err() {
155 m.abandon(p);
156 return false;
157 }
158 }
159 T![use] if p.nth_at(1, T![<]) => {
165 p.bump_any();
166 let m = p.start();
167 delimited(
168 p,
169 T![<],
170 T![>],
171 T![,],
172 || "expected identifier or lifetime".into(),
173 TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]),
174 |p| {
175 if p.at(LIFETIME_IDENT) {
176 lifetime(p);
177 } else {
178 name_ref_or_upper_self(p);
179 }
180 true
181 },
182 );
183 m.complete(p, USE_BOUND_GENERIC_ARGS);
184 }
185 _ => {
186 if path_type_bound(p).is_err() {
187 m.abandon(p);
188 return false;
189 }
190 }
191 }
192 if has_paren {
193 p.expect(T![')']);
194 }
195 m.complete(p, TYPE_BOUND);
196
197 true
198}
199
200fn path_type_bound(p: &mut Parser<'_>) -> Result<(), ()> {
201 if p.eat(T![~]) {
202 p.expect(T![const]);
203 } else if p.eat(T!['[']) {
204 p.expect(T![const]);
207 p.expect(T![']']);
208 } else {
209 p.eat(T![const]);
212 }
213 p.eat(T![async]);
216 p.eat(T![?]);
219
220 if paths::is_use_path_start(p) {
224 types::path_type_bounds(p, false);
225 if p.at(T![!]) {
228 let m = p.start();
229 p.bump(T![!]);
230 p.error("unexpected `!` in type path, macro calls are not allowed here");
231 if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
232 items::token_tree(p);
233 }
234 m.complete(p, ERROR);
235 }
236 Ok(())
237 } else {
238 Err(())
239 }
240}
241
242pub(super) fn opt_where_clause(p: &mut Parser<'_>) {
251 if !p.at(T![where]) {
252 return;
253 }
254 let m = p.start();
255 p.bump(T![where]);
256
257 while is_where_predicate(p) {
258 where_predicate(p);
259
260 let comma = p.eat(T![,]);
261
262 match p.current() {
263 T!['{'] | T![;] | T![=] => break,
264 _ => (),
265 }
266
267 if !comma {
268 p.error("expected comma");
269 }
270 }
271
272 m.complete(p, WHERE_CLAUSE);
273
274 fn is_where_predicate(p: &mut Parser<'_>) -> bool {
275 match p.current() {
276 LIFETIME_IDENT => true,
277 T![impl] => false,
278 token => types::TYPE_FIRST.contains(token),
279 }
280 }
281}
282
283fn where_predicate(p: &mut Parser<'_>) {
284 let m = p.start();
285 match p.current() {
286 LIFETIME_IDENT => {
287 lifetime(p);
288 if p.at(T![:]) {
289 bounds(p);
290 } else {
291 p.error("expected colon");
292 }
293 }
294 T![impl] => {
295 p.error("expected lifetime or type");
296 }
297 _ => {
298 if p.at(T![for]) {
299 types::for_binder(p);
305 }
306
307 types::type_(p);
308
309 if p.at(T![:]) {
310 bounds(p);
311 } else {
312 p.error("expected colon");
313 }
314 }
315 }
316 m.complete(p, WHERE_PRED);
317}