aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar/type_params.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/grammar/type_params.rs')
-rw-r--r--crates/parser/src/grammar/type_params.rs209
1 files changed, 209 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs
new file mode 100644
index 000000000..90dabb4c0
--- /dev/null
+++ b/crates/parser/src/grammar/type_params.rs
@@ -0,0 +1,209 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) fn opt_type_param_list(p: &mut Parser) {
6 if !p.at(T![<]) {
7 return;
8 }
9 type_param_list(p);
10}
11
12fn type_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_attributes(p);
24
25 match p.current() {
26 LIFETIME => lifetime_param(p, m),
27 IDENT => type_param(p, m),
28 CONST_KW => type_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
42fn lifetime_param(p: &mut Parser, m: Marker) {
43 assert!(p.at(LIFETIME));
44 p.bump(LIFETIME);
45 if p.at(T![:]) {
46 lifetime_bounds(p);
47 }
48 m.complete(p, LIFETIME_PARAM);
49}
50
51fn 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>;
68fn type_const_param(p: &mut Parser, m: Marker) {
69 assert!(p.at(CONST_KW));
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)>;
78pub(super) fn bounds(p: &mut Parser) {
79 assert!(p.at(T![:]));
80 p.bump(T![:]);
81 bounds_without_colon(p);
82}
83
84fn lifetime_bounds(p: &mut Parser) {
85 assert!(p.at(T![:]));
86 p.bump(T![:]);
87 while p.at(LIFETIME) {
88 p.bump(LIFETIME);
89 if !p.eat(T![+]) {
90 break;
91 }
92 }
93}
94
95pub(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
105pub(super) fn bounds_without_colon(p: &mut Parser) {
106 let m = p.start();
107 bounds_without_colon_m(p, m);
108}
109
110fn 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 => p.bump(LIFETIME),
116 T![for] => types::for_type(p),
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// {}
139pub(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
163fn is_where_predicate(p: &mut Parser) -> bool {
164 match p.current() {
165 LIFETIME => true,
166 T![impl] => false,
167 token => types::TYPE_FIRST.contains(token),
168 }
169}
170
171fn is_where_clause_end(p: &mut Parser) -> bool {
172 matches!(p.current(), T!['{'] | T![;] | T![=])
173}
174
175fn where_predicate(p: &mut Parser) {
176 let m = p.start();
177 match p.current() {
178 LIFETIME => {
179 p.bump(LIFETIME);
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}