parser/grammar/
generic_params.rs

1use 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
11// test generic_param_list
12// fn f<T: Clone>() {}
13
14// test_err generic_param_list_recover
15// fn f<T: Clone,, U:, V>() {}
16pub(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            // test generic_param_attribute
28            // fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
29            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
54// test lifetime_param
55// fn f<'a: 'b>() {}
56fn 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
65// test type_param
66// fn f<T: Clone>() {}
67fn 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        // test type_param_default
75        // struct S<T = i32>;
76        p.bump(T![=]);
77        types::type_(p);
78    }
79    m.complete(p, TYPE_PARAM);
80}
81
82// test const_param
83// struct S<const N: u32>;
84fn 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        // test const_param_default_literal
95        // struct A<const N: i32 = -1>;
96
97        // test const_param_default_expression
98        // struct A<const N: i32 = { 1 }>;
99
100        // test const_param_default_path
101        // struct A<const N: i32 = i32::MAX>;
102        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
124// test type_param_bounds
125// struct S<T: 'a + ?Sized + (Copy) + [const] Drop>;
126pub(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        // test for_binder_bound
151        // fn foo<T: for<'a> [const] async Trait>() {}
152        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        // test precise_capturing
160        // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
161
162        // test_err precise_capturing_invalid
163        // type T = impl use<self, 1>;
164        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        // test maybe_const_trait_bound
205        // const fn foo(_: impl [const] Trait) {}
206        p.expect(T![const]);
207        p.expect(T![']']);
208    } else {
209        // test const_trait_bound
210        // const fn foo(_: impl const Trait) {}
211        p.eat(T![const]);
212    }
213    // test async_trait_bound
214    // fn async_foo(_: impl async Fn(&i32)) {}
215    p.eat(T![async]);
216    // test question_for_type_trait_bound
217    // fn f<T>() where T: for<> ?Sized {}
218    p.eat(T![?]);
219
220    // test_err invalid_question_for_type_trait_bound
221    // fn f<T>() where T: ?for<> Sized {}
222
223    if paths::is_use_path_start(p) {
224        types::path_type_bounds(p, false);
225        // test_err type_bounds_macro_call_recovery
226        // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
227        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
242// test where_clause
243// fn foo()
244// where
245//    'a: 'b + 'c,
246//    T: Clone + Copy + 'static,
247//    Iterator::Item: 'a,
248//    <T as Iterator>::Item: 'a
249// {}
250pub(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                // test where_pred_for
300                // fn for_trait<F>()
301                // where
302                //    for<'a> F: Fn(&'a str)
303                // { }
304                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}