1 mod atom;
2
3 use crate::grammar::attributes::ATTRIBUTE_FIRST;
4
5 use super::*;
6
7 pub(crate) use atom::{block_expr, match_arm_list};
8 pub(super) use atom::{literal, LITERAL_FIRST};
9
10 #[derive(PartialEq, Eq)]
11 pub(super) enum Semicolon {
12 Required,
13 Optional,
14 Forbidden,
15 }
16
17 const EXPR_FIRST: TokenSet = LHS_FIRST;
18
expr(p: &mut Parser<'_>) -> Option<CompletedMarker>19 pub(super) fn expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
20 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
21 expr_bp(p, None, r, 1).map(|(m, _)| m)
22 }
23
expr_stmt( p: &mut Parser<'_>, m: Option<Marker>, ) -> Option<(CompletedMarker, BlockLike)>24 pub(super) fn expr_stmt(
25 p: &mut Parser<'_>,
26 m: Option<Marker>,
27 ) -> Option<(CompletedMarker, BlockLike)> {
28 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
29 expr_bp(p, m, r, 1)
30 }
31
expr_no_struct(p: &mut Parser<'_>)32 fn expr_no_struct(p: &mut Parser<'_>) {
33 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
34 expr_bp(p, None, r, 1);
35 }
36
37 /// Parses the expression in `let pattern = expression`.
38 /// It needs to be parsed with lower precedence than `&&`, so that
39 /// `if let true = true && false` is parsed as `if (let true = true) && (true)`
40 /// and not `if let true = (true && true)`.
expr_let(p: &mut Parser<'_>)41 fn expr_let(p: &mut Parser<'_>) {
42 let r = Restrictions { forbid_structs: true, prefer_stmt: false };
43 expr_bp(p, None, r, 5);
44 }
45
stmt(p: &mut Parser<'_>, semicolon: Semicolon)46 pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
47 if p.eat(T![;]) {
48 return;
49 }
50
51 let m = p.start();
52 // test attr_on_expr_stmt
53 // fn foo() {
54 // #[A] foo();
55 // #[B] bar!{}
56 // #[C] #[D] {}
57 // #[D] return ();
58 // }
59 attributes::outer_attrs(p);
60
61 if p.at(T![let]) {
62 let_stmt(p, m, semicolon);
63 return;
64 }
65
66 // test block_items
67 // fn a() { fn b() {} }
68 let m = match items::opt_item(p, m) {
69 Ok(()) => return,
70 Err(m) => m,
71 };
72
73 if !p.at_ts(EXPR_FIRST) {
74 p.err_and_bump("expected expression, item or let statement");
75 m.abandon(p);
76 return;
77 }
78
79 if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
80 if !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) {
81 // test no_semi_after_block
82 // fn foo() {
83 // if true {}
84 // loop {}
85 // match () {}
86 // while true {}
87 // for _ in () {}
88 // {}
89 // {}
90 // macro_rules! test {
91 // () => {}
92 // }
93 // test!{}
94 // }
95 let m = cm.precede(p);
96 match semicolon {
97 Semicolon::Required => {
98 if blocklike.is_block() {
99 p.eat(T![;]);
100 } else {
101 p.expect(T![;]);
102 }
103 }
104 Semicolon::Optional => {
105 p.eat(T![;]);
106 }
107 Semicolon::Forbidden => (),
108 }
109 m.complete(p, EXPR_STMT);
110 }
111 }
112
113 // test let_stmt
114 // fn f() { let x: i32 = 92; }
115 fn let_stmt(p: &mut Parser<'_>, m: Marker, with_semi: Semicolon) {
116 p.bump(T![let]);
117 patterns::pattern(p);
118 if p.at(T![:]) {
119 // test let_stmt_ascription
120 // fn f() { let x: i32; }
121 types::ascription(p);
122 }
123
124 let mut expr_after_eq: Option<CompletedMarker> = None;
125 if p.eat(T![=]) {
126 // test let_stmt_init
127 // fn f() { let x = 92; }
128 expr_after_eq = expressions::expr(p);
129 }
130
131 if p.at(T![else]) {
132 // test_err let_else_right_curly_brace
133 // fn func() { let Some(_) = {Some(1)} else { panic!("h") };}
134 if let Some(expr) = expr_after_eq {
135 if BlockLike::is_blocklike(expr.kind()) {
136 p.error(
137 "right curly brace `}` before `else` in a `let...else` statement not allowed",
138 )
139 }
140 }
141
142 // test let_else
143 // fn f() { let Some(x) = opt else { return }; }
144 let m = p.start();
145 p.bump(T![else]);
146 block_expr(p);
147 m.complete(p, LET_ELSE);
148 }
149
150 match with_semi {
151 Semicolon::Forbidden => (),
152 Semicolon::Optional => {
153 p.eat(T![;]);
154 }
155 Semicolon::Required => {
156 p.expect(T![;]);
157 }
158 }
159 m.complete(p, LET_STMT);
160 }
161 }
162
expr_block_contents(p: &mut Parser<'_>)163 pub(super) fn expr_block_contents(p: &mut Parser<'_>) {
164 attributes::inner_attrs(p);
165
166 while !p.at(EOF) && !p.at(T!['}']) {
167 // test nocontentexpr
168 // fn foo(){
169 // ;;;some_expr();;;;{;;;};;;;Ok(())
170 // }
171
172 // test nocontentexpr_after_item
173 // fn simple_function() {
174 // enum LocalEnum {
175 // One,
176 // Two,
177 // };
178 // fn f() {};
179 // struct S {};
180 // }
181 stmt(p, Semicolon::Required);
182 }
183 }
184
185 #[derive(Clone, Copy)]
186 struct Restrictions {
187 forbid_structs: bool,
188 prefer_stmt: bool,
189 }
190
191 enum Associativity {
192 Left,
193 Right,
194 }
195
196 /// Binding powers of operators for a Pratt parser.
197 ///
198 /// See <https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html>
199 ///
200 /// Note that Rust doesn't define associativity for some infix operators (e.g. `==` and `..`) and
201 /// requires parentheses to disambiguate. We just treat them as left associative.
202 #[rustfmt::skip]
current_op(p: &Parser<'_>) -> (u8, SyntaxKind, Associativity)203 fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind, Associativity) {
204 use Associativity::*;
205 const NOT_AN_OP: (u8, SyntaxKind, Associativity) = (0, T![@], Left);
206 match p.current() {
207 T![|] if p.at(T![||]) => (3, T![||], Left),
208 T![|] if p.at(T![|=]) => (1, T![|=], Right),
209 T![|] => (6, T![|], Left),
210 T![>] if p.at(T![>>=]) => (1, T![>>=], Right),
211 T![>] if p.at(T![>>]) => (9, T![>>], Left),
212 T![>] if p.at(T![>=]) => (5, T![>=], Left),
213 T![>] => (5, T![>], Left),
214 T![=] if p.at(T![=>]) => NOT_AN_OP,
215 T![=] if p.at(T![==]) => (5, T![==], Left),
216 T![=] => (1, T![=], Right),
217 T![<] if p.at(T![<=]) => (5, T![<=], Left),
218 T![<] if p.at(T![<<=]) => (1, T![<<=], Right),
219 T![<] if p.at(T![<<]) => (9, T![<<], Left),
220 T![<] => (5, T![<], Left),
221 T![+] if p.at(T![+=]) => (1, T![+=], Right),
222 T![+] => (10, T![+], Left),
223 T![^] if p.at(T![^=]) => (1, T![^=], Right),
224 T![^] => (7, T![^], Left),
225 T![%] if p.at(T![%=]) => (1, T![%=], Right),
226 T![%] => (11, T![%], Left),
227 T![&] if p.at(T![&=]) => (1, T![&=], Right),
228 // If you update this, remember to update `expr_let()` too.
229 T![&] if p.at(T![&&]) => (4, T![&&], Left),
230 T![&] => (8, T![&], Left),
231 T![/] if p.at(T![/=]) => (1, T![/=], Right),
232 T![/] => (11, T![/], Left),
233 T![*] if p.at(T![*=]) => (1, T![*=], Right),
234 T![*] => (11, T![*], Left),
235 T![.] if p.at(T![..=]) => (2, T![..=], Left),
236 T![.] if p.at(T![..]) => (2, T![..], Left),
237 T![!] if p.at(T![!=]) => (5, T![!=], Left),
238 T![-] if p.at(T![-=]) => (1, T![-=], Right),
239 T![-] => (10, T![-], Left),
240 T![as] => (12, T![as], Left),
241
242 _ => NOT_AN_OP
243 }
244 }
245
246 // Parses expression with binding power of at least bp.
expr_bp( p: &mut Parser<'_>, m: Option<Marker>, mut r: Restrictions, bp: u8, ) -> Option<(CompletedMarker, BlockLike)>247 fn expr_bp(
248 p: &mut Parser<'_>,
249 m: Option<Marker>,
250 mut r: Restrictions,
251 bp: u8,
252 ) -> Option<(CompletedMarker, BlockLike)> {
253 let m = m.unwrap_or_else(|| {
254 let m = p.start();
255 attributes::outer_attrs(p);
256 m
257 });
258
259 if !p.at_ts(EXPR_FIRST) {
260 p.err_recover("expected expression", atom::EXPR_RECOVERY_SET);
261 m.abandon(p);
262 return None;
263 }
264 let mut lhs = match lhs(p, r) {
265 Some((lhs, blocklike)) => {
266 let lhs = lhs.extend_to(p, m);
267 if r.prefer_stmt && blocklike.is_block() {
268 // test stmt_bin_expr_ambiguity
269 // fn f() {
270 // let _ = {1} & 2;
271 // {1} &2;
272 // }
273 return Some((lhs, BlockLike::Block));
274 }
275 lhs
276 }
277 None => {
278 m.abandon(p);
279 return None;
280 }
281 };
282
283 loop {
284 let is_range = p.at(T![..]) || p.at(T![..=]);
285 let (op_bp, op, associativity) = current_op(p);
286 if op_bp < bp {
287 break;
288 }
289 // test as_precedence
290 // fn f() { let _ = &1 as *const i32; }
291 if p.at(T![as]) {
292 lhs = cast_expr(p, lhs);
293 continue;
294 }
295 let m = lhs.precede(p);
296 p.bump(op);
297
298 // test binop_resets_statementness
299 // fn f() { v = {1}&2; }
300 r = Restrictions { prefer_stmt: false, ..r };
301
302 if is_range {
303 // test postfix_range
304 // fn foo() {
305 // let x = 1..;
306 // match 1.. { _ => () };
307 // match a.b()..S { _ => () };
308 // }
309 let has_trailing_expression =
310 p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{']));
311 if !has_trailing_expression {
312 // no RHS
313 lhs = m.complete(p, RANGE_EXPR);
314 break;
315 }
316 }
317
318 let op_bp = match associativity {
319 Associativity::Left => op_bp + 1,
320 Associativity::Right => op_bp,
321 };
322 expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp);
323 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
324 }
325 Some((lhs, BlockLike::NotBlock))
326 }
327
328 const LHS_FIRST: TokenSet =
329 atom::ATOM_EXPR_FIRST.union(TokenSet::new(&[T![&], T![*], T![!], T![.], T![-], T![_]]));
330
lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>331 fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
332 let m;
333 let kind = match p.current() {
334 // test ref_expr
335 // fn foo() {
336 // // reference operator
337 // let _ = &1;
338 // let _ = &mut &f();
339 // let _ = &raw;
340 // let _ = &raw.0;
341 // // raw reference operator
342 // let _ = &raw mut foo;
343 // let _ = &raw const foo;
344 // }
345 T![&] => {
346 m = p.start();
347 p.bump(T![&]);
348 if p.at_contextual_kw(T![raw]) && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const])) {
349 p.bump_remap(T![raw]);
350 p.bump_any();
351 } else {
352 p.eat(T![mut]);
353 }
354 REF_EXPR
355 }
356 // test unary_expr
357 // fn foo() {
358 // **&1;
359 // !!true;
360 // --1;
361 // }
362 T![*] | T![!] | T![-] => {
363 m = p.start();
364 p.bump_any();
365 PREFIX_EXPR
366 }
367 _ => {
368 // test full_range_expr
369 // fn foo() { xs[..]; }
370 for op in [T![..=], T![..]] {
371 if p.at(op) {
372 m = p.start();
373 p.bump(op);
374 if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
375 expr_bp(p, None, r, 2);
376 }
377 let cm = m.complete(p, RANGE_EXPR);
378 return Some((cm, BlockLike::NotBlock));
379 }
380 }
381
382 // test expression_after_block
383 // fn foo() {
384 // let mut p = F{x: 5};
385 // {p}.x = 10;
386 // }
387 let (lhs, blocklike) = atom::atom_expr(p, r)?;
388 let (cm, block_like) =
389 postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()));
390 return Some((cm, block_like));
391 }
392 };
393 // parse the interior of the unary expression
394 expr_bp(p, None, r, 255);
395 let cm = m.complete(p, kind);
396 Some((cm, BlockLike::NotBlock))
397 }
398
postfix_expr( p: &mut Parser<'_>, mut lhs: CompletedMarker, mut block_like: BlockLike, mut allow_calls: bool, ) -> (CompletedMarker, BlockLike)399 fn postfix_expr(
400 p: &mut Parser<'_>,
401 mut lhs: CompletedMarker,
402 // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple
403 // E.g. `while true {break}();` is parsed as
404 // `while true {break}; ();`
405 mut block_like: BlockLike,
406 mut allow_calls: bool,
407 ) -> (CompletedMarker, BlockLike) {
408 loop {
409 lhs = match p.current() {
410 // test stmt_postfix_expr_ambiguity
411 // fn foo() {
412 // match () {
413 // _ => {}
414 // () => {}
415 // [] => {}
416 // }
417 // }
418 T!['('] if allow_calls => call_expr(p, lhs),
419 T!['['] if allow_calls => index_expr(p, lhs),
420 T![.] => match postfix_dot_expr::<false>(p, lhs) {
421 Ok(it) => it,
422 Err(it) => {
423 lhs = it;
424 break;
425 }
426 },
427 T![?] => try_expr(p, lhs),
428 _ => break,
429 };
430 allow_calls = true;
431 block_like = BlockLike::NotBlock;
432 }
433 (lhs, block_like)
434 }
435
postfix_dot_expr<const FLOAT_RECOVERY: bool>( p: &mut Parser<'_>, lhs: CompletedMarker, ) -> Result<CompletedMarker, CompletedMarker>436 fn postfix_dot_expr<const FLOAT_RECOVERY: bool>(
437 p: &mut Parser<'_>,
438 lhs: CompletedMarker,
439 ) -> Result<CompletedMarker, CompletedMarker> {
440 if !FLOAT_RECOVERY {
441 assert!(p.at(T![.]));
442 }
443 let nth1 = if FLOAT_RECOVERY { 0 } else { 1 };
444 let nth2 = if FLOAT_RECOVERY { 1 } else { 2 };
445
446 if p.nth(nth1) == IDENT && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::])) {
447 return Ok(method_call_expr::<FLOAT_RECOVERY>(p, lhs));
448 }
449
450 // test await_expr
451 // fn foo() {
452 // x.await;
453 // x.0.await;
454 // x.0().await?.hello();
455 // x.0.0.await;
456 // x.0. await;
457 // }
458 if p.nth(nth1) == T![await] {
459 let m = lhs.precede(p);
460 if !FLOAT_RECOVERY {
461 p.bump(T![.]);
462 }
463 p.bump(T![await]);
464 return Ok(m.complete(p, AWAIT_EXPR));
465 }
466
467 if p.at(T![..=]) || p.at(T![..]) {
468 return Err(lhs);
469 }
470
471 field_expr::<FLOAT_RECOVERY>(p, lhs)
472 }
473
474 // test call_expr
475 // fn foo() {
476 // let _ = f();
477 // let _ = f()(1)(1, 2,);
478 // let _ = f(<Foo>::func());
479 // f(<Foo as Trait>::func());
480 // }
call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker481 fn call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
482 assert!(p.at(T!['(']));
483 let m = lhs.precede(p);
484 arg_list(p);
485 m.complete(p, CALL_EXPR)
486 }
487
488 // test index_expr
489 // fn foo() {
490 // x[1][2];
491 // }
index_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker492 fn index_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
493 assert!(p.at(T!['[']));
494 let m = lhs.precede(p);
495 p.bump(T!['[']);
496 expr(p);
497 p.expect(T![']']);
498 m.complete(p, INDEX_EXPR)
499 }
500
501 // test method_call_expr
502 // fn foo() {
503 // x.foo();
504 // y.bar::<T>(1, 2,);
505 // x.0.0.call();
506 // x.0. call();
507 // }
method_call_expr<const FLOAT_RECOVERY: bool>( p: &mut Parser<'_>, lhs: CompletedMarker, ) -> CompletedMarker508 fn method_call_expr<const FLOAT_RECOVERY: bool>(
509 p: &mut Parser<'_>,
510 lhs: CompletedMarker,
511 ) -> CompletedMarker {
512 if FLOAT_RECOVERY {
513 assert!(p.nth(0) == IDENT && (p.nth(1) == T!['('] || p.nth_at(1, T![::])));
514 } else {
515 assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])));
516 }
517 let m = lhs.precede(p);
518 if !FLOAT_RECOVERY {
519 p.bump(T![.]);
520 }
521 name_ref(p);
522 generic_args::opt_generic_arg_list(p, true);
523 if p.at(T!['(']) {
524 arg_list(p);
525 }
526 m.complete(p, METHOD_CALL_EXPR)
527 }
528
529 // test field_expr
530 // fn foo() {
531 // x.foo;
532 // x.0.bar;
533 // x.0.1;
534 // x.0. bar;
535 // x.0();
536 // }
field_expr<const FLOAT_RECOVERY: bool>( p: &mut Parser<'_>, lhs: CompletedMarker, ) -> Result<CompletedMarker, CompletedMarker>537 fn field_expr<const FLOAT_RECOVERY: bool>(
538 p: &mut Parser<'_>,
539 lhs: CompletedMarker,
540 ) -> Result<CompletedMarker, CompletedMarker> {
541 if !FLOAT_RECOVERY {
542 assert!(p.at(T![.]));
543 }
544 let m = lhs.precede(p);
545 if !FLOAT_RECOVERY {
546 p.bump(T![.]);
547 }
548 if p.at(IDENT) || p.at(INT_NUMBER) {
549 name_ref_or_index(p);
550 } else if p.at(FLOAT_NUMBER) {
551 return match p.split_float(m) {
552 (true, m) => {
553 let lhs = m.complete(p, FIELD_EXPR);
554 postfix_dot_expr::<true>(p, lhs)
555 }
556 (false, m) => Ok(m.complete(p, FIELD_EXPR)),
557 };
558 } else {
559 p.error("expected field name or number");
560 }
561 Ok(m.complete(p, FIELD_EXPR))
562 }
563
564 // test try_expr
565 // fn foo() {
566 // x?;
567 // }
try_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker568 fn try_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
569 assert!(p.at(T![?]));
570 let m = lhs.precede(p);
571 p.bump(T![?]);
572 m.complete(p, TRY_EXPR)
573 }
574
575 // test cast_expr
576 // fn foo() {
577 // 82 as i32;
578 // 81 as i8 + 1;
579 // 79 as i16 - 1;
580 // 0x36 as u8 <= 0x37;
581 // }
cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker582 fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
583 assert!(p.at(T![as]));
584 let m = lhs.precede(p);
585 p.bump(T![as]);
586 // Use type_no_bounds(), because cast expressions are not
587 // allowed to have bounds.
588 types::type_no_bounds(p);
589 m.complete(p, CAST_EXPR)
590 }
591
592 // test_err arg_list_recovery
593 // fn main() {
594 // foo(bar::);
595 // foo(bar:);
596 // foo(bar+);
597 // }
arg_list(p: &mut Parser<'_>)598 fn arg_list(p: &mut Parser<'_>) {
599 assert!(p.at(T!['(']));
600 let m = p.start();
601 // test arg_with_attr
602 // fn main() {
603 // foo(#[attr] 92)
604 // }
605 delimited(
606 p,
607 T!['('],
608 T![')'],
609 T![,],
610 EXPR_FIRST.union(ATTRIBUTE_FIRST),
611 |p: &mut Parser<'_>| expr(p).is_some(),
612 );
613 m.complete(p, ARG_LIST);
614 }
615
616 // test path_expr
617 // fn foo() {
618 // let _ = a;
619 // let _ = a::b;
620 // let _ = ::a::<b>;
621 // let _ = format!();
622 // }
path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike)623 fn path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike) {
624 assert!(paths::is_path_start(p));
625 let m = p.start();
626 paths::expr_path(p);
627 match p.current() {
628 T!['{'] if !r.forbid_structs => {
629 record_expr_field_list(p);
630 (m.complete(p, RECORD_EXPR), BlockLike::NotBlock)
631 }
632 T![!] if !p.at(T![!=]) => {
633 let block_like = items::macro_call_after_excl(p);
634 (m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_EXPR), block_like)
635 }
636 _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
637 }
638 }
639
640 // test record_lit
641 // fn foo() {
642 // S {};
643 // S { x };
644 // S { x, y: 32, };
645 // S { x, y: 32, ..Default::default() };
646 // S { x: ::default() };
647 // TupleStruct { 0: 1 };
648 // }
record_expr_field_list(p: &mut Parser<'_>)649 pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
650 assert!(p.at(T!['{']));
651 let m = p.start();
652 p.bump(T!['{']);
653 while !p.at(EOF) && !p.at(T!['}']) {
654 let m = p.start();
655 // test record_literal_field_with_attr
656 // fn main() {
657 // S { #[cfg(test)] field: 1 }
658 // }
659 attributes::outer_attrs(p);
660
661 match p.current() {
662 IDENT | INT_NUMBER => {
663 // test_err record_literal_missing_ellipsis_recovery
664 // fn main() {
665 // S { S::default() }
666 // }
667 if p.nth_at(1, T![::]) {
668 m.abandon(p);
669 p.expect(T![..]);
670 expr(p);
671 } else {
672 // test_err record_literal_before_ellipsis_recovery
673 // fn main() {
674 // S { field ..S::default() }
675 // }
676 if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
677 name_ref_or_index(p);
678 p.expect(T![:]);
679 }
680 expr(p);
681 m.complete(p, RECORD_EXPR_FIELD);
682 }
683 }
684 T![.] if p.at(T![..]) => {
685 m.abandon(p);
686 p.bump(T![..]);
687
688 // test destructuring_assignment_struct_rest_pattern
689 // fn foo() {
690 // S { .. } = S {};
691 // }
692
693 // We permit `.. }` on the left-hand side of a destructuring assignment.
694 if !p.at(T!['}']) {
695 expr(p);
696 }
697 }
698 T!['{'] => {
699 error_block(p, "expected a field");
700 m.abandon(p);
701 }
702 _ => {
703 p.err_and_bump("expected identifier");
704 m.abandon(p);
705 }
706 }
707 if !p.at(T!['}']) {
708 p.expect(T![,]);
709 }
710 }
711 p.expect(T!['}']);
712 m.complete(p, RECORD_EXPR_FIELD_LIST);
713 }
714