aboutsummaryrefslogtreecommitdiff
path: root/crates/parser/src/grammar/types.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/parser/src/grammar/types.rs')
-rw-r--r--crates/parser/src/grammar/types.rs324
1 files changed, 324 insertions, 0 deletions
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
new file mode 100644
index 000000000..0aa173a52
--- /dev/null
+++ b/crates/parser/src/grammar/types.rs
@@ -0,0 +1,324 @@
1//! FIXME: write short doc here
2
3use super::*;
4
5pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![
6 T!['('],
7 T!['['],
8 T![<],
9 T![!],
10 T![*],
11 T![&],
12 T![_],
13 T![fn],
14 T![unsafe],
15 T![extern],
16 T![for],
17 T![impl],
18 T![dyn],
19]);
20
21const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA, L_DOLLAR];
22
23pub(crate) fn type_(p: &mut Parser) {
24 type_with_bounds_cond(p, true);
25}
26
27pub(super) fn type_no_bounds(p: &mut Parser) {
28 type_with_bounds_cond(p, false);
29}
30
31fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
32 match p.current() {
33 T!['('] => paren_or_tuple_type(p),
34 T![!] => never_type(p),
35 T![*] => pointer_type(p),
36 T!['['] => array_or_slice_type(p),
37 T![&] => reference_type(p),
38 T![_] => placeholder_type(p),
39 T![fn] | T![unsafe] | T![extern] => fn_pointer_type(p),
40 T![for] => for_type(p),
41 T![impl] => impl_trait_type(p),
42 T![dyn] => dyn_trait_type(p),
43 // Some path types are not allowed to have bounds (no plus)
44 T![<] => path_type_(p, allow_bounds),
45 _ if paths::is_use_path_start(p) => path_or_macro_type_(p, allow_bounds),
46 _ => {
47 p.err_recover("expected type", TYPE_RECOVERY_SET);
48 }
49 }
50}
51
52pub(super) fn ascription(p: &mut Parser) {
53 p.expect(T![:]);
54 type_(p)
55}
56
57fn paren_or_tuple_type(p: &mut Parser) {
58 assert!(p.at(T!['(']));
59 let m = p.start();
60 p.bump(T!['(']);
61 let mut n_types: u32 = 0;
62 let mut trailing_comma: bool = false;
63 while !p.at(EOF) && !p.at(T![')']) {
64 n_types += 1;
65 type_(p);
66 if p.eat(T![,]) {
67 trailing_comma = true;
68 } else {
69 trailing_comma = false;
70 break;
71 }
72 }
73 p.expect(T![')']);
74
75 let kind = if n_types == 1 && !trailing_comma {
76 // test paren_type
77 // type T = (i32);
78 PAREN_TYPE
79 } else {
80 // test unit_type
81 // type T = ();
82
83 // test singleton_tuple_type
84 // type T = (i32,);
85 TUPLE_TYPE
86 };
87 m.complete(p, kind);
88}
89
90// test never_type
91// type Never = !;
92fn never_type(p: &mut Parser) {
93 assert!(p.at(T![!]));
94 let m = p.start();
95 p.bump(T![!]);
96 m.complete(p, NEVER_TYPE);
97}
98
99fn pointer_type(p: &mut Parser) {
100 assert!(p.at(T![*]));
101 let m = p.start();
102 p.bump(T![*]);
103
104 match p.current() {
105 // test pointer_type_mut
106 // type M = *mut ();
107 // type C = *mut ();
108 T![mut] | T![const] => p.bump_any(),
109 _ => {
110 // test_err pointer_type_no_mutability
111 // type T = *();
112 p.error(
113 "expected mut or const in raw pointer type \
114 (use `*mut T` or `*const T` as appropriate)",
115 );
116 }
117 };
118
119 type_no_bounds(p);
120 m.complete(p, PTR_TYPE);
121}
122
123fn array_or_slice_type(p: &mut Parser) {
124 assert!(p.at(T!['[']));
125 let m = p.start();
126 p.bump(T!['[']);
127
128 type_(p);
129 let kind = match p.current() {
130 // test slice_type
131 // type T = [()];
132 T![']'] => {
133 p.bump(T![']']);
134 SLICE_TYPE
135 }
136
137 // test array_type
138 // type T = [(); 92];
139 T![;] => {
140 p.bump(T![;]);
141 expressions::expr(p);
142 p.expect(T![']']);
143 ARRAY_TYPE
144 }
145 // test_err array_type_missing_semi
146 // type T = [() 92];
147 _ => {
148 p.error("expected `;` or `]`");
149 SLICE_TYPE
150 }
151 };
152 m.complete(p, kind);
153}
154
155// test reference_type;
156// type A = &();
157// type B = &'static ();
158// type C = &mut ();
159fn reference_type(p: &mut Parser) {
160 assert!(p.at(T![&]));
161 let m = p.start();
162 p.bump(T![&]);
163 p.eat(LIFETIME);
164 p.eat(T![mut]);
165 type_no_bounds(p);
166 m.complete(p, REF_TYPE);
167}
168
169// test placeholder_type
170// type Placeholder = _;
171fn placeholder_type(p: &mut Parser) {
172 assert!(p.at(T![_]));
173 let m = p.start();
174 p.bump(T![_]);
175 m.complete(p, INFER_TYPE);
176}
177
178// test fn_pointer_type
179// type A = fn();
180// type B = unsafe fn();
181// type C = unsafe extern "C" fn();
182// type D = extern "C" fn ( u8 , ... ) -> u8;
183fn fn_pointer_type(p: &mut Parser) {
184 let m = p.start();
185 p.eat(T![unsafe]);
186 if p.at(T![extern]) {
187 abi(p);
188 }
189 // test_err fn_pointer_type_missing_fn
190 // type F = unsafe ();
191 if !p.eat(T![fn]) {
192 m.abandon(p);
193 p.error("expected `fn`");
194 return;
195 }
196 if p.at(T!['(']) {
197 params::param_list_fn_ptr(p);
198 } else {
199 p.error("expected parameters")
200 }
201 // test fn_pointer_type_with_ret
202 // type F = fn() -> ();
203 opt_fn_ret_type(p);
204 m.complete(p, FN_PTR_TYPE);
205}
206
207pub(super) fn for_binder(p: &mut Parser) {
208 assert!(p.at(T![for]));
209 p.bump(T![for]);
210 if p.at(T![<]) {
211 type_params::opt_type_param_list(p);
212 } else {
213 p.error("expected `<`");
214 }
215}
216
217// test for_type
218// type A = for<'a> fn() -> ();
219// type B = for<'a> unsafe extern "C" fn(&'a ()) -> ();
220// type Obj = for<'a> PartialEq<&'a i32>;
221pub(super) fn for_type(p: &mut Parser) {
222 assert!(p.at(T![for]));
223 let m = p.start();
224 for_binder(p);
225 match p.current() {
226 T![fn] | T![unsafe] | T![extern] => {}
227 // OK: legacy trait object format
228 _ if paths::is_use_path_start(p) => {}
229 _ => {
230 p.error("expected a function pointer or path");
231 }
232 }
233 type_no_bounds(p);
234 m.complete(p, FOR_TYPE);
235}
236
237// test impl_trait_type
238// type A = impl Iterator<Item=Foo<'a>> + 'a;
239fn impl_trait_type(p: &mut Parser) {
240 assert!(p.at(T![impl]));
241 let m = p.start();
242 p.bump(T![impl]);
243 type_params::bounds_without_colon(p);
244 m.complete(p, IMPL_TRAIT_TYPE);
245}
246
247// test dyn_trait_type
248// type A = dyn Iterator<Item=Foo<'a>> + 'a;
249fn dyn_trait_type(p: &mut Parser) {
250 assert!(p.at(T![dyn]));
251 let m = p.start();
252 p.bump(T![dyn]);
253 type_params::bounds_without_colon(p);
254 m.complete(p, DYN_TRAIT_TYPE);
255}
256
257// test path_type
258// type A = Foo;
259// type B = ::Foo;
260// type C = self::Foo;
261// type D = super::Foo;
262pub(super) fn path_type(p: &mut Parser) {
263 path_type_(p, true)
264}
265
266// test macro_call_type
267// type A = foo!();
268// type B = crate::foo!();
269fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
270 assert!(paths::is_path_start(p));
271 let m = p.start();
272 paths::type_path(p);
273
274 let kind = if p.at(T![!]) && !p.at(T![!=]) {
275 items::macro_call_after_excl(p);
276 MACRO_CALL
277 } else {
278 PATH_TYPE
279 };
280
281 let path = m.complete(p, kind);
282
283 if allow_bounds {
284 opt_path_type_bounds_as_dyn_trait_type(p, path);
285 }
286}
287
288pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
289 assert!(paths::is_path_start(p));
290 let m = p.start();
291 paths::type_path(p);
292
293 // test path_type_with_bounds
294 // fn foo() -> Box<T + 'f> {}
295 // fn foo() -> Box<dyn T + 'f> {}
296 let path = m.complete(p, PATH_TYPE);
297 if allow_bounds {
298 opt_path_type_bounds_as_dyn_trait_type(p, path);
299 }
300}
301
302/// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE
303/// with a TYPE_BOUND_LIST
304fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) {
305 if !p.at(T![+]) {
306 return;
307 }
308
309 // First create a TYPE_BOUND from the completed PATH_TYPE
310 let m = path_type_marker.precede(p).complete(p, TYPE_BOUND);
311
312 // Next setup a marker for the TYPE_BOUND_LIST
313 let m = m.precede(p);
314
315 // This gets consumed here so it gets properly set
316 // in the TYPE_BOUND_LIST
317 p.eat(T![+]);
318
319 // Parse rest of the bounds into the TYPE_BOUND_LIST
320 let m = type_params::bounds_without_colon_m(p, m);
321
322 // Finally precede everything with DYN_TRAIT_TYPE
323 m.precede(p).complete(p, DYN_TRAIT_TYPE);
324}