1use core::mem;
4use core::ops::{Bound, ControlFlow};
5
6use ast::mut_visit::{self, MutVisitor};
7use ast::token::IdentKind;
8use ast::{ForLoopKind, MatchKind, Pat, Path, PathSegment, Recovered};
9use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind};
10use rustc_ast::util::case::Case;
11use rustc_ast::util::classify;
12use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
13use rustc_ast::visit::{Visitor, walk_expr};
14use rustc_ast::{
15 self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
16 BlockCheckMode, CaptureBy, ClosureBinder, CoroutineKind, DUMMY_NODE_ID, Expr, ExprField,
17 ExprKind, FnDecl, FnRetTy, ForLoop, Guard, Label, MacCall, MetaItemLit, Movability, Param,
18 RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
19};
20use rustc_ast_pretty::pprust;
21use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
22use rustc_lint_defs::builtin::BREAK_WITH_LABEL_AND_LOOP;
23use rustc_literal_escaper::unescape_char;
24use rustc_session::diagnostics::report_lit_error;
25use rustc_span::edition::Edition;
26use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Spanned, Symbol, kw, respan, sym};
27use thin_vec::{ThinVec, thin_vec};
28use tracing::instrument;
29
30use super::diagnostics::SnapshotParser;
31use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
32use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
33use super::{
34 AttrWrapper, BlockMode, ClosureSpans, ExpTokenPair, ForceCollect, Parser, PathStyle,
35 Restrictions, SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,
36};
37use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
38
39mod diagnostics;
40
41#[derive(#[automatically_derived]
impl ::core::fmt::Debug for DestructuredFloat {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
DestructuredFloat::Single(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f, "Single",
__self_0, &__self_1),
DestructuredFloat::TrailingDot(__self_0, __self_1, __self_2) =>
::core::fmt::Formatter::debug_tuple_field3_finish(f,
"TrailingDot", __self_0, __self_1, &__self_2),
DestructuredFloat::MiddleDot(__self_0, __self_1, __self_2,
__self_3, __self_4) =>
::core::fmt::Formatter::debug_tuple_field5_finish(f,
"MiddleDot", __self_0, __self_1, __self_2, __self_3,
&__self_4),
DestructuredFloat::Error =>
::core::fmt::Formatter::write_str(f, "Error"),
}
}
}Debug)]
42pub(super) enum DestructuredFloat {
43 Single(Symbol, Span),
45 TrailingDot(Symbol, Span, Span),
47 MiddleDot(Symbol, Span, Span, Symbol, Span),
49 Error,
51}
52
53impl<'a> Parser<'a> {
54 #[inline]
56 pub fn parse_expr(&mut self) -> PResult<'a, Box<Expr>> {
57 self.current_closure.take();
58 self.parse_expr_res(Restrictions::empty())
59 }
60
61 pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box<Expr>> {
63 self.current_closure.take();
64
65 let pre_attr_pos = self.collect_pos();
70 let attrs = self.parse_outer_attributes()?;
71 self.collect_tokens(
72 Some(pre_attr_pos),
73 AttrWrapper::empty(),
74 ForceCollect::Yes,
75 |this, _empty_attrs| {
76 let (expr, is_assoc) =
77 this.parse_expr_res_after_attrs(Restrictions::empty(), attrs)?;
78 let use_pre_attr_pos =
79 if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };
80 Ok((expr, Trailing::No, use_pre_attr_pos))
81 },
82 )
83 }
84
85 pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
86 self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })
87 }
88
89 fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<Box<Expr>>> {
91 self.parse_paren_comma_seq(Self::parse_expr).map(|(r, _)| r)
92 }
93
94 #[inline]
96 pub(super) fn parse_expr_res(&mut self, r: Restrictions) -> PResult<'a, Box<Expr>> {
97 let attrs = self.parse_outer_attributes()?;
98 self.parse_expr_res_after_attrs(r, attrs).map(|(expr, _)| expr)
99 }
100
101 #[inline]
105 pub(super) fn parse_expr_res_after_attrs(
106 &mut self,
107 r: Restrictions,
108 attrs: AttrWrapper,
109 ) -> PResult<'a, (Box<Expr>, bool)> {
110 self.with_res(r, |this| this.parse_expr_assoc_after_attrs(Bound::Unbounded, attrs))
111 }
112
113 pub(super) fn parse_expr_assoc(
115 &mut self,
116 min_prec: Bound<ExprPrecedence>,
117 ) -> PResult<'a, Box<Expr>> {
118 let attrs = self.parse_outer_attributes()?;
119 self.parse_expr_assoc_after_attrs(min_prec, attrs).map(|(expr, _)| expr)
120 }
121
122 pub(super) fn parse_expr_assoc_after_attrs(
126 &mut self,
127 min_prec: Bound<ExprPrecedence>,
128 attrs: AttrWrapper,
129 ) -> PResult<'a, (Box<Expr>, bool)> {
130 let lhs = if self.token.is_range_separator() {
131 return self.parse_expr_prefix_range(attrs).map(|res| (res, false));
132 } else {
133 self.parse_expr_prefix(attrs)?
134 };
135 self.parse_expr_assoc_rest(min_prec, false, lhs)
136 }
137
138 pub(super) fn parse_expr_assoc_rest(
142 &mut self,
143 min_prec: Bound<ExprPrecedence>,
144 starts_stmt: bool,
145 mut lhs: Box<Expr>,
146 ) -> PResult<'a, (Box<Expr>, bool)> {
147 let mut parsed_something = false;
148 if !self.should_continue_as_assoc_expr(&lhs) {
149 return Ok((lhs, parsed_something));
150 }
151
152 self.expected_token_types.insert(TokenType::Operator);
153 while let Some(op) = self.check_assoc_op() {
154 let lhs_span = self.interpolated_or_expr_span(&lhs);
155 let restrictions = if op.node.is_assign_like() {
156 self.restrictions & Restrictions::NO_STRUCT_LITERAL
157 } else {
158 self.restrictions
159 };
160 let prec = op.node.precedence();
161 if match min_prec {
162 Bound::Included(min_prec) => prec < min_prec,
163 Bound::Excluded(min_prec) => prec <= min_prec,
164 Bound::Unbounded => false,
165 } {
166 break;
167 }
168
169 self.reject_dotdotdot_expr_op();
170 self.reject_larrow_expr_op();
171
172 parsed_something = true;
173 self.bump();
174
175 if op.node.is_comparison()
176 && let Some(expr) = self.check_no_chained_comparison(&lhs, &op)?
177 {
178 return Ok((expr, parsed_something));
179 }
180
181 self.recover_from_strict_eq_op(op);
182 self.recover_from_diamond_ne_op();
183 self.recover_from_spaceship_cmp_op();
184 self.recover_from_postfix_inc_op(&lhs, starts_stmt)?;
185 self.recover_from_postfix_dec_op(&lhs, starts_stmt)?;
186
187 let min_prec = match op.node.fixity() {
188 Fixity::Right => Bound::Included(prec),
189 Fixity::Left | Fixity::None => Bound::Excluded(prec),
190 };
191
192 let finish_parsing_bin_op = |this: &mut Self| {
193 let rhs = this.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
194 this.parse_expr_assoc(min_prec)
195 })?;
196 let span = this.mk_expr_sp(&lhs, lhs_span, op.span, rhs.span);
197 Ok((rhs, span))
198 };
199
200 lhs = match op.node {
201 AssocOp::Binary(ast_op) => {
202 let (rhs, span) = finish_parsing_bin_op(self)?;
203 self.mk_expr(span, self.mk_binary(respan(op.span, ast_op), lhs, rhs))
204 }
205 AssocOp::AssignOp(aop) => {
206 let (rhs, span) = finish_parsing_bin_op(self)?;
207 self.mk_expr(span, self.mk_assign_op(respan(op.span, aop), lhs, rhs))
208 }
209 AssocOp::Assign => {
210 let (rhs, span) = finish_parsing_bin_op(self)?;
211 self.mk_expr(span, ExprKind::Assign(lhs, rhs, op.span))
212 }
213 AssocOp::Cast => self.parse_assoc_op_cast(lhs, lhs_span, op.span)?,
214 AssocOp::Range(limits) => self.parse_expr_range(min_prec, lhs, limits, op.span)?,
215 };
216
217 if let AssocOp::Range(_) = op.node {
218 break;
219 }
220 }
221
222 Ok((lhs, parsed_something))
223 }
224
225 fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
226 match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) {
227 (true, None) => false,
230 (false, _) => true, (true, Some(AssocOp::Binary(
235 BinOpKind::Mul | BinOpKind::Sub | BinOpKind::Add | BinOpKind::And | BinOpKind::Or | BinOpKind::BitOr ))) => {
242 let sp = self.psess.source_map().start_point(self.token.span);
249 self.psess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
250 false
251 }
252 (true, Some(op)) if !op.can_continue_expr_unambiguously() => false,
253 (true, Some(_)) => {
254 self.error_found_expr_would_be_stmt(lhs);
255 true
256 }
257 }
258 }
259
260 fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
264 self.dcx().emit_err(crate::diagnostics::FoundExprWouldBeStmt {
265 span: self.token.span,
266 token: pprust::token_to_string(&self.token),
267 suggestion: crate::diagnostics::ExprParenthesesNeeded::surrounding(lhs.span),
268 });
269 }
270
271 pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
274 let op = AssocOp::from_token(&self.token);
275
276 if self.restrictions.contains(Restrictions::CONST_EXPR)
278 && let Some(op) = op
279 && let AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
280 | AssocOp::AssignOp(AssignOpKind::ShrAssign) = op
281 {
282 return None;
283 }
284
285 if self.restrictions.contains(Restrictions::IS_PAT)
288 && let Some(op) = op
289 && let AssocOp::Assign
290 | AssocOp::AssignOp(_)
291 | AssocOp::Binary(BinOpKind::BitOr)
292 | AssocOp::Range(_) = op
293 {
294 return None;
295 }
296
297 if let Some(op) = op {
298 return Some(respan(self.token.span, op));
299 }
300
301 self.recover_from_alpha_logic_op()
302 }
303
304 fn expr_is_complete(&self, e: &Expr) -> bool {
306 self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)
307 }
308
309 fn parse_expr_range(
312 &mut self,
313 min_prec: Bound<ExprPrecedence>,
314 lhs: Box<Expr>,
315 limits: RangeLimits,
316 cur_op_span: Span,
317 ) -> PResult<'a, Box<Expr>> {
318 let rhs = if self.is_at_start_of_range_notation_rhs() {
319 let maybe_lt = self.token;
320 Some(
321 self.parse_expr_assoc(min_prec)
322 .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,
323 )
324 } else {
325 None
326 };
327 let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
328 let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span);
329 let range = self.mk_range(Some(lhs), rhs, limits);
330 Ok(self.mk_expr(span, range))
331 }
332
333 fn is_at_start_of_range_notation_rhs(&self) -> bool {
334 if self.token.can_begin_expr() {
335 if self.token == token::OpenBrace {
337 return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
338 }
339 true
340 } else {
341 false
342 }
343 }
344
345 fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
347 if !attrs.is_empty() {
348 let err = crate::diagnostics::DotDotRangeAttribute { span: self.token.span };
349 self.dcx().emit_err(err);
350 }
351
352 self.reject_dotdotdot_expr_op();
353
354 if true {
if !self.token.is_range_separator() {
{
::core::panicking::panic_fmt(format_args!("parse_prefix_range_expr: token {0:?} is not DotDot/DotDotEq",
self.token));
}
};
};debug_assert!(
355 self.token.is_range_separator(),
356 "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
357 self.token
358 );
359
360 let limits = match self.token.kind {
361 token::DotDot => RangeLimits::HalfOpen,
362 _ => RangeLimits::Closed,
363 };
364 let op = AssocOp::from_token(&self.token);
365 self.collect_tokens_for_expr(AttrWrapper::empty(), |this, _empty_attrs| {
366 let lo = this.token.span;
367 let maybe_lt = this.look_ahead(1, |t| t.clone());
368 this.bump();
369 let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
370 this.parse_expr_assoc(Bound::Excluded(op.unwrap().precedence()))
372 .map(|expr| (lo.to(expr.span), Some(expr)))
373 .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
374 } else {
375 (lo, None)
376 };
377 let range = this.mk_range(None, opt_end, limits);
378 Ok(this.mk_expr(span, range))
379 })
380 }
381
382 fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
384 let lo = self.token.span;
385
386 macro_rules! make_it {
387 ($this:ident, $attrs:expr, |this, _| $body:expr) => {
388 $this.collect_tokens_for_expr($attrs, |$this, attrs| {
389 let (hi, ex) = $body?;
390 Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
391 })
392 };
393 }
394
395 let this = self;
396
397 match this.token.uninterpolate().kind {
399 token::Bang => this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.parse_expr_unary(lo, UnOp::Not)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)),
401 token::Tilde => this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.recover_tilde_expr(lo)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)),
403 token::Minus => {
405 this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.parse_expr_unary(lo, UnOp::Neg)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Neg))
406 }
407 token::Star => {
409 this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.parse_expr_unary(lo, UnOp::Deref)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Deref))
410 }
411 token::And | token::AndAnd => {
413 this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.parse_expr_borrow(lo)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.parse_expr_borrow(lo))
414 }
415 token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
417 let mut err = crate::diagnostics::LeadingPlusNotSupported {
418 span: lo,
419 remove_plus: None,
420 add_parentheses: None,
421 };
422
423 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
425 err.add_parentheses =
426 Some(crate::diagnostics::ExprParenthesesNeeded::surrounding(*sp));
427 } else {
428 err.remove_plus = Some(lo);
429 }
430 this.dcx().emit_err(err);
431
432 this.bump(); Ok(this.parse_expr_prefix_common(lo)?.1)
434 }
435 token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {
437 let starts_stmt =
438 this.prev_token == token::Semi || this.prev_token == token::CloseBrace;
439 let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
440 this.bump();
442 this.bump();
443
444 let operand = this.parse_expr_dot_or_call(attrs)?;
445 return Err(this.report_inc_dec_op(
446 &operand,
447 starts_stmt,
448 diagnostics::IncOrDec::Inc,
449 diagnostics::UnaryFixity::Pre,
450 pre_span,
451 ));
452 }
453 token::Ident(..)
454 if this.token.is_keyword(kw::Move)
455 && this.look_ahead(1, |t| *t == token::OpenParen) =>
456 {
457 this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.parse_expr_move(lo)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.parse_expr_move(lo))
458 }
459 token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
460 this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.recover_not_expr(lo)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
461 }
462 _ => this.parse_expr_dot_or_call(attrs),
463 }
464 }
465
466 fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> {
467 let attrs = self.parse_outer_attributes()?;
468 let expr = if self.token.is_range_separator() {
469 self.parse_expr_prefix_range(attrs)
470 } else {
471 self.parse_expr_prefix(attrs)
472 }?;
473 let span = self.interpolated_or_expr_span(&expr);
474 Ok((lo.to(span), expr))
475 }
476
477 fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
478 self.bump(); let (span, expr) = self.parse_expr_prefix_common(lo)?;
480 Ok((span, self.mk_unary(op, expr)))
481 }
482
483 fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
485 self.dcx().emit_err(crate::diagnostics::TildeAsUnaryOperator(lo));
486
487 self.parse_expr_unary(lo, UnOp::Not)
488 }
489
490 fn parse_expr_move(&mut self, move_kw: Span) -> PResult<'a, (Span, ExprKind)> {
491 self.bump();
492 self.psess.gated_spans.gate(sym::move_expr, move_kw);
493 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
494 let expr = self.parse_expr()?;
495 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
496 let span = move_kw.to(self.prev_token.span);
497 Ok((span, ExprKind::Move(expr, move_kw)))
498 }
499
500 fn is_mistaken_not_ident_negation(&self) -> bool {
501 let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {
502 token::Ident(name, kind) => token::ident_can_begin_expr(name, t.span, kind),
505 token::Literal(..) | token::Pound => true,
506 _ => t.is_metavar_expr(),
507 };
508 self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)
509 }
510
511 fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
513 let negated_token = self.look_ahead(1, |t| *t);
514
515 let sub_diag = if negated_token.is_numeric_lit() {
516 crate::diagnostics::NotAsNegationOperatorSub::SuggestNotBitwise
517 } else if negated_token.is_bool_lit() {
518 crate::diagnostics::NotAsNegationOperatorSub::SuggestNotLogical
519 } else {
520 crate::diagnostics::NotAsNegationOperatorSub::SuggestNotDefault
521 };
522
523 self.dcx().emit_err(crate::diagnostics::NotAsNegationOperator {
524 negated: negated_token.span,
525 negated_desc: super::token_descr(&negated_token),
526 sub: sub_diag(
529 self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
530 ),
531 });
532
533 self.parse_expr_unary(lo, UnOp::Not)
534 }
535
536 fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
538 match self.prev_token.kind {
539 token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,
540 token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {
541 self.prev_token.span
546 }
547 _ => expr.span,
548 }
549 }
550
551 fn parse_assoc_op_cast(
552 &mut self,
553 lhs: Box<Expr>,
554 lhs_span: Span,
555 op_span: Span,
556 ) -> PResult<'a, Box<Expr>> {
557 let mk_expr = |this: &mut Self, rhs: Box<Ty>| {
558 let span = this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);
559 this.mk_expr(span, ExprKind::Cast(lhs, rhs))
560 };
561
562 let parser_snapshot_before_type = self.clone();
565 let cast_expr = match self.parse_as_cast_ty() {
566 Ok(rhs) => mk_expr(self, rhs),
567 Err(type_err) => {
568 if !self.may_recover() {
569 return Err(type_err);
570 }
571
572 let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
576
577 match self.parse_path(PathStyle::Expr) {
578 Ok(path) => {
579 let span_after_type = parser_snapshot_after_type.token.span;
580 let expr =
581 mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path.clone())));
582
583 let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
584 match self.token.kind {
585 token::Lt => self.dcx().emit_err(
586 crate::diagnostics::ComparisonInterpretedAsGeneric {
587 comparison: self.token.span,
588 r#type: pprust::path_to_string(&path),
589 args: args_span,
590 suggestion:
591 crate::diagnostics::ComparisonInterpretedAsGenericSugg {
592 left: expr.span.shrink_to_lo(),
593 right: expr.span.shrink_to_hi(),
594 },
595 },
596 ),
597 token::Shl => {
598 self.dcx().emit_err(crate::diagnostics::ShiftInterpretedAsGeneric {
599 shift: self.token.span,
600 r#type: pprust::path_to_string(&path),
601 args: args_span,
602 suggestion: crate::diagnostics::ShiftInterpretedAsGenericSugg {
603 left: expr.span.shrink_to_lo(),
604 right: expr.span.shrink_to_hi(),
605 },
606 })
607 }
608 _ => {
609 *self = parser_snapshot_after_type;
614 return Err(type_err);
615 }
616 };
617
618 type_err.cancel();
620
621 expr
623 }
624 Err(path_err) => {
625 path_err.cancel();
627 *self = parser_snapshot_after_type;
628 return Err(type_err);
629 }
630 }
631 }
632 };
633
634 let span = cast_expr.span;
640 let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
641
642 if !#[allow(non_exhaustive_omitted_patterns)] match with_postfix.kind {
ExprKind::Cast(_, _) => true,
_ => false,
}matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
645 let kind = match with_postfix.kind {
646 ExprKind::Index(..) => "indexing",
647 ExprKind::Try(_) => "`?`",
648 ExprKind::Field(_, _) => "a field access",
649 ExprKind::MethodCall(_) => "a method call",
650 ExprKind::Call(_, _) => "a function call",
651 ExprKind::Await(_, _) => "`.await`",
652 ExprKind::Use(_, _) => "`.use`",
653 ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
654 ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
655 ExprKind::Err(_) => return Ok(with_postfix),
656 _ => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("did not expect {0:?} as an illegal postfix operator following cast",
with_postfix.kind)));
}unreachable!(
657 "did not expect {:?} as an illegal postfix operator following cast",
658 with_postfix.kind
659 ),
660 };
661 self.dcx()
662 .struct_span_err(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cast cannot be followed by {0}",
kind))
})format!("cast cannot be followed by {kind}"))
663 .with_multipart_suggestion(
664 "try surrounding the expression in parentheses",
665 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span.shrink_to_lo(), "(".to_string()),
(span.shrink_to_hi(), ")".to_string())]))vec![
666 (span.shrink_to_lo(), "(".to_string()),
667 (span.shrink_to_hi(), ")".to_string()),
668 ],
669 Applicability::MachineApplicable,
670 )
671 .emit();
672 };
673 Ok(with_postfix)
674 }
675
676 fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
678 self.expect_and()?;
679 let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
680 let lifetime = has_lifetime.then(|| self.expect_lifetime()); let (borrow_kind, mutbl) = self.parse_borrow_modifiers();
682 let (span, expr) = self.parse_expr_prefix_common(lo)?;
683 if let Some(lt) = lifetime {
684 self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
685 }
686
687 if borrow_kind == ast::BorrowKind::Ref
691 && mutbl == ast::Mutability::Not
692 && #[allow(non_exhaustive_omitted_patterns)] match &expr.kind {
ExprKind::Path(None, p) if *p == kw::Raw => true,
_ => false,
}matches!(&expr.kind, ExprKind::Path(None, p) if *p == kw::Raw)
693 {
694 self.expected_token_types.insert(TokenType::KwMut);
695 self.expected_token_types.insert(TokenType::KwConst);
696 }
697
698 Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
699 }
700
701 fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
702 self.dcx().emit_err(crate::diagnostics::LifetimeInBorrowExpression {
703 span,
704 lifetime_span: lt_span,
705 });
706 }
707
708 fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
710 if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Raw,
token_type: crate::parser::token_type::TokenType::KwRaw,
}exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
711 let found_raw = self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Raw,
token_type: crate::parser::token_type::TokenType::KwRaw,
}exp!(Raw));
713 if !found_raw { ::core::panicking::panic("assertion failed: found_raw") };assert!(found_raw);
714 let mutability = self.parse_mut_or_const().unwrap();
715 (ast::BorrowKind::Raw, mutability)
716 } else {
717 match self.parse_pin_and_mut() {
718 (ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),
720 (ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),
724 }
725 }
726 }
727
728 fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
730 self.collect_tokens_for_expr(attrs, |this, attrs| {
731 let base = this.parse_expr_bottom()?;
732 let span = this.interpolated_or_expr_span(&base);
733 this.parse_expr_dot_or_call_with(attrs, base, span)
734 })
735 }
736
737 pub(super) fn parse_expr_dot_or_call_with(
738 &mut self,
739 mut attrs: ast::AttrVec,
740 mut e: Box<Expr>,
741 lo: Span,
742 ) -> PResult<'a, Box<Expr>> {
743 let mut res = loop {
744 let has_question = if self.prev_token == TokenKind::Ident(kw::Return, IdentKind::Normal)
745 {
746 self.eat_noexpect(&token::Question)
749 } else {
750 self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Question,
token_type: crate::parser::token_type::TokenType::Question,
}exp!(Question))
751 };
752 if has_question {
753 e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
755 continue;
756 }
757 let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentKind::Normal) {
758 self.eat_noexpect(&token::Dot)
761 } else if self.token == TokenKind::RArrow && self.may_recover() {
762 self.bump();
764 let span = self.prev_token.span;
765 self.dcx().emit_err(crate::diagnostics::ExprRArrowCall { span });
766 true
767 } else {
768 self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Dot,
token_type: crate::parser::token_type::TokenType::Dot,
}exp!(Dot))
769 };
770 if has_dot {
771 e = self.parse_dot_suffix_expr(lo, e)?;
773 continue;
774 }
775 if self.expr_is_complete(&e) {
776 break Ok(e);
777 }
778 e = match self.token.kind {
779 token::OpenParen => self.parse_expr_fn_call(lo, e),
780 token::OpenBracket => self.parse_expr_index(lo, e)?,
781 _ => break Ok(e),
782 }
783 };
784
785 if !attrs.is_empty()
788 && let Ok(expr) = &mut res
789 {
790 mem::swap(&mut expr.attrs, &mut attrs);
791 expr.attrs.extend(attrs)
792 }
793 res
794 }
795
796 pub(super) fn parse_dot_suffix_expr(
797 &mut self,
798 lo: Span,
799 base: Box<Expr>,
800 ) -> PResult<'a, Box<Expr>> {
801 match self.token.uninterpolate().kind {
804 token::Ident(..) => self.parse_dot_suffix(base, lo),
805 token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
806 let ident_span = self.token.span;
807 self.bump();
808 Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))
809 }
810 token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {
811 Ok(match self.break_up_float(symbol, self.token.span) {
812 DestructuredFloat::Single(sym, _sp) => {
814 let ident_span = self.token.span;
818 self.bump();
819 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)
820 }
821 DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
823 if !suffix.is_none() {
::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
827 self.token = Token::new(token::Ident(sym, IdentKind::Normal), ident_span);
828 self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
829 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)
830 }
831 DestructuredFloat::MiddleDot(
833 sym1,
834 ident1_span,
835 _dot_span,
836 sym2,
837 ident2_span,
838 ) => {
839 let next_token2 =
843 Token::new(token::Ident(sym2, IdentKind::Normal), ident2_span);
844 self.bump_with((next_token2, self.token_spacing));
845 self.bump();
846 let base1 =
847 self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
848 self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
849 }
850 DestructuredFloat::Error => base,
851 })
852 }
853 _ => {
854 self.error_unexpected_after_dot();
855 Ok(base)
856 }
857 }
858 }
859
860 fn error_unexpected_after_dot(&self) {
861 let actual = super::token_descr(&self.token);
862 let span = self.token.span;
863 let sm = self.psess.source_map();
864 let (span, actual) = match (&self.token.kind, self.subparser_name) {
865 (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {
866 (span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", snippet))
})format!("`{}`", snippet))
867 }
868 (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {
869 self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");
884 return;
885 }
886 _ => (span, actual),
887 };
888 self.dcx().emit_err(crate::diagnostics::UnexpectedTokenAfterDot { span, actual });
889 }
890
891 pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
902 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for FloatComponent {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
FloatComponent::IdentLike(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"IdentLike", &__self_0),
FloatComponent::Punct(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Punct",
&__self_0),
}
}
}Debug)]
903 enum FloatComponent {
904 IdentLike(String),
905 Punct(char),
906 }
907 use FloatComponent::*;
908
909 let float_str = float.as_str();
910 let mut components = Vec::new();
911 let mut ident_like = String::new();
912 for c in float_str.chars() {
913 if c == '_' || c.is_ascii_alphanumeric() {
914 ident_like.push(c);
915 } else if #[allow(non_exhaustive_omitted_patterns)] match c {
'.' | '+' | '-' => true,
_ => false,
}matches!(c, '.' | '+' | '-') {
916 if !ident_like.is_empty() {
917 components.push(IdentLike(mem::take(&mut ident_like)));
918 }
919 components.push(Punct(c));
920 } else {
921 {
::core::panicking::panic_fmt(format_args!("unexpected character in a float token: {0:?}",
c));
}panic!("unexpected character in a float token: {c:?}")
922 }
923 }
924 if !ident_like.is_empty() {
925 components.push(IdentLike(ident_like));
926 }
927
928 let can_take_span_apart =
932 || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
933
934 match &*components {
935 [IdentLike(i)] => DestructuredFloat::Single(Symbol::intern(i), span),
937 [IdentLike(left), Punct('.')] => {
939 let (left_span, dot_span) = if can_take_span_apart() {
940 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
941 let dot_span = span.with_lo(left_span.hi());
942 (left_span, dot_span)
943 } else {
944 (span, span)
945 };
946 let left = Symbol::intern(left);
947 DestructuredFloat::TrailingDot(left, left_span, dot_span)
948 }
949 [IdentLike(left), Punct('.'), IdentLike(right)] => {
951 let (left_span, dot_span, right_span) = if can_take_span_apart() {
952 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
953 let dot_span =
954 span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));
955 let right_span = span.with_lo(dot_span.hi());
956 (left_span, dot_span, right_span)
957 } else {
958 (span, span, span)
959 };
960 let left = Symbol::intern(left);
961 let right = Symbol::intern(right);
962 DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)
963 }
964 [IdentLike(_), Punct('+' | '-')] |
966 [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |
968 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |
970 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
972 self.error_unexpected_after_dot();
974 DestructuredFloat::Error
975 }
976 _ => {
::core::panicking::panic_fmt(format_args!("unexpected components in a float token: {0:?}",
components));
}panic!("unexpected components in a float token: {components:?}"),
977 }
978 }
979
980 pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, ThinVec<Ident>> {
984 let mut fields = ThinVec::new();
985 let mut trailing_dot = None;
986
987 loop {
988 let expr = self.parse_expr()?;
992 let mut current = &expr;
993 let start_idx = fields.len();
994 loop {
995 match current.kind {
996 ExprKind::Field(ref left, right) => {
997 fields.insert(start_idx, right);
999 trailing_dot = None;
1000 current = left;
1001 }
1002 ExprKind::Index(ref left, ref _right, span) => {
1005 self.dcx().emit_err(crate::diagnostics::ArrayIndexInOffsetOf(span));
1006 current = left;
1007 }
1008 ExprKind::Lit(token::Lit {
1009 kind: token::Float | token::Integer,
1010 symbol,
1011 suffix,
1012 }) => {
1013 if let Some(suffix) = suffix {
1014 self.dcx().emit_err(
1015 crate::diagnostics::InvalidLiteralSuffixOnTupleIndex {
1016 span: current.span,
1017 suffix,
1018 },
1019 );
1020 }
1021 match self.break_up_float(symbol, current.span) {
1022 DestructuredFloat::Single(sym, sp) => {
1024 trailing_dot = None;
1025 fields.insert(start_idx, Ident::new(sym, sp));
1026 }
1027 DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
1029 if !suffix.is_none() {
::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
1030 trailing_dot = Some(dot_span);
1031 fields.insert(start_idx, Ident::new(sym, sym_span));
1032 }
1033 DestructuredFloat::MiddleDot(
1035 symbol1,
1036 span1,
1037 _dot_span,
1038 symbol2,
1039 span2,
1040 ) => {
1041 trailing_dot = None;
1042 fields.insert(start_idx, Ident::new(symbol2, span2));
1043 fields.insert(start_idx, Ident::new(symbol1, span1));
1044 }
1045 DestructuredFloat::Error => {
1046 trailing_dot = None;
1047 fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
1048 }
1049 }
1050 break;
1051 }
1052 ExprKind::Path(None, Path { ref segments, .. }) => {
1053 match &segments[..] {
1054 [PathSegment { ident, args: None, .. }] => {
1055 trailing_dot = None;
1056 fields.insert(start_idx, *ident)
1057 }
1058 _ => {
1059 self.dcx()
1060 .emit_err(crate::diagnostics::InvalidOffsetOf(current.span));
1061 break;
1062 }
1063 }
1064 break;
1065 }
1066 _ => {
1067 self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(current.span));
1068 break;
1069 }
1070 }
1071 }
1072
1073 if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {
1074 break;
1075 } else if trailing_dot.is_none() {
1076 self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(self.token.span));
1078 break;
1079 }
1080 }
1081 if let Some(dot) = trailing_dot {
1082 self.dcx().emit_err(crate::diagnostics::InvalidOffsetOf(dot));
1083 }
1084 Ok(fields.into_iter().collect())
1085 }
1086
1087 fn mk_expr_tuple_field_access(
1088 &self,
1089 lo: Span,
1090 ident_span: Span,
1091 base: Box<Expr>,
1092 field: Symbol,
1093 suffix: Option<Symbol>,
1094 ) -> Box<Expr> {
1095 if let Some(suffix) = suffix {
1096 self.dcx().emit_err(crate::diagnostics::InvalidLiteralSuffixOnTupleIndex {
1097 span: ident_span,
1098 suffix,
1099 });
1100 }
1101 self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))
1102 }
1103
1104 fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> {
1106 let snapshot = if self.token == token::OpenParen {
1107 Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
1108 } else {
1109 None
1110 };
1111 let open_paren = self.token.span;
1112 let call_depth = self.token_cursor.depth();
1113
1114 let seq = match self.parse_expr_paren_seq() {
1115 Ok(args) => Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))),
1116 Err(err)
1117 if self.is_expected_raw_ref_mut() && self.token_cursor.depth() == call_depth =>
1118 {
1119 let guar = err.emit_err();
1120 let args = self.recover_raw_ref_call_args(guar);
1123 return self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args));
1124 }
1125 Err(err) => Err(err),
1126 };
1127 match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {
1128 Ok(expr) => expr,
1129 Err(err) => self.recover_seq_parse_error(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen), crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen), lo, err),
1130 }
1131 }
1132
1133 fn recover_raw_ref_call_args(&mut self, guar: ErrorGuaranteed) -> ThinVec<Box<Expr>> {
1134 let err_span = self.prev_token.span.to(self.token.span);
1135 let mut args = {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(self.mk_expr_err(err_span, guar));
vec
}thin_vec![self.mk_expr_err(err_span, guar)];
1136 while !self.token.kind.is_close_delim_or_eof() {
1137 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1138 if !self.token.kind.is_close_delim_or_eof() {
1139 args.push(self.mk_expr_err(self.prev_token.span.shrink_to_hi(), guar));
1140 }
1141 } else {
1142 self.parse_token_tree();
1143 }
1144 }
1145 let _ = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen));
1146 args
1147 }
1148
1149 {}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("maybe_recover_struct_lit_bad_delims",
"rustc_parse::parser::expr", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/1303417c416e1595173d9689e7394c31e136ae95/compiler/rustc_parse/src/parser/expr.rs"),
::tracing_core::__macro_support::Option::Some(1151u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::expr"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("lo")
}> =
::tracing::__macro_support::FieldName::new("lo");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("open_paren")
}> =
::tracing::__macro_support::FieldName::new("open_paren");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&lo)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&open_paren)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: PResult<'a, Box<Expr>> = loop {};
return __tracing_attr_fake_return;
}
{
match (self.may_recover(), seq, snapshot) {
(true, Err(err),
Some((mut snapshot, ExprKind::Path(None, path)))) => {
snapshot.bump();
match snapshot.parse_struct_fields(path.clone(), false,
crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}) {
Ok((fields, ..)) if
snapshot.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}) => {
self.restore_snapshot(snapshot);
let close_paren = self.prev_token.span;
let span = lo.to(close_paren);
let fields: Vec<_> =
fields.into_iter().filter(|field|
!field.is_shorthand).collect();
let guar =
if !fields.is_empty() &&
self.span_to_snippet(close_paren).is_ok_and(|snippet|
snippet == ")") {
err.cancel();
let type_str = pprust::path_to_string(&path);
self.dcx().emit_err(crate::diagnostics::ParenthesesWithStructFields {
span,
braces_for_struct: crate::diagnostics::BracesForStructLiteral {
first: open_paren,
second: close_paren,
r#type: type_str.clone(),
},
no_fields_for_fn: crate::diagnostics::NoFieldsForFnCall {
r#type: type_str,
fields: fields.into_iter().map(|field|
field.span.until(field.expr.span)).collect(),
},
})
} else { err.emit_err() };
Ok(self.mk_expr_err(span, guar))
}
Ok(_) => Err(err),
Err(err2) => { err2.cancel(); Err(err) }
}
}
(_, seq, _) => seq,
}
}
}
}#[instrument(skip(self, seq, snapshot), level = "trace")]
1152 fn maybe_recover_struct_lit_bad_delims(
1153 &mut self,
1154 lo: Span,
1155 open_paren: Span,
1156 seq: PResult<'a, Box<Expr>>,
1157 snapshot: Option<(SnapshotParser<'a>, ExprKind)>,
1158 ) -> PResult<'a, Box<Expr>> {
1159 match (self.may_recover(), seq, snapshot) {
1160 (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
1161 snapshot.bump(); match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {
1163 Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {
1164 self.restore_snapshot(snapshot);
1167 let close_paren = self.prev_token.span;
1168 let span = lo.to(close_paren);
1169 let fields: Vec<_> =
1171 fields.into_iter().filter(|field| !field.is_shorthand).collect();
1172
1173 let guar = if !fields.is_empty() &&
1174 self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")
1179 {
1180 err.cancel();
1181 let type_str = pprust::path_to_string(&path);
1182 self.dcx().emit_err(crate::diagnostics::ParenthesesWithStructFields {
1183 span,
1184 braces_for_struct: crate::diagnostics::BracesForStructLiteral {
1185 first: open_paren,
1186 second: close_paren,
1187 r#type: type_str.clone(),
1188 },
1189 no_fields_for_fn: crate::diagnostics::NoFieldsForFnCall {
1190 r#type: type_str,
1191 fields: fields
1192 .into_iter()
1193 .map(|field| field.span.until(field.expr.span))
1194 .collect(),
1195 },
1196 })
1197 } else {
1198 err.emit_err()
1199 };
1200 Ok(self.mk_expr_err(span, guar))
1201 }
1202 Ok(_) => Err(err),
1203 Err(err2) => {
1204 err2.cancel();
1205 Err(err)
1206 }
1207 }
1208 }
1209 (_, seq, _) => seq,
1210 }
1211 }
1212
1213 fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> {
1215 let prev_token = self.prev_token;
1216 let open_delim_span = self.token.span;
1217 self.bump(); let index = self.parse_expr()?;
1219 self.suggest_missing_semicolon_before_array(prev_token.span, open_delim_span)?;
1220 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBracket,
token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket)).map_err(|mut err| {
1221 if prev_token.is_non_reserved_ident() {
1222 err.span_suggestion_verbose(
1223 prev_token.span.shrink_to_hi(),
1224 "you might have meant to call a macro",
1225 "!".to_string(),
1226 Applicability::MaybeIncorrect,
1227 );
1228 }
1229 err
1230 })?;
1231 Ok(self.mk_expr(
1232 lo.to(self.prev_token.span),
1233 self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),
1234 ))
1235 }
1236
1237 fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> {
1239 if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Await,
token_type: crate::parser::token_type::TokenType::KwAwait,
}exp!(Await)) {
1240 return Ok(self.mk_await_expr(self_arg, lo));
1241 }
1242
1243 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Use,
token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use)) {
1244 let use_span = self.prev_token.span;
1245 self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
1246 return Ok(self.mk_use_expr(self_arg, lo));
1247 }
1248
1249 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Match,
token_type: crate::parser::token_type::TokenType::KwMatch,
}exp!(Match)) {
1251 let match_span = self.prev_token.span;
1252 self.psess.gated_spans.gate(sym::postfix_match, match_span);
1253 return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
1254 }
1255
1256 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Yield,
token_type: crate::parser::token_type::TokenType::KwYield,
}exp!(Yield)) {
1258 let yield_span = self.prev_token.span;
1259 self.psess.gated_spans.gate(sym::yield_expr, yield_span);
1260 return Ok(
1261 self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))
1262 );
1263 }
1264
1265 let fn_span_lo = self.token.span;
1266 let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
1267 self.check_trailing_angle_brackets(&seg, &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)]);
1268 self.check_turbofish_missing_angle_brackets(&mut seg);
1269
1270 if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1271 let args = self.parse_expr_paren_seq()?;
1273 let fn_span = fn_span_lo.to(self.prev_token.span);
1274 let span = lo.to(self.prev_token.span);
1275 Ok(self.mk_expr(
1276 span,
1277 ExprKind::MethodCall(Box::new(ast::MethodCall {
1278 seg,
1279 receiver: self_arg,
1280 args,
1281 span: fn_span,
1282 })),
1283 ))
1284 } else {
1285 let span = lo.to(self.prev_token.span);
1287 if let Some(args) = seg.args {
1288 self.dcx()
1290 .create_err(crate::diagnostics::FieldExpressionWithGeneric(args.span()))
1291 .stash(seg.ident.span, StashKey::GenericInFieldExpr);
1292 }
1293
1294 Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))
1295 }
1296 }
1297
1298 fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> {
1304 if true && self.may_recover() &&
let Some(mv_kind) = self.token.is_metavar_seq() &&
let token::MetaVarKind::Ty { .. } = mv_kind &&
self.check_noexpect_past_close_delim(&token::PathSep) {
let ty =
self.eat_metavar_seq(mv_kind,
|this|
this.parse_ty_no_question_mark_recover()).expect("metavar seq ty");
return self.maybe_recover_from_bad_qpath_stage_2(self.prev_token.span,
ty);
};maybe_recover_from_interpolated_ty_qpath!(self, true);
1305
1306 let span = self.token.span;
1307 if let Some(expr) = self.eat_metavar_seq_with_matcher(
1308 |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
MetaVarKind::Expr { .. } => true,
_ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
1309 |this| {
1310 let expr = this.parse_expr_force_collect();
1313 if this.token.kind == token::Comma {
1318 this.bump();
1319 }
1320 expr
1321 },
1322 ) {
1323 return Ok(expr);
1324 } else if let Some(lit) =
1325 self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
1326 {
1327 return Ok(lit);
1328 } else if let Some(block) =
1329 self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())
1330 {
1331 return Ok(self.mk_expr(span, ExprKind::Block(block, None)));
1332 } else if let Some(path) =
1333 self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
1334 {
1335 return Ok(self.mk_expr(span, ExprKind::Path(None, path)));
1336 }
1337
1338 let restrictions = self.restrictions;
1342 self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {
1343 let lo = this.token.span;
1345 if let token::Literal(_) = this.token.kind {
1346 this.parse_expr_lit()
1350 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1351 this.parse_expr_tuple_parens(restrictions)
1352 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
1353 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
1354 return Ok(expr);
1355 }
1356 if let Some(arr) = this.recover_from_c_array(lo) {
1357 return Ok(arr);
1358 }
1359 this.parse_expr_block(None, lo, BlockCheckMode::Default)
1360 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Or,
token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or)) || this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OrOr,
token_type: crate::parser::token_type::TokenType::OrOr,
}exp!(OrOr)) {
1361 this.parse_expr_closure().map_err(|mut err| {
1362 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
1365 err.subdiagnostic(crate::diagnostics::ExprParenthesesNeeded::surrounding(
1366 *sp,
1367 ));
1368 }
1369 err
1370 })
1371 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBracket,
token_type: crate::parser::token_type::TokenType::OpenBracket,
}exp!(OpenBracket)) {
1372 this.parse_expr_array_or_repeat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBracket,
token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket))
1373 } else if this.is_builtin() {
1374 this.parse_expr_builtin()
1375 } else if this.check_path() {
1376 this.parse_expr_path_start()
1377 } else if this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Move,
token_type: crate::parser::token_type::TokenType::KwMove,
}exp!(Move))
1378 || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Use,
token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use))
1379 || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Static,
token_type: crate::parser::token_type::TokenType::KwStatic,
}exp!(Static))
1380 || this.check_const_closure()
1381 {
1382 this.parse_expr_closure()
1383 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::If,
token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If)) {
1384 this.parse_expr_if()
1385 } else if this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::For,
token_type: crate::parser::token_type::TokenType::KwFor,
}exp!(For)) {
1386 if this.choose_generics_over_qpath(1) {
1387 this.parse_expr_closure()
1388 } else {
1389 if !this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::For,
token_type: crate::parser::token_type::TokenType::KwFor,
}) {
::core::panicking::panic("assertion failed: this.eat_keyword(exp!(For))")
};assert!(this.eat_keyword(exp!(For)));
1390 this.parse_expr_for(None, lo)
1391 }
1392 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::While,
token_type: crate::parser::token_type::TokenType::KwWhile,
}exp!(While)) {
1393 this.parse_expr_while(None, lo)
1394 } else if let Some(label) = this.eat_label() {
1395 this.parse_expr_labeled(label, true)
1396 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Loop,
token_type: crate::parser::token_type::TokenType::KwLoop,
}exp!(Loop)) {
1397 this.parse_expr_loop(None, lo).map_err(|mut err| {
1398 err.span_label(lo, "while parsing this `loop` expression");
1399 err
1400 })
1401 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Match,
token_type: crate::parser::token_type::TokenType::KwMatch,
}exp!(Match)) {
1402 this.parse_expr_match().map_err(|mut err| {
1403 err.span_label(lo, "while parsing this `match` expression");
1404 err
1405 })
1406 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Unsafe,
token_type: crate::parser::token_type::TokenType::KwUnsafe,
}exp!(Unsafe)) {
1407 this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
1408 |mut err| {
1409 err.span_label(lo, "while parsing this `unsafe` expression");
1410 err
1411 },
1412 )
1413 } else if this.check_inline_const(0) {
1414 this.parse_const_block(lo, false)
1415 } else if this.may_recover() && this.is_do_catch_block() {
1416 this.recover_do_catch()
1417 } else if this.is_try_block() {
1418 this.expect_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Try,
token_type: crate::parser::token_type::TokenType::KwTry,
}exp!(Try))?;
1419 this.parse_try_block(lo)
1420 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Return,
token_type: crate::parser::token_type::TokenType::KwReturn,
}exp!(Return)) {
1421 this.parse_expr_return()
1422 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Continue,
token_type: crate::parser::token_type::TokenType::KwContinue,
}exp!(Continue)) {
1423 this.parse_expr_continue(lo)
1424 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Break,
token_type: crate::parser::token_type::TokenType::KwBreak,
}exp!(Break)) {
1425 this.parse_expr_break()
1426 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Yield,
token_type: crate::parser::token_type::TokenType::KwYield,
}exp!(Yield)) {
1427 this.parse_expr_yield()
1428 } else if this.is_do_yeet() {
1429 this.parse_expr_yeet()
1430 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Become,
token_type: crate::parser::token_type::TokenType::KwBecome,
}exp!(Become)) {
1431 this.parse_expr_become()
1432 } else if this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Let,
token_type: crate::parser::token_type::TokenType::KwLet,
}exp!(Let)) {
1433 this.parse_expr_let(restrictions)
1434 } else if this.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Underscore,
token_type: crate::parser::token_type::TokenType::KwUnderscore,
}exp!(Underscore)) {
1435 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
1436 return Ok(expr);
1437 }
1438 Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
1439 } else if this.token_uninterpolated_span().at_least_rust_2018() {
1440 let at_async = this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Async,
token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async));
1442 if this.token_uninterpolated_span().at_least_rust_2024()
1447 && this.is_gen_block(kw::Gen, at_async as usize)
1448 {
1449 this.parse_gen_block()
1450 } else if this.is_gen_block(kw::Async, 0) {
1452 this.parse_gen_block()
1453 } else if at_async {
1454 this.parse_expr_closure()
1455 } else if this.eat_keyword_noexpect(kw::Await) {
1456 this.recover_incorrect_await_syntax(lo)
1457 } else {
1458 this.parse_expr_lit()
1459 }
1460 } else {
1461 this.parse_expr_lit()
1462 }
1463 })
1464 }
1465
1466 fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> {
1467 let lo = self.token.span;
1468 match self.parse_opt_token_lit() {
1469 Some((token_lit, _)) => {
1470 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));
1471 self.maybe_recover_from_bad_qpath(expr)
1472 }
1473 None => self.try_macro_suggestion(),
1474 }
1475 }
1476
1477 fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
1478 let lo = self.token.span;
1479 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1480 let (es, trailing_comma) = match self.parse_seq_to_end(
1481 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1482 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
1483 |p| p.parse_expr_res(restrictions.intersection(Restrictions::ALLOW_LET)),
1484 ) {
1485 Ok(x) => x,
1486 Err(err) => {
1487 return Ok(self.recover_seq_parse_error(
1488 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen),
1489 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1490 lo,
1491 err,
1492 ));
1493 }
1494 };
1495 let kind = if es.len() == 1 && #[allow(non_exhaustive_omitted_patterns)] match trailing_comma {
Trailing::No => true,
_ => false,
}matches!(trailing_comma, Trailing::No) {
1496 ExprKind::Paren(es.into_iter().next().unwrap())
1498 } else {
1499 ExprKind::Tup(es)
1501 };
1502 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1503 self.maybe_recover_from_bad_qpath(expr)
1504 }
1505
1506 fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> {
1507 let lo = self.token.span;
1508 self.bump(); let kind = if self.eat(close) {
1511 ExprKind::Array(ThinVec::new())
1513 } else {
1514 let first_expr = self.parse_expr()?;
1516 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) {
1517 let count = self.parse_expr_anon_const()?;
1519 self.expect(close)?;
1520 ExprKind::Repeat(first_expr, count)
1521 } else if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1522 let sep = SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
1524 let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
1525 exprs.insert(0, first_expr);
1526 ExprKind::Array(exprs)
1527 } else {
1528 self.expect(close)?;
1530 ExprKind::Array({
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(first_expr);
vec
}thin_vec![first_expr])
1531 }
1532 };
1533 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1534 self.maybe_recover_from_bad_qpath(expr)
1535 }
1536
1537 fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> {
1538 let maybe_eq_tok = self.prev_token;
1539 let (qself, path) = if self.eat_lt() {
1540 let lt_span = self.prev_token.span;
1541 let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
1542 if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
1546 let eq_lt = maybe_eq_tok.span.to(lt_span);
1547 err.span_suggestion_verbose(
1548 eq_lt,
1549 "you might have meant to write a \"less than or equal to\" comparison",
1550 "<=",
1551 Applicability::Unspecified,
1552 );
1553 }
1554 err
1555 })?;
1556 (Some(qself), path)
1557 } else {
1558 (None, self.parse_path(PathStyle::Expr)?)
1559 };
1560
1561 let (span, kind) = if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Bang,
token_type: crate::parser::token_type::TokenType::Bang,
}exp!(Bang)) {
1563 if qself.is_some() {
1565 self.dcx()
1566 .emit_err(crate::diagnostics::MacroInvocationWithQualifiedPath(path.span));
1567 }
1568 let lo = path.span;
1569 let mac = Box::new(MacCall { path, args: self.parse_delim_args()? });
1570 (lo.to(self.prev_token.span), ExprKind::MacCall(mac))
1571 } else if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
1572 && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
1573 {
1574 if qself.is_some() {
1575 self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);
1576 }
1577 return expr;
1578 } else {
1579 (path.span, ExprKind::Path(qself, path))
1580 };
1581
1582 let expr = self.mk_expr(span, kind);
1583 self.maybe_recover_from_bad_qpath(expr)
1584 }
1585
1586 pub(super) fn parse_expr_labeled(
1588 &mut self,
1589 label_: Label,
1590 mut consume_colon: bool,
1591 ) -> PResult<'a, Box<Expr>> {
1592 let lo = label_.ident.span;
1593 let label = Some(label_);
1594 let ate_colon = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon));
1595 let tok_sp = self.token.span;
1596 let expr = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::While,
token_type: crate::parser::token_type::TokenType::KwWhile,
}exp!(While)) {
1597 self.parse_expr_while(label, lo)
1598 } else if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::For,
token_type: crate::parser::token_type::TokenType::KwFor,
}exp!(For)) {
1599 self.parse_expr_for(label, lo)
1600 } else if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Loop,
token_type: crate::parser::token_type::TokenType::KwLoop,
}exp!(Loop)) {
1601 self.parse_expr_loop(label, lo)
1602 } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {
1603 self.parse_expr_block(label, lo, BlockCheckMode::Default)
1604 } else if !ate_colon
1605 && self.may_recover()
1606 && (self.token.kind.close_delim().is_some() || self.token.is_punct())
1607 && could_be_unclosed_char_literal(label_.ident)
1608 {
1609 let (lit, _) =
1610 self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
1611 self_.dcx().create_err(crate::diagnostics::UnexpectedTokenAfterLabel {
1612 span: self_.token.span,
1613 remove_label: None,
1614 enclose_in_block: None,
1615 })
1616 });
1617 consume_colon = false;
1618 Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
1619 } else if !ate_colon
1620 && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
1621 {
1622 let guar = self.dcx().emit_err(crate::diagnostics::UnexpectedTokenAfterLabel {
1624 span: self.token.span,
1625 remove_label: None,
1626 enclose_in_block: None,
1627 });
1628 consume_colon = false;
1629 Ok(self.mk_expr_err(lo, guar))
1630 } else {
1631 let mut err = crate::diagnostics::UnexpectedTokenAfterLabel {
1632 span: self.token.span,
1633 remove_label: None,
1634 enclose_in_block: None,
1635 };
1636
1637 let expr = self.parse_expr().map(|expr| {
1639 let span = expr.span;
1640
1641 let found_labeled_breaks = {
1642 struct FindLabeledBreaksVisitor;
1643
1644 impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {
1645 type Result = ControlFlow<()>;
1646 fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {
1647 if let ExprKind::Break(Some(_label), _) = ex.kind {
1648 ControlFlow::Break(())
1649 } else {
1650 walk_expr(self, ex)
1651 }
1652 }
1653 }
1654
1655 FindLabeledBreaksVisitor.visit_expr(&expr).is_break()
1656 };
1657
1658 if !found_labeled_breaks {
1663 err.remove_label = Some(lo.until(span));
1664
1665 return expr;
1666 }
1667
1668 err.enclose_in_block = Some(crate::diagnostics::UnexpectedTokenAfterLabelSugg {
1669 left: span.shrink_to_lo(),
1670 right: span.shrink_to_hi(),
1671 });
1672
1673 let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
1675 let blk = self.mk_block({
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(stmt);
vec
}thin_vec![stmt], BlockCheckMode::Default, span);
1676 self.mk_expr(span, ExprKind::Block(blk, label))
1677 });
1678
1679 self.dcx().emit_err(err);
1680 expr
1681 }?;
1682
1683 if !ate_colon && consume_colon {
1684 self.dcx().emit_err(crate::diagnostics::RequireColonAfterLabeledExpression {
1685 span: expr.span,
1686 label: lo,
1687 label_end: lo.between(tok_sp),
1688 });
1689 }
1690
1691 Ok(expr)
1692 }
1693
1694 pub(super) fn recover_unclosed_char<L>(
1696 &self,
1697 ident: Ident,
1698 mk_lit_char: impl FnOnce(Symbol, Span) -> L,
1699 err: impl FnOnce(&Self) -> Diag<'a>,
1700 ) -> L {
1701 if !could_be_unclosed_char_literal(ident) {
::core::panicking::panic("assertion failed: could_be_unclosed_char_literal(ident)")
};assert!(could_be_unclosed_char_literal(ident));
1702 self.dcx()
1703 .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {
1704 err.span_suggestion_verbose(
1705 ident.span.shrink_to_hi(),
1706 "add `'` to close the char literal",
1707 "'",
1708 Applicability::MaybeIncorrect,
1709 );
1710 })
1711 .unwrap_or_else(|| {
1712 err(self)
1713 .with_span_suggestion_verbose(
1714 ident.span.shrink_to_hi(),
1715 "add `'` to close the char literal",
1716 "'",
1717 Applicability::MaybeIncorrect,
1718 )
1719 .emit_err()
1720 });
1721 let name = ident.without_first_quote().name;
1722 mk_lit_char(name, ident.span)
1723 }
1724
1725 fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> {
1727 let lo = self.token.span;
1728
1729 self.bump(); self.bump(); let span = lo.to(self.prev_token.span);
1733 self.dcx().emit_err(crate::diagnostics::DoCatchSyntaxRemoved { span });
1734
1735 self.parse_try_block(lo)
1736 }
1737
1738 fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> {
1740 Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })
1741 }
1742
1743 fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> {
1745 let lo = self.prev_token.span;
1746 let kind = ExprKind::Ret(self.parse_expr_opt()?);
1747 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1748 self.maybe_recover_from_bad_qpath(expr)
1749 }
1750
1751 fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> {
1753 let lo = self.token.span;
1754
1755 self.bump(); self.bump(); let kind = ExprKind::Yeet(self.parse_expr_opt()?);
1759
1760 let span = lo.to(self.prev_token.span);
1761 self.psess.gated_spans.gate(sym::yeet_expr, span);
1762 let expr = self.mk_expr(span, kind);
1763 self.maybe_recover_from_bad_qpath(expr)
1764 }
1765
1766 fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> {
1768 let lo = self.prev_token.span;
1769 let kind = ExprKind::Become(self.parse_expr()?);
1770 let span = lo.to(self.prev_token.span);
1771 self.psess.gated_spans.gate(sym::explicit_tail_calls, span);
1772 let expr = self.mk_expr(span, kind);
1773 self.maybe_recover_from_bad_qpath(expr)
1774 }
1775
1776 fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {
1785 let lo = self.prev_token.span;
1786 let mut label = self.eat_label();
1787 let kind = if self.token == token::Colon
1788 && let Some(label) = label.take()
1789 {
1790 let lexpr = self.parse_expr_labeled(label, true)?;
1793 self.dcx().emit_err(crate::diagnostics::LabeledLoopInBreak {
1794 span: lexpr.span,
1795 sub: crate::diagnostics::WrapInParentheses::Expression {
1796 left: lexpr.span.shrink_to_lo(),
1797 right: lexpr.span.shrink_to_hi(),
1798 },
1799 });
1800 Some(lexpr)
1801 } else if self.token != token::OpenBrace
1802 || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
1803 {
1804 let mut expr = self.parse_expr_opt()?;
1805 if let Some(expr) = &mut expr {
1806 if label.is_some()
1807 && match &expr.kind {
1808 ExprKind::While(_, _, None)
1809 | ExprKind::ForLoop(ForLoop { label: None, .. })
1810 | ExprKind::Loop(_, None, _) => true,
1811 ExprKind::Block(block, None) => {
1812 #[allow(non_exhaustive_omitted_patterns)] match block.rules {
BlockCheckMode::Default => true,
_ => false,
}matches!(block.rules, BlockCheckMode::Default)
1813 }
1814 _ => false,
1815 }
1816 {
1817 let span = expr.span;
1818 self.psess.buffer_lint(
1819 BREAK_WITH_LABEL_AND_LOOP,
1820 lo.to(expr.span),
1821 ast::CRATE_NODE_ID,
1822 crate::diagnostics::BreakWithLabelAndLoop {
1823 sub: crate::diagnostics::BreakWithLabelAndLoopSub {
1824 left: span.shrink_to_lo(),
1825 right: span.shrink_to_hi(),
1826 },
1827 },
1828 );
1829 }
1830
1831 if self.may_recover()
1833 && let ExprKind::Path(None, p) = &expr.kind
1834 && let [segment] = &*p.segments
1835 && let &ast::PathSegment { ident, args: None, .. } = segment
1836 && let Some(next) = self.parse_expr_opt()?
1837 {
1838 label = Some(self.recover_ident_into_label(ident));
1839 *expr = next;
1840 }
1841 }
1842
1843 expr
1844 } else {
1845 None
1846 };
1847 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));
1848 self.maybe_recover_from_bad_qpath(expr)
1849 }
1850
1851 fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
1853 let mut label = self.eat_label();
1854
1855 if self.may_recover()
1857 && label.is_none()
1858 && let Some((ident, _)) = self.token.ident()
1859 {
1860 self.bump();
1861 label = Some(self.recover_ident_into_label(ident));
1862 }
1863
1864 let kind = ExprKind::Continue(label);
1865 Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
1866 }
1867
1868 fn parse_expr_yield(&mut self) -> PResult<'a, Box<Expr>> {
1870 let lo = self.prev_token.span;
1871 let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));
1872 let span = lo.to(self.prev_token.span);
1873 self.psess.gated_spans.gate(sym::yield_expr, span);
1874 let expr = self.mk_expr(span, kind);
1875 self.maybe_recover_from_bad_qpath(expr)
1876 }
1877
1878 fn parse_expr_builtin(&mut self) -> PResult<'a, Box<Expr>> {
1880 self.parse_builtin(|this, lo, ident| {
1881 Ok(match ident.name {
1882 sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
1883 sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
1884 sym::wrap_binder => {
1885 Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
1886 }
1887 sym::unwrap_binder => {
1888 Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
1889 }
1890 _ => None,
1891 })
1892 })
1893 }
1894
1895 pub(crate) fn parse_builtin<T>(
1896 &mut self,
1897 parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
1898 ) -> PResult<'a, T> {
1899 let lo = self.token.span;
1900
1901 self.bump(); self.bump(); let Some((ident, IdentKind::Normal)) = self.token.ident() else {
1905 let err = self
1906 .dcx()
1907 .create_err(crate::diagnostics::ExpectedBuiltinIdent { span: self.token.span });
1908 return Err(err);
1909 };
1910 self.psess.gated_spans.gate(sym::builtin_syntax, ident.span);
1911 self.bump();
1912
1913 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1914 let ret = if let Some(res) = parse(self, lo, ident)? {
1915 Ok(res)
1916 } else {
1917 let err = self.dcx().create_err(crate::diagnostics::UnknownBuiltinConstruct {
1918 span: lo.to(ident.span),
1919 name: ident,
1920 });
1921 return Err(err);
1922 };
1923 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
1924
1925 ret
1926 }
1927
1928 pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
1930 let container = self.parse_ty()?;
1931 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
1932
1933 let fields = self.parse_floating_field_access()?;
1934 let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
1935
1936 if let Err(mut e) = self.expect_one_of(&[], &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen)]) {
1937 if trailing_comma {
1938 e.note("unexpected third argument to offset_of");
1939 } else {
1940 e.note("offset_of expects dot-separated field and variant names");
1941 }
1942 e.emit();
1943 }
1944
1945 if self.may_recover() {
1947 while !self.token.kind.is_close_delim_or_eof() {
1948 self.bump();
1949 }
1950 }
1951
1952 let span = lo.to(self.token.span);
1953 Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
1954 }
1955
1956 pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
1958 let expr = self.parse_expr()?;
1959 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
1960 let ty = self.parse_ty()?;
1961 let span = lo.to(self.token.span);
1962 Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
1963 }
1964
1965 pub(crate) fn parse_expr_unsafe_binder_cast(
1966 &mut self,
1967 lo: Span,
1968 kind: UnsafeBinderCastKind,
1969 ) -> PResult<'a, Box<Expr>> {
1970 let expr = self.parse_expr()?;
1971 let ty = if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) { Some(self.parse_ty()?) } else { None };
1972 let span = lo.to(self.token.span);
1973 Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
1974 }
1975
1976 pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<MetaItemLit>> {
1980 match self.parse_opt_meta_item_lit() {
1981 Some(lit) => match lit.kind {
1982 ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
1983 style,
1984 symbol: lit.symbol,
1985 suffix: lit.suffix,
1986 span: lit.span,
1987 symbol_unescaped,
1988 }),
1989 _ => Err(Some(lit)),
1990 },
1991 None => Err(None),
1992 }
1993 }
1994
1995 pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) {
1996 (token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
1997 }
1998
1999 fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
2000 ast::MetaItemLit {
2001 symbol: name,
2002 suffix: None,
2003 kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),
2004 span,
2005 }
2006 }
2007
2008 fn handle_missing_lit<L>(
2009 &mut self,
2010 mk_lit_char: impl FnOnce(Symbol, Span) -> L,
2011 ) -> PResult<'a, L> {
2012 let token = self.token;
2013 let err = |self_: &Self| {
2014 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unexpected token: {0}",
super::token_descr(&token)))
})format!("unexpected token: {}", super::token_descr(&token));
2015 self_.dcx().struct_span_err(token.span, msg)
2016 };
2017 if let Some((ident, IdentKind::Normal)) = self.token.lifetime()
2020 && could_be_unclosed_char_literal(ident)
2021 {
2022 let lt = self.expect_lifetime();
2023 Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err))
2024 } else {
2025 Err(err(self))
2026 }
2027 }
2028
2029 pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> {
2030 self.parse_opt_token_lit()
2031 .ok_or(())
2032 .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char))
2033 }
2034
2035 pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> {
2036 self.parse_opt_meta_item_lit()
2037 .ok_or(())
2038 .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char))
2039 }
2040
2041 fn recover_after_dot(&mut self) {
2042 if self.token == token::Dot {
2043 let recovered = self.look_ahead(1, |next_token| {
2046 if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
2053 next_token.kind
2054 && suffix.is_none_or(|s| s == sym::f32 || s == sym::f64)
2055 && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
2056 && self.token.span.hi() == next_token.span.lo()
2057 {
2058 let s = String::from("0.") + symbol.as_str();
2059 let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
2060 Some(Token::new(kind, self.token.span.to(next_token.span)))
2061 } else {
2062 None
2063 }
2064 });
2065 if let Some(recovered) = recovered {
2066 self.dcx().emit_err(crate::diagnostics::FloatLiteralRequiresIntegerPart {
2067 span: recovered.span,
2068 suggestion: recovered.span.shrink_to_lo(),
2069 });
2070 self.bump();
2071 self.token = recovered;
2072 }
2073 }
2074 }
2075
2076 pub fn eat_token_lit(&mut self) -> Option<token::Lit> {
2079 let check_expr = |expr: Box<Expr>| {
2080 if let ast::ExprKind::Lit(token_lit) = expr.kind {
2081 Some(token_lit)
2082 } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind
2083 && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner
2084 {
2085 None
2086 } else {
2087 {
::core::panicking::panic_fmt(format_args!("unexpected reparsed expr/literal: {0:?}",
expr.kind));
};panic!("unexpected reparsed expr/literal: {:?}", expr.kind);
2088 }
2089 };
2090 match self.token.uninterpolate().kind {
2091 token::Ident(name, IdentKind::Normal) if name.is_bool_lit() => {
2092 self.bump();
2093 Some(token::Lit::new(token::Bool, name, None))
2094 }
2095 token::Literal(token_lit) => {
2096 self.bump();
2097 Some(token_lit)
2098 }
2099 token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => {
2100 let lit = self
2101 .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2102 .expect("metavar seq literal");
2103 check_expr(lit)
2104 }
2105 token::OpenInvisible(InvisibleOrigin::MetaVar(
2106 mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. },
2107 )) => {
2108 let expr = self
2109 .eat_metavar_seq(mv_kind, |this| this.parse_expr())
2110 .expect("metavar seq expr");
2111 check_expr(expr)
2112 }
2113 _ => None,
2114 }
2115 }
2116
2117 fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> {
2120 self.recover_after_dot();
2121 let span = self.token.span;
2122 self.eat_token_lit().map(|token_lit| (token_lit, span))
2123 }
2124
2125 fn parse_opt_meta_item_lit(&mut self) -> Option<MetaItemLit> {
2128 self.recover_after_dot();
2129 let span = self.token.span;
2130 let uninterpolated_span = self.token_uninterpolated_span();
2131 self.eat_token_lit().map(|token_lit| {
2132 match MetaItemLit::from_token_lit(token_lit, span) {
2133 Ok(lit) => lit,
2134 Err(err) => {
2135 let guar = report_lit_error(&self.psess, err, token_lit, uninterpolated_span);
2136 let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
2139 let symbol = Symbol::intern(&suffixless_lit.to_string());
2140 let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
2141 MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
2142 }
2143 }
2144 })
2145 }
2146
2147 pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> {
2150 if let Some(expr) = self.eat_metavar_seq_with_matcher(
2151 |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
MetaVarKind::Expr { .. } => true,
_ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
2152 |this| {
2153 this.parse_expr()
2164 },
2165 ) {
2166 return Ok(expr);
2167 } else if let Some(lit) =
2168 self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2169 {
2170 return Ok(lit);
2171 }
2172
2173 let lo = self.token.span;
2174 let minus_present = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Minus,
token_type: crate::parser::token_type::TokenType::Minus,
}exp!(Minus));
2175 let (token_lit, span) = self.parse_token_lit()?;
2176 let expr = self.mk_expr(span, ExprKind::Lit(token_lit));
2177
2178 if minus_present {
2179 Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr)))
2180 } else {
2181 Ok(expr)
2182 }
2183 }
2184
2185 fn suggest_missing_semicolon_before_array(
2186 &self,
2187 prev_span: Span,
2188 open_delim_span: Span,
2189 ) -> PResult<'a, ()> {
2190 if !self.may_recover() {
2191 return Ok(());
2192 }
2193
2194 if self.token == token::Comma {
2195 if !self.psess.source_map().is_multiline(prev_span.until(self.token.span)) {
2196 return Ok(());
2197 }
2198 let mut snapshot = self.create_snapshot_for_diagnostic();
2199 snapshot.bump();
2200 match snapshot.parse_seq_to_before_end(
2201 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBracket,
token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket),
2202 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2203 |p| p.parse_expr(),
2204 ) {
2205 Ok(_)
2206 if snapshot
2212 .span_to_snippet(snapshot.token.span)
2213 .is_ok_and(|snippet| snippet == "]") =>
2214 {
2215 return Err(self.dcx().create_err(crate::diagnostics::MissingSemicolonBeforeArray {
2216 open_delim: open_delim_span,
2217 semicolon: prev_span.shrink_to_hi(),
2218 }));
2219 }
2220 Ok(_) => (),
2221 Err(err) => err.cancel(),
2222 }
2223 }
2224 Ok(())
2225 }
2226
2227 pub(super) fn parse_expr_block(
2229 &mut self,
2230 opt_label: Option<Label>,
2231 lo: Span,
2232 blk_mode: BlockCheckMode,
2233 ) -> PResult<'a, Box<Expr>> {
2234 if self.token.is_metavar_block() {
2235 self.dcx().emit_err(crate::diagnostics::InvalidBlockMacroSegment {
2236 span: self.token.span,
2237 context: lo.to(self.token.span),
2238 wrap: crate::diagnostics::WrapInExplicitBlock {
2239 lo: self.token.span.shrink_to_lo(),
2240 hi: self.token.span.shrink_to_hi(),
2241 },
2242 });
2243 }
2244
2245 let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?;
2246 Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
2247 }
2248
2249 fn parse_simple_block(&mut self) -> PResult<'a, Box<Expr>> {
2251 let blk = self.parse_block()?;
2252 Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None)))
2253 }
2254
2255 fn parse_expr_closure(&mut self) -> PResult<'a, Box<Expr>> {
2257 let lo = self.token.span;
2258
2259 let before = self.prev_token;
2260 let binder = if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::For,
token_type: crate::parser::token_type::TokenType::KwFor,
}exp!(For)) {
2261 let lo = self.token.span;
2262 let (bound_vars, _) = self.parse_higher_ranked_binder()?;
2263 let span = lo.to(self.prev_token.span);
2264
2265 self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
2266
2267 ClosureBinder::For { span, generic_params: bound_vars }
2268 } else {
2269 ClosureBinder::NotPresent
2270 };
2271
2272 let constness = self.parse_closure_constness();
2273
2274 let movability = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Static,
token_type: crate::parser::token_type::TokenType::KwStatic,
}exp!(Static)) {
2275 self.psess.gated_spans.gate(sym::coroutines, self.prev_token.span);
2276 Movability::Static
2277 } else {
2278 Movability::Movable
2279 };
2280
2281 let coroutine_marker = if self.token_uninterpolated_span().at_least_rust_2018() {
2282 self.parse_coroutine_marker(Case::Sensitive)
2283 } else {
2284 None
2285 };
2286
2287 if let ClosureBinder::NotPresent = binder
2288 && coroutine_marker.is_some()
2289 {
2290 self.expected_token_types.insert(TokenType::OpenBrace);
2293 }
2294
2295 let capture_clause = self.parse_capture_clause()?;
2296 let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
2297 let decl_hi = self.prev_token.span;
2298 let mut body = match &fn_decl.output {
2299 FnRetTy::Default(_) => {
2301 let restrictions =
2302 self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2303 let prev = self.prev_token;
2304 let token = self.token;
2305 match self.parse_expr_res(restrictions) {
2306 Ok(expr) => expr,
2307 Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
2308 }
2309 }
2310 FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
2312 };
2313
2314 if let Some(coroutine_marker) = coroutine_marker
2315 && coroutine_marker.kind.is_gen()
2316 {
2317 self.psess.gated_spans.gate(sym::gen_blocks, coroutine_marker.span);
2320 }
2321
2322 if self.token == TokenKind::Semi
2323 && let Some((Delimiter::Parenthesis, _)) = self.token_cursor.parent_delim_and_span()
2324 && self.may_recover()
2325 {
2326 body = self.mk_expr_err(
2330 body.span,
2331 self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"),
2332 );
2333 }
2334
2335 let body_span = body.span;
2336
2337 let closure = self.mk_expr(
2338 lo.to(body.span),
2339 ExprKind::Closure(Box::new(ast::Closure {
2340 binder,
2341 capture_clause,
2342 constness,
2343 coroutine_marker,
2344 movability,
2345 fn_decl,
2346 body,
2347 fn_decl_span: lo.to(decl_hi),
2348 fn_arg_span,
2349 })),
2350 );
2351
2352 let spans =
2354 ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
2355 self.current_closure = Some(spans);
2356
2357 Ok(closure)
2358 }
2359
2360 fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, Box<Expr>> {
2362 if self.may_recover()
2363 && self.token.can_begin_expr()
2364 && self.token.kind != TokenKind::OpenBrace
2365 && !self.token.is_metavar_block()
2366 {
2367 let snapshot = self.create_snapshot_for_diagnostic();
2368 let restrictions =
2369 self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2370 let tok = self.token.clone();
2371 match self.parse_expr_res(restrictions) {
2372 Ok(expr) => {
2373 let descr = super::token_descr(&tok);
2374 let mut diag = self
2375 .dcx()
2376 .struct_span_err(tok.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected `{{`, found {0}", descr))
})format!("expected `{{`, found {descr}"));
2377 diag.span_label(
2378 ret_span,
2379 "explicit return type requires closure body to be enclosed in braces",
2380 );
2381 diag.multipart_suggestion(
2382 "wrap the expression in curly braces",
2383 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(expr.span.shrink_to_lo(), "{ ".to_string()),
(expr.span.shrink_to_hi(), " }".to_string())]))vec![
2384 (expr.span.shrink_to_lo(), "{ ".to_string()),
2385 (expr.span.shrink_to_hi(), " }".to_string()),
2386 ],
2387 Applicability::MachineApplicable,
2388 );
2389 diag.emit();
2390 return Ok(expr);
2391 }
2392 Err(diag) => {
2393 diag.cancel();
2394 self.restore_snapshot(snapshot);
2395 }
2396 }
2397 }
2398
2399 let body_lo = self.token.span;
2400 self.parse_expr_block(None, body_lo, BlockCheckMode::Default)
2401 }
2402
2403 fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
2405 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Move,
token_type: crate::parser::token_type::TokenType::KwMove,
}exp!(Move)) {
2406 let move_kw_span = self.prev_token.span;
2407 if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Async,
token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async)) {
2409 let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2410 Err(self.dcx().create_err(crate::diagnostics::AsyncMoveOrderIncorrect {
2411 span: move_async_span,
2412 }))
2413 } else {
2414 Ok(CaptureBy::Value { move_kw: move_kw_span })
2415 }
2416 } else if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Use,
token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use)) {
2417 let use_kw_span = self.prev_token.span;
2418 self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
2419 if self.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Async,
token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async)) {
2421 let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2422 Err(self.dcx().create_err(crate::diagnostics::AsyncUseOrderIncorrect {
2423 span: use_async_span,
2424 }))
2425 } else {
2426 Ok(CaptureBy::Use { use_kw: use_kw_span })
2427 }
2428 } else {
2429 Ok(CaptureBy::Ref)
2430 }
2431 }
2432
2433 fn parse_fn_block_decl(&mut self) -> PResult<'a, (Box<FnDecl>, Span)> {
2435 let arg_start = self.token.span.lo();
2436
2437 let inputs = if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OrOr,
token_type: crate::parser::token_type::TokenType::OrOr,
}exp!(OrOr)) {
2438 ThinVec::new()
2439 } else {
2440 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Or,
token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or))?;
2441 let args = self
2442 .parse_seq_to_before_tokens(
2443 &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Or,
token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or)],
2444 &[&token::OrOr],
2445 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2446 |p| p.parse_fn_block_param(),
2447 )?
2448 .0;
2449 self.expect_or()?;
2450 args
2451 };
2452 let arg_span = self.prev_token.span.with_lo(arg_start);
2453 let output =
2454 self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
2455
2456 Ok((Box::new(FnDecl { inputs, output }), arg_span))
2457 }
2458
2459 fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
2461 let lo = self.token.span;
2462 let attrs = self.parse_outer_attributes()?;
2463 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
2464 let pat = Box::new(this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?);
2465 let ty = if this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
2466 this.parse_ty()?
2467 } else {
2468 this.mk_ty(pat.span, TyKind::Infer)
2469 };
2470
2471 Ok((
2472 Param {
2473 attrs,
2474 ty,
2475 pat,
2476 span: lo.to(this.prev_token.span),
2477 id: DUMMY_NODE_ID,
2478 is_placeholder: false,
2479 },
2480 Trailing::from(this.token == token::Comma),
2481 UsePreAttrPos::No,
2482 ))
2483 })
2484 }
2485
2486 fn parse_expr_if(&mut self) -> PResult<'a, Box<Expr>> {
2488 let lo = self.prev_token.span;
2489 let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2492 let cond = self.parse_expr_cond(let_chains_policy)?;
2493 self.parse_if_after_cond(lo, cond)
2494 }
2495
2496 fn parse_if_after_cond(&mut self, lo: Span, mut cond: Box<Expr>) -> PResult<'a, Box<Expr>> {
2497 let cond_span = cond.span;
2498 let mut recover_block_from_condition = |this: &mut Self| {
2502 let block = match &mut cond.kind {
2503 ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
2504 if let ExprKind::Block(_, None) = right.kind =>
2505 {
2506 let guar = this.dcx().emit_err(crate::diagnostics::IfExpressionMissingThenBlock {
2507 if_span: lo,
2508 missing_then_block_sub:
2509 crate::diagnostics::IfExpressionMissingThenBlockSub::UnfinishedCondition(
2510 cond_span.shrink_to_lo().to(*binop_span),
2511 ),
2512 let_else_sub: None,
2513 });
2514 std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar))
2515 }
2516 ExprKind::Block(_, None) => {
2517 let guar =
2518 this.dcx().emit_err(crate::diagnostics::IfExpressionMissingCondition {
2519 if_span: lo.with_neighbor(cond.span).shrink_to_hi(),
2520 block_span: self.psess.source_map().start_point(cond_span),
2521 });
2522 std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar))
2523 }
2524 _ => {
2525 return None;
2526 }
2527 };
2528 if let ExprKind::Block(block, _) = &block.kind {
2529 Some(block.clone())
2530 } else {
2531 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
2532 }
2533 };
2534 let thn = if self.token.is_keyword(kw::Else) {
2536 if let Some(block) = recover_block_from_condition(self) {
2537 block
2538 } else {
2539 let let_else_sub = #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
ExprKind::Let(..) => true,
_ => false,
}matches!(cond.kind, ExprKind::Let(..)).then(|| {
2540 crate::diagnostics::IfExpressionLetSomeSub { if_span: lo.until(cond_span) }
2541 });
2542
2543 let guar = self.dcx().emit_err(crate::diagnostics::IfExpressionMissingThenBlock {
2544 if_span: lo,
2545 missing_then_block_sub:
2546 crate::diagnostics::IfExpressionMissingThenBlockSub::AddThenBlock(
2547 cond_span.shrink_to_hi(),
2548 ),
2549 let_else_sub,
2550 });
2551 self.mk_block_err(cond_span.shrink_to_hi(), guar)
2552 }
2553 } else {
2554 let attrs = self.parse_outer_attributes()?; let maybe_fatarrow = self.token;
2556 let block = if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2557 self.parse_block()?
2558 } else if let Some(block) = recover_block_from_condition(self) {
2559 block
2560 } else {
2561 self.error_on_extra_if(&cond)?;
2562 self.parse_block().map_err(|mut err| {
2564 if self.prev_token == token::Semi
2565 && self.token == token::AndAnd
2566 && let maybe_let = self.look_ahead(1, |t| t.clone())
2567 && maybe_let.is_keyword(kw::Let)
2568 {
2569 err.span_suggestion_verbose(
2570 self.prev_token.span,
2571 "consider removing this semicolon to parse the `let` as part of the same chain",
2572 "",
2573 Applicability::MachineApplicable,
2574 ).span_note(
2575 self.token.span.to(maybe_let.span),
2576 "you likely meant to continue parsing the let-chain starting here",
2577 );
2578 } else {
2579 if self.prev_token == token::Semi
2580 && (self.token == token::OpenBrace || AssocOp::from_token(&self.token).is_some())
2581 {
2582 err.span_suggestion_verbose(
2583 self.prev_token.span,
2584 "remove this semicolon",
2585 "",
2586 Applicability::MaybeIncorrect,
2587 );
2588 }
2589
2590 if maybe_fatarrow == token::FatArrow {
2592 err.span_suggestion_verbose(
2593 maybe_fatarrow.span,
2594 "you might have meant to write a \"greater than or equal to\" comparison",
2595 ">=",
2596 Applicability::MaybeIncorrect,
2597 );
2598 }
2599 err.span_note(
2600 cond_span,
2601 "the `if` expression is missing a block after this condition",
2602 );
2603 }
2604 err
2605 })?
2606 };
2607 self.error_on_if_block_attrs(lo, false, block.span, attrs);
2608 block
2609 };
2610 let els = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Else,
token_type: crate::parser::token_type::TokenType::KwElse,
}exp!(Else)) { Some(self.parse_expr_else()?) } else { None };
2611 Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
2612 }
2613
2614 pub fn parse_expr_cond(
2621 &mut self,
2622 let_chains_policy: LetChainsPolicy,
2623 ) -> PResult<'a, Box<Expr>> {
2624 let mut cond =
2625 self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET)?;
2626
2627 let mut checker = CondChecker::new(self, let_chains_policy);
2628 checker.visit_expr(&mut cond);
2629 Ok(if let Some(guar) = checker.found_incorrect_let_chain {
2630 self.mk_expr_err(cond.span, guar)
2631 } else {
2632 cond
2633 })
2634 }
2635
2636 fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
2638 let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
2639 let err = crate::diagnostics::ExpectedExpressionFoundLet {
2640 span: self.token.span,
2641 reason: crate::diagnostics::ForbiddenLetReason::OtherForbidden,
2642 missing_let: None,
2643 comparison: None,
2644 };
2645 if self.prev_token == token::Or {
2646 return Err(self.dcx().create_err(err));
2648 } else {
2649 Recovered::Yes(self.dcx().emit_err(err))
2650 }
2651 } else {
2652 Recovered::No
2653 };
2654 self.bump(); let lo = self.prev_token.span;
2656 let pat = self.parse_pat_no_top_guard(
2657 None,
2658 RecoverComma::Yes,
2659 RecoverColon::Yes,
2660 CommaRecoveryMode::LikelyTuple,
2661 )?;
2662 if self.token == token::EqEq {
2663 self.dcx().emit_err(crate::diagnostics::ExpectedEqForLetExpr {
2664 span: self.token.span,
2665 sugg_span: self.token.span,
2666 });
2667 self.bump();
2668 } else {
2669 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq))?;
2670 }
2671 let expr = self.parse_expr_assoc(Bound::Excluded(prec_let_scrutinee_needs_par()))?;
2672 let span = lo.to(expr.span);
2673 Ok(self.mk_expr(span, ExprKind::Let(Box::new(pat), expr, span, recovered)))
2674 }
2675
2676 fn parse_expr_else(&mut self) -> PResult<'a, Box<Expr>> {
2678 let else_span = self.prev_token.span; let attrs = self.parse_outer_attributes()?; let expr = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::If,
token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If)) {
2681 self.parse_expr_if()?
2682 } else if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2683 self.parse_simple_block()?
2684 } else {
2685 let snapshot = self.create_snapshot_for_diagnostic();
2686 let first_tok = super::token_descr(&self.token);
2687 let first_tok_span = self.token.span;
2688 match self.parse_expr() {
2689 Ok(cond)
2690 if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
2725 && (classify::expr_requires_semi_to_be_stmt(&cond)
2726 || #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
ExprKind::MacCall(..) => true,
_ => false,
}matches!(cond.kind, ExprKind::MacCall(..)))
2727 =>
2728 {
2729 self.dcx().emit_err(crate::diagnostics::ExpectedElseBlock {
2730 first_tok_span,
2731 first_tok,
2732 else_span,
2733 condition_start: cond.span.shrink_to_lo(),
2734 });
2735 self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
2736 }
2737 Err(e) => {
2738 e.cancel();
2739 self.restore_snapshot(snapshot);
2740 self.parse_simple_block()?
2741 },
2742 Ok(_) => {
2743 self.restore_snapshot(snapshot);
2744 self.parse_simple_block()?
2745 },
2746 }
2747 };
2748 self.error_on_if_block_attrs(else_span, true, expr.span, attrs);
2749 Ok(expr)
2750 }
2751
2752 fn error_on_if_block_attrs(
2753 &self,
2754 ctx_span: Span,
2755 is_ctx_else: bool,
2756 branch_span: Span,
2757 attrs: AttrWrapper,
2758 ) {
2759 if !attrs.is_empty()
2760 && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
2761 {
2762 let attributes = x0.span.until(branch_span);
2763 let last = xn.span;
2764 let ctx = if is_ctx_else { "else" } else { "if" };
2765 self.dcx().emit_err(crate::diagnostics::OuterAttributeNotAllowedOnIfElse {
2766 last,
2767 branch_span,
2768 ctx_span,
2769 ctx: ctx.to_string(),
2770 attributes,
2771 });
2772 }
2773 }
2774
2775 fn error_on_extra_if(&mut self, cond: &Box<Expr>) -> PResult<'a, ()> {
2776 if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind
2777 && let BinOpKind::And = binop
2778 && let ExprKind::If(cond, ..) = &right.kind
2779 {
2780 Err(self.dcx().create_err(crate::diagnostics::UnexpectedIfWithIf(
2781 binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()),
2782 )))
2783 } else {
2784 Ok(())
2785 }
2786 }
2787
2788 pub fn parse_for_head(&mut self) -> PResult<'a, (Pat, Box<Expr>)> {
2790 let begin_paren = if self.token == token::OpenParen {
2791 let start_span = self.token.span;
2795 let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2796 Some((start_span, left))
2797 } else {
2798 None
2799 };
2800 let pat = match (
2802 self.parse_pat_allow_top_guard(
2803 None,
2804 RecoverComma::Yes,
2805 RecoverColon::Yes,
2806 CommaRecoveryMode::LikelyTuple,
2807 ),
2808 begin_paren,
2809 ) {
2810 (Ok(pat), _) => pat, (Err(err), Some((start_span, left))) if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::In,
token_type: crate::parser::token_type::TokenType::KwIn,
}exp!(In)) => {
2812 let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL) {
2815 Ok(expr) => expr,
2816 Err(expr_err) => {
2817 expr_err.cancel();
2820 return Err(err);
2821 }
2822 };
2823 return if self.token == token::CloseParen {
2824 let span = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[start_span, self.token.span]))vec![start_span, self.token.span];
2827 let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2828 self.bump(); err.cancel();
2830 self.dcx().emit_err(crate::diagnostics::ParenthesesInForHead {
2831 span,
2832 sugg: crate::diagnostics::ParenthesesInForHeadSugg { left, right },
2836 });
2837 Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
2838 } else {
2839 Err(err) };
2841 }
2842 (Err(err), _) => return Err(err), };
2844 if !self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::In,
token_type: crate::parser::token_type::TokenType::KwIn,
}exp!(In)) {
2845 self.error_missing_in_for_loop();
2846 }
2847 self.check_for_for_in_in_typo(self.prev_token.span);
2848 let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
2849 Ok((pat, expr))
2850 }
2851
2852 fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
2854 let is_await =
2855 self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Await,
token_type: crate::parser::token_type::TokenType::KwAwait,
}exp!(Await));
2856
2857 if is_await {
2858 self.psess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
2859 }
2860
2861 let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For };
2862
2863 let (pat, expr) = self.parse_for_head()?;
2864 let pat = Box::new(pat);
2865 if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ExprKind::Block(..) => true,
_ => false,
}matches!(expr.kind, ExprKind::Block(..))
2867 && self.token.kind != token::OpenBrace
2868 && self.may_recover()
2869 {
2870 let guar = self.dcx().emit_err(crate::diagnostics::MissingExpressionInForLoop {
2871 span: expr.span.shrink_to_lo(),
2872 });
2873 let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar));
2874 let block = self.mk_block(::thin_vec::ThinVec::new()thin_vec![], BlockCheckMode::Default, self.prev_token.span);
2875 return Ok(self.mk_expr(
2876 lo.to(self.prev_token.span),
2877 ExprKind::ForLoop(Box::new(ForLoop {
2878 pat,
2879 iter: err_expr,
2880 body: block,
2881 label: opt_label,
2882 kind,
2883 })),
2884 ));
2885 }
2886
2887 let (attrs, loop_block) = self.parse_inner_attrs_and_block(
2888 opt_label.is_none().then_some(lo),
2891 )?;
2892
2893 let kind = ExprKind::ForLoop(Box::new(ForLoop {
2894 pat,
2895 iter: expr,
2896 body: loop_block,
2897 label: opt_label,
2898 kind,
2899 }));
2900
2901 self.recover_loop_else("for", lo)?;
2902
2903 Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
2904 }
2905
2906 fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> {
2908 if self.token.is_keyword(kw::Else) && self.may_recover() {
2909 let else_span = self.token.span;
2910 self.bump();
2911 let else_clause = self.parse_expr_else()?;
2912 self.dcx().emit_err(crate::diagnostics::LoopElseNotSupported {
2913 span: else_span.to(else_clause.span),
2914 loop_kind,
2915 loop_kw,
2916 });
2917 }
2918 Ok(())
2919 }
2920
2921 fn error_missing_in_for_loop(&mut self) {
2922 let (span, sub) = if self.token.is_ident_named(sym::of) {
2923 let span = self.token.span;
2925 self.bump();
2926 (span, Some(crate::diagnostics::MissingInInForLoopSub::InNotOf(span)))
2927 } else if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) {
2928 let span = self.prev_token.span;
2929 (span, Some(crate::diagnostics::MissingInInForLoopSub::InNotEq(span)))
2930 } else {
2931 let span = self.prev_token.span.between(self.token.span);
2932 let sub = (!self.for_loop_head_has_in())
2933 .then_some(crate::diagnostics::MissingInInForLoopSub::AddIn(span));
2934 (span, sub)
2935 };
2936
2937 self.dcx().emit_err(crate::diagnostics::MissingInInForLoop { span, sub });
2938 }
2939
2940 fn for_loop_head_has_in(&self) -> bool {
2944 let mut dist = 0;
2945 loop {
2946 let (is_in, is_end) = self.look_ahead(dist, |t| {
2947 (t.is_keyword(kw::In), #[allow(non_exhaustive_omitted_patterns)] match t.kind {
token::OpenBrace | token::Eof => true,
_ => false,
}matches!(t.kind, token::OpenBrace | token::Eof))
2948 });
2949 if is_in {
2950 return true;
2951 }
2952 if is_end {
2953 return false;
2954 }
2955 dist += 1;
2956 }
2957 }
2958
2959 fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
2961 let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2962 let cond = self.parse_expr_cond(policy).map_err(|mut err| {
2963 err.span_label(lo, "while parsing the condition of this `while` expression");
2964 err
2965 })?;
2966 let (attrs, body) = self
2967 .parse_inner_attrs_and_block(
2968 opt_label.is_none().then_some(lo),
2971 )
2972 .map_err(|mut err| {
2973 err.span_label(lo, "while parsing the body of this `while` expression");
2974 err.span_label(cond.span, "this `while` condition successfully parsed");
2975 err
2976 })?;
2977
2978 self.recover_loop_else("while", lo)?;
2979
2980 Ok(self.mk_expr_with_attrs(
2981 lo.to(self.prev_token.span),
2982 ExprKind::While(cond, body, opt_label),
2983 attrs,
2984 ))
2985 }
2986
2987 fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
2989 let loop_span = self.prev_token.span;
2990 let (attrs, body) = self.parse_inner_attrs_and_block(
2991 opt_label.is_none().then_some(lo),
2994 )?;
2995 self.recover_loop_else("loop", lo)?;
2996 Ok(self.mk_expr_with_attrs(
2997 lo.to(self.prev_token.span),
2998 ExprKind::Loop(body, opt_label, loop_span),
2999 attrs,
3000 ))
3001 }
3002
3003 pub(crate) fn eat_label(&mut self) -> Option<Label> {
3004 if let Some((ident, kind)) = self.token.lifetime() {
3005 if kind == IdentKind::Normal && ident.without_first_quote().is_reserved() {
3007 self.dcx().emit_err(crate::diagnostics::KeywordLabel { span: ident.span });
3008 }
3009
3010 self.bump();
3011 Some(Label { ident })
3012 } else {
3013 None
3014 }
3015 }
3016
3017 fn parse_expr_match(&mut self) -> PResult<'a, Box<Expr>> {
3019 let match_span = self.prev_token.span;
3020 let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
3021
3022 self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
3023 }
3024
3025 fn parse_match_block(
3028 &mut self,
3029 lo: Span,
3030 match_span: Span,
3031 scrutinee: Box<Expr>,
3032 match_kind: MatchKind,
3033 ) -> PResult<'a, Box<Expr>> {
3034 if let Err(mut e) = self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
3035 if self.token == token::Semi {
3036 e.span_suggestion_short(
3037 match_span,
3038 "try removing this `match`",
3039 "",
3040 Applicability::MaybeIncorrect, );
3042 }
3043 if self.maybe_recover_unexpected_block_label(None) {
3044 e.cancel();
3045 self.bump();
3046 } else {
3047 return Err(e);
3048 }
3049 }
3050 let attrs = self.parse_inner_attributes()?;
3051
3052 let mut arms = ThinVec::new();
3053 while self.token != token::CloseBrace {
3054 match self.parse_arm() {
3055 Ok(arm) => arms.push(arm),
3056 Err(e) => {
3057 let guar = e.emit_err();
3059 self.recover_stmt();
3060 let span = lo.to(self.token.span);
3061 if self.token == token::CloseBrace {
3062 self.bump();
3063 }
3064 arms.push(Arm {
3066 attrs: Default::default(),
3067 pat: Box::new(self.mk_pat(span, ast::PatKind::Err(guar))),
3068 guard: None,
3069 body: Some(self.mk_expr_err(span, guar)),
3070 span,
3071 id: DUMMY_NODE_ID,
3072 is_placeholder: false,
3073 });
3074 return Ok(self.mk_expr_with_attrs(
3075 span,
3076 ExprKind::Match(scrutinee, arms, match_kind),
3077 attrs,
3078 ));
3079 }
3080 }
3081 }
3082 let hi = self.token.span;
3083 self.bump();
3084 Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
3085 }
3086
3087 fn parse_arm_body_missing_braces(
3089 &mut self,
3090 first_expr: &Box<Expr>,
3091 arrow_span: Span,
3092 ) -> Option<(Span, ErrorGuaranteed)> {
3093 if self.token != token::Semi {
3094 return None;
3095 }
3096 let start_snapshot = self.create_snapshot_for_diagnostic();
3097 let semi_sp = self.token.span;
3098 self.bump(); let mut stmts =
3100 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[self.mk_stmt(first_expr.span,
ast::StmtKind::Expr(first_expr.clone()))]))vec![self.mk_stmt(first_expr.span, ast::StmtKind::Expr(first_expr.clone()))];
3101 let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
3102 let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
3103
3104 let guar = this.dcx().emit_err(crate::diagnostics::MatchArmBodyWithoutBraces {
3105 statements: span,
3106 arrow: arrow_span,
3107 num_statements: stmts.len(),
3108 sub: if stmts.len() > 1 {
3109 crate::diagnostics::MatchArmBodyWithoutBracesSugg::AddBraces {
3110 left: span.shrink_to_lo(),
3111 right: span.shrink_to_hi(),
3112 num_statements: stmts.len(),
3113 }
3114 } else {
3115 crate::diagnostics::MatchArmBodyWithoutBracesSugg::UseComma {
3116 semicolon: semi_sp,
3117 }
3118 },
3119 });
3120 (span, guar)
3121 };
3122 loop {
3125 if self.token == token::CloseBrace {
3126 return Some(err(self, stmts));
3128 }
3129 if self.token == token::Comma {
3130 self.restore_snapshot(start_snapshot);
3131 return None;
3132 }
3133 let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
3134 match self.parse_pat_no_top_alt(None, None) {
3135 Ok(_pat) => {
3136 if self.token == token::FatArrow {
3137 self.restore_snapshot(pre_pat_snapshot);
3139 return Some(err(self, stmts));
3140 }
3141 }
3142 Err(err) => {
3143 err.cancel();
3144 }
3145 }
3146
3147 self.restore_snapshot(pre_pat_snapshot);
3148 match self.parse_stmt_without_recovery(true, ForceCollect::No, false) {
3149 Ok(stmt) => {
3151 stmts.push(stmt);
3152 }
3153 Err(stmt_err) => {
3156 stmt_err.cancel();
3157 self.restore_snapshot(start_snapshot);
3158 break;
3159 }
3160 }
3161 }
3162 None
3163 }
3164
3165 pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
3166 let attrs = self.parse_outer_attributes()?;
3167 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3168 let lo = this.token.span;
3169 let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
3170 let pat = Box::new(pat);
3171
3172 let span_before_body = this.prev_token.span;
3173 let arm_body;
3174 let is_fat_arrow = this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::FatArrow,
token_type: crate::parser::token_type::TokenType::FatArrow,
}exp!(FatArrow));
3175 let is_almost_fat_arrow =
3176 TokenKind::FatArrow.similar_tokens().contains(&this.token.kind);
3177
3178 let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
3181 || #[allow(non_exhaustive_omitted_patterns)] match this.token.kind {
token::Comma | token::CloseBrace => true,
_ => false,
}matches!(this.token.kind, token::Comma | token::CloseBrace);
3182
3183 let mut result = if armless {
3184 arm_body = None;
3186 let span = lo.to(this.prev_token.span);
3187 this.expect_one_of(&[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)], &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)]).map(|x| {
3188 if !pat.contains_never_pattern() {
3190 this.psess.gated_spans.gate(sym::never_patterns, span);
3191 }
3192 x
3193 })
3194 } else {
3195 if let Err(mut err) = this.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::FatArrow,
token_type: crate::parser::token_type::TokenType::FatArrow,
}exp!(FatArrow)) {
3196 if is_almost_fat_arrow {
3198 err.span_suggestion_verbose(
3199 this.token.span,
3200 "use a fat arrow to start a match arm",
3201 "=>",
3202 Applicability::MachineApplicable,
3203 );
3204 if #[allow(non_exhaustive_omitted_patterns)] match (&this.prev_token.kind,
&this.token.kind) {
(token::DotDotEq, token::Gt) => true,
_ => false,
}matches!(
3205 (&this.prev_token.kind, &this.token.kind),
3206 (token::DotDotEq, token::Gt)
3207 ) {
3208 err.delay_as_bug();
3211 } else {
3212 err.emit();
3213 }
3214 this.bump();
3215 } else {
3216 return Err(err);
3217 }
3218 }
3219 let arrow_span = this.prev_token.span;
3220 let arm_start_span = this.token.span;
3221
3222 let expr =
3223 this.parse_expr_res(Restrictions::STMT_EXPR).map_err(|mut err| {
3224 err.span_label(arrow_span, "while parsing the `match` arm starting here");
3225 err
3226 })?;
3227
3228 let require_comma =
3229 !classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
3230
3231 if !require_comma {
3232 arm_body = Some(expr);
3233 let _ = this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3235 Ok(Recovered::No)
3236 } else if let Some((span, guar)) =
3237 this.parse_arm_body_missing_braces(&expr, arrow_span)
3238 {
3239 let body = this.mk_expr_err(span, guar);
3240 arm_body = Some(body);
3241 Ok(Recovered::Yes(guar))
3242 } else {
3243 let expr_span = expr.span;
3244 arm_body = Some(expr);
3245 this.expect_one_of(&[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)], &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)]).map_err(|mut err| {
3246 if this.token == token::FatArrow {
3247 let sm = this.psess.source_map();
3248 if let Ok(expr_lines) = sm.span_to_lines(expr_span)
3249 && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
3250 && expr_lines.lines.len() == 2
3251 {
3252 if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col {
3253 err.span_suggestion_short(
3265 arm_start_span.shrink_to_hi(),
3266 "missing a comma here to end this `match` arm",
3267 ",",
3268 Applicability::MachineApplicable,
3269 );
3270 } else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1)
3271 == expr_lines.lines[0].end_col
3272 {
3273 let comma_span = arm_start_span
3275 .shrink_to_hi()
3276 .with_hi(arm_start_span.hi() + rustc_span::BytePos(1));
3277 if let Ok(res) = sm.span_to_snippet(comma_span)
3278 && (res == "." || res == "/")
3279 {
3280 err.span_suggestion_short(
3281 comma_span,
3282 "you might have meant to write a `,` to end this `match` arm",
3283 ",",
3284 Applicability::MachineApplicable,
3285 );
3286 }
3287 }
3288 }
3289 } else {
3290 err.span_label(
3291 arrow_span,
3292 "while parsing the `match` arm starting here",
3293 );
3294 }
3295 err
3296 })
3297 }
3298 };
3299
3300 let hi_span = arm_body.as_ref().map_or(span_before_body, |body| body.span);
3301 let arm_span = lo.to(hi_span);
3302
3303 let recover_missing_comma = arm_body.is_some() || pat.could_be_never_pattern();
3317 if recover_missing_comma {
3318 result = result.or_else(|err| {
3319 let mut snapshot = this.create_snapshot_for_diagnostic();
3324 let pattern_follows = snapshot
3325 .parse_pat_no_top_guard(
3326 None,
3327 RecoverComma::Yes,
3328 RecoverColon::Yes,
3329 CommaRecoveryMode::EitherTupleOrPipe,
3330 )
3331 .map_err(|err| err.cancel())
3332 .is_ok();
3333 if pattern_follows && snapshot.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::FatArrow,
token_type: crate::parser::token_type::TokenType::FatArrow,
}exp!(FatArrow)) {
3334 err.cancel();
3335 let guar = this.dcx().emit_err(crate::diagnostics::MissingCommaAfterMatchArm {
3336 span: arm_span.shrink_to_hi(),
3337 });
3338 return Ok(Recovered::Yes(guar));
3339 }
3340 Err(err)
3341 });
3342 }
3343 result?;
3344
3345 Ok((
3346 ast::Arm {
3347 attrs,
3348 pat,
3349 guard,
3350 body: arm_body,
3351 span: arm_span,
3352 id: DUMMY_NODE_ID,
3353 is_placeholder: false,
3354 },
3355 Trailing::No,
3356 UsePreAttrPos::No,
3357 ))
3358 })
3359 }
3360
3361 pub(crate) fn eat_metavar_guard(&mut self) -> Option<Box<Guard>> {
3362 self.eat_metavar_seq(MetaVarKind::Guard, |this| {
3363 this.expect_match_arm_guard(ForceCollect::Yes)
3364 })
3365 }
3366
3367 fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Guard>>> {
3368 if let Some(guard) = self.eat_metavar_guard() {
3369 return Ok(Some(guard));
3370 }
3371
3372 if !self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::If,
token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If)) {
3373 return Ok(None);
3375 }
3376 self.expect_match_arm_guard_cond(ForceCollect::No).map(Some)
3377 }
3378
3379 pub(crate) fn expect_match_arm_guard(
3380 &mut self,
3381 force_collect: ForceCollect,
3382 ) -> PResult<'a, Box<Guard>> {
3383 if let Some(guard) = self.eat_metavar_guard() {
3384 return Ok(guard);
3385 }
3386
3387 self.expect_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::If,
token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If))?;
3388 self.expect_match_arm_guard_cond(force_collect)
3389 }
3390
3391 fn expect_match_arm_guard_cond(
3392 &mut self,
3393 force_collect: ForceCollect,
3394 ) -> PResult<'a, Box<Guard>> {
3395 let leading_if_span = self.prev_token.span;
3396
3397 let mut cond = self.parse_match_guard_condition(force_collect)?;
3398 let cond_span = cond.span;
3399
3400 CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3401
3402 let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) };
3403 Ok(Box::new(guard))
3404 }
3405
3406 fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Guard>>)> {
3407 if self.token == token::OpenParen {
3408 let left = self.token.span;
3409 let pat = self.parse_pat_no_top_guard(
3410 None,
3411 RecoverComma::Yes,
3412 RecoverColon::Yes,
3413 CommaRecoveryMode::EitherTupleOrPipe,
3414 )?;
3415 if let ast::PatKind::Paren(subpat) = &pat.kind
3416 && let ast::PatKind::Guard(..) = &subpat.kind
3417 {
3418 let span = pat.span;
3421 let ast::PatKind::Paren(subpat) = pat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3422 let ast::PatKind::Guard(_, mut guard) = subpat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3423 self.psess.gated_spans.ungate_last(sym::guard_patterns, guard.span());
3424 let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3425 checker.visit_expr(&mut guard.cond);
3426
3427 let right = self.prev_token.span;
3428 self.dcx().emit_err(crate::diagnostics::ParenthesesInMatchPat {
3429 span: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[left, right]))vec![left, right],
3430 sugg: crate::diagnostics::ParenthesesInMatchPatSugg { left, right },
3431 });
3432
3433 if let Some(guar) = checker.found_incorrect_let_chain {
3434 guard.cond = *self.mk_expr_err(guard.span(), guar);
3435 }
3436 Ok((self.mk_pat(span, ast::PatKind::Wild), Some(guard)))
3437 } else {
3438 Ok((pat, self.parse_match_arm_guard()?))
3439 }
3440 } else {
3441 let pat = self.parse_pat_no_top_guard(
3443 None,
3444 RecoverComma::Yes,
3445 RecoverColon::Yes,
3446 CommaRecoveryMode::EitherTupleOrPipe,
3447 )?;
3448 Ok((pat, self.parse_match_arm_guard()?))
3449 }
3450 }
3451
3452 fn parse_match_guard_condition(
3453 &mut self,
3454 force_collect: ForceCollect,
3455 ) -> PResult<'a, Box<Expr>> {
3456 let attrs = self.parse_outer_attributes()?;
3457 let expr = self.collect_tokens(
3458 None,
3459 AttrWrapper::empty(),
3460 force_collect,
3461 |this, _empty_attrs| {
3462 match this.parse_expr_res_after_attrs(
3463 Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD,
3464 attrs,
3465 ) {
3466 Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)),
3467 Err(mut err) => {
3468 if this.prev_token == token::OpenBrace {
3469 let sugg_sp = this.prev_token.span.shrink_to_lo();
3470 this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
3473 let msg =
3474 "you might have meant to start a match arm after the match guard";
3475 if this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
3476 let applicability = if this.token != token::FatArrow {
3477 Applicability::MachineApplicable
3482 } else {
3483 Applicability::MaybeIncorrect
3484 };
3485 err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
3486 }
3487 }
3488 Err(err)
3489 }
3490 }
3491 },
3492 )?;
3493 Ok(expr)
3494 }
3495
3496 pub(crate) fn is_builtin(&self) -> bool {
3497 self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
3498 }
3499
3500 fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box<Expr>> {
3502 let annotation =
3503 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::sym::bikeshed,
token_type: crate::parser::token_type::TokenType::SymBikeshed,
}exp!(Bikeshed)) { Some(self.parse_ty()?) } else { None };
3504
3505 let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3506 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Catch,
token_type: crate::parser::token_type::TokenType::KwCatch,
}exp!(Catch)) {
3507 Err(self
3508 .dcx()
3509 .create_err(crate::diagnostics::CatchAfterTry { span: self.prev_token.span }))
3510 } else {
3511 let span = span_lo.to(body.span);
3512 let gate_sym =
3513 if annotation.is_none() { sym::try_blocks } else { sym::try_blocks_heterogeneous };
3514 self.psess.gated_spans.gate(gate_sym, span);
3515 Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body, annotation), attrs))
3516 }
3517 }
3518
3519 fn is_do_catch_block(&self) -> bool {
3520 self.token.is_keyword(kw::Do)
3521 && self.is_keyword_ahead(1, &[kw::Catch])
3522 && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
3523 && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3524 }
3525
3526 fn is_do_yeet(&self) -> bool {
3527 self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
3528 }
3529
3530 fn is_try_block(&self) -> bool {
3531 self.token.is_keyword(kw::Try)
3532 && self.look_ahead(1, |t| {
3533 *t == token::OpenBrace || t.is_metavar_block() || t.is_keyword(sym::bikeshed)
3534 })
3535 && self.token_uninterpolated_span().at_least_rust_2018()
3536 }
3537
3538 fn parse_gen_block(&mut self) -> PResult<'a, Box<Expr>> {
3540 let lo = self.token.span;
3541 let kind = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Async,
token_type: crate::parser::token_type::TokenType::KwAsync,
}exp!(Async)) {
3542 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Gen,
token_type: crate::parser::token_type::TokenType::KwGen,
}exp!(Gen)) { CoroutineKind::AsyncGen } else { CoroutineKind::Async }
3543 } else {
3544 if !self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Gen,
token_type: crate::parser::token_type::TokenType::KwGen,
}) {
::core::panicking::panic("assertion failed: self.eat_keyword(exp!(Gen))")
};assert!(self.eat_keyword(exp!(Gen)));
3545 CoroutineKind::Gen
3546 };
3547 if kind.is_gen() {
3548 self.psess.gated_spans.gate(sym::gen_blocks, lo.to(self.prev_token.span));
3549 }
3550 let capture_clause = self.parse_capture_clause()?;
3551 let decl_span = lo.to(self.prev_token.span);
3552 let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3553 let kind = ExprKind::Gen(capture_clause, body, kind, decl_span);
3554 Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3555 }
3556
3557 fn is_gen_block(&self, kw: Symbol, lookahead: usize) -> bool {
3558 self.is_keyword_ahead(lookahead, &[kw])
3559 && ((
3560 self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
3562 && self.look_ahead(lookahead + 2, |t| {
3563 *t == token::OpenBrace || t.is_metavar_block()
3564 })
3565 ) || (
3566 self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
3568 ))
3569 }
3570
3571 pub(super) fn is_async_gen_block(&self) -> bool {
3572 self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1)
3573 }
3574
3575 fn is_likely_struct_lit(&self) -> bool {
3576 self.look_ahead(1, |t| t.is_ident())
3578 && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
3579 }
3580
3581 fn maybe_parse_struct_expr(
3582 &mut self,
3583 qself: &Option<Box<ast::QSelf>>,
3584 path: &ast::Path,
3585 ) -> Option<PResult<'a, Box<Expr>>> {
3586 let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
3587 match (struct_allowed, self.is_likely_struct_lit()) {
3588 (false, false) => None,
3593 (true, _) => {
3594 if let Err(err) = self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
3597 return Some(Err(err));
3598 }
3599 Some(self.parse_expr_struct(qself.clone(), path.clone(), true))
3600 }
3601 (false, true) => {
3602 let snapshot = self.create_snapshot_for_diagnostic();
3606 if let Err(err) = self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
3607 return Some(Err(err));
3608 }
3609 match self.parse_expr_struct(qself.clone(), path.clone(), false) {
3610 Ok(expr) => {
3611 self.dcx().emit_err(crate::diagnostics::StructLiteralNotAllowedHere {
3613 span: expr.span,
3614 sub: crate::diagnostics::StructLiteralNotAllowedHereSugg {
3615 left: path.span.shrink_to_lo(),
3616 right: expr.span.shrink_to_hi(),
3617 },
3618 });
3619 Some(Ok(expr))
3620 }
3621 Err(err) => {
3622 err.cancel();
3625 self.restore_snapshot(snapshot);
3626 None
3627 }
3628 }
3629 }
3630 }
3631 }
3632
3633 fn maybe_recover_bad_struct_literal_path(
3634 &mut self,
3635 is_underscore_entry_point: bool,
3636 ) -> PResult<'a, Option<Box<Expr>>> {
3637 if self.may_recover()
3638 && self.check_noexpect(&token::OpenBrace)
3639 && (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3640 && self.is_likely_struct_lit())
3641 {
3642 let span = if is_underscore_entry_point {
3643 self.prev_token.span
3644 } else {
3645 self.token.span.shrink_to_lo()
3646 };
3647
3648 self.bump(); let expr = self.parse_expr_struct(
3650 None,
3651 Path::from_ident(Ident::new(kw::Underscore, span)),
3652 false,
3653 )?;
3654
3655 let guar = if is_underscore_entry_point {
3656 self.dcx().emit_err(crate::diagnostics::StructLiteralPlaceholderPath { span })
3657 } else {
3658 self.dcx().emit_err(crate::diagnostics::StructLiteralWithoutPathLate {
3659 span: expr.span,
3660 suggestion_span: expr.span.shrink_to_lo(),
3661 })
3662 };
3663
3664 Ok(Some(self.mk_expr_err(expr.span, guar)))
3665 } else {
3666 Ok(None)
3667 }
3668 }
3669
3670 pub(super) fn parse_struct_fields(
3671 &mut self,
3672 pth: ast::Path,
3673 recover: bool,
3674 close: ExpTokenPair,
3675 ) -> PResult<
3676 'a,
3677 (
3678 ThinVec<ExprField>,
3679 ast::StructRest,
3680 Option<ErrorGuaranteed>, ),
3682 > {
3683 let mut fields = ThinVec::new();
3684 let mut base = ast::StructRest::None;
3685 let mut recovered_async = None;
3686 let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);
3687
3688 let async_block_err = |e: &mut Diag<'_>, span: Span| {
3689 crate::diagnostics::AsyncBlockIn2015 { span }.add_to_diag(e);
3690 crate::diagnostics::HelpUseLatestEdition::new().add_to_diag(e);
3691 };
3692
3693 while self.token != close.tok {
3694 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::DotDot,
token_type: crate::parser::token_type::TokenType::DotDot,
}exp!(DotDot)) || self.recover_struct_field_dots(&close.tok) {
3695 let exp_span = self.prev_token.span;
3696 if self.check(close) {
3698 base = ast::StructRest::Rest(self.prev_token.span);
3699 break;
3700 }
3701 match self.parse_expr() {
3702 Ok(e) => base = ast::StructRest::Base(e),
3703 Err(e) if recover => {
3704 e.emit();
3705 self.recover_stmt();
3706 }
3707 Err(e) => return Err(e),
3708 }
3709 self.recover_struct_comma_after_dotdot(exp_span);
3710 break;
3711 }
3712
3713 let peek = self
3715 .token
3716 .non_reserved_ident()
3717 .filter(|_| self.look_ahead(1, |&tok| tok == token::Colon));
3718
3719 let field_ident = |this: &Self, guar: ErrorGuaranteed| {
3721 peek.map(|ident| {
3722 let span = ident.span;
3723 ExprField {
3724 ident,
3725 span,
3726 expr: this.mk_expr_err(span, guar),
3727 is_shorthand: false,
3728 attrs: AttrVec::new(),
3729 id: DUMMY_NODE_ID,
3730 is_placeholder: false,
3731 }
3732 })
3733 };
3734
3735 let parsed_field = match self.parse_expr_field() {
3736 Ok(f) => Ok(f),
3737 Err(mut e) => {
3738 if pth == kw::Async {
3739 async_block_err(&mut e, pth.span);
3740 } else {
3741 e.span_label(pth.span, "while parsing this struct");
3742 }
3743
3744 if let Some((ident, _)) = self.token.ident()
3745 && !self.token.is_reserved_ident()
3746 && self.look_ahead(1, |t| {
3747 AssocOp::from_token(t).is_some()
3748 || #[allow(non_exhaustive_omitted_patterns)] match t.kind {
token::OpenParen | token::OpenBracket | token::OpenBrace => true,
_ => false,
}matches!(
3749 t.kind,
3750 token::OpenParen | token::OpenBracket | token::OpenBrace
3751 )
3752 || *t == token::Dot
3753 })
3754 {
3755 e.span_suggestion_verbose(
3758 self.token.span.shrink_to_lo(),
3759 "try naming a field",
3760 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: ", ident))
})format!("{ident}: ",),
3761 Applicability::MaybeIncorrect,
3762 );
3763 }
3764 if in_if_guard && close.token_type == TokenType::CloseBrace {
3765 return Err(e);
3766 }
3767
3768 if !recover {
3769 return Err(e);
3770 }
3771
3772 let guar = e.emit_err();
3773 if pth == kw::Async {
3774 recovered_async = Some(guar);
3775 }
3776
3777 base = ast::StructRest::NoneWithError(guar);
3785
3786 if self.token != token::Comma {
3790 self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3791 if self.token != token::Comma {
3792 break;
3793 }
3794 }
3795
3796 Err(guar)
3797 }
3798 };
3799
3800 let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
3801 self.check_or_expected(!is_shorthand, TokenType::Colon);
3804
3805 match self.expect_one_of(&[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)], &[close]) {
3806 Ok(_) => {
3807 if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
3808 {
3809 fields.push(f);
3811 }
3812 }
3813 Err(mut e) => {
3814 if pth == kw::Async {
3815 async_block_err(&mut e, pth.span);
3816 } else {
3817 e.span_label(pth.span, "while parsing this struct");
3818 if peek.is_some() {
3819 e.span_suggestion(
3820 self.prev_token.span.shrink_to_hi(),
3821 "try adding a comma",
3822 ",",
3823 Applicability::MachineApplicable,
3824 );
3825 }
3826 }
3827 if !recover {
3828 return Err(e);
3829 }
3830 let guar = e.emit_err();
3831 if pth == kw::Async {
3832 recovered_async = Some(guar);
3833 } else if let Some(f) = field_ident(self, guar) {
3834 fields.push(f);
3835 }
3836
3837 base = ast::StructRest::NoneWithError(guar);
3839
3840 self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3841 let _ = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3842 }
3843 }
3844 }
3845 Ok((fields, base, recovered_async))
3846 }
3847
3848 pub(super) fn parse_expr_struct(
3850 &mut self,
3851 qself: Option<Box<ast::QSelf>>,
3852 pth: ast::Path,
3853 recover: bool,
3854 ) -> PResult<'a, Box<Expr>> {
3855 let lo = pth.span;
3856 let (fields, base, recovered_async) =
3857 self.parse_struct_fields(pth.clone(), recover, crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace))?;
3858 let span = lo.to(self.token.span);
3859 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace))?;
3860 let expr = if let Some(guar) = recovered_async {
3861 ExprKind::Err(guar)
3862 } else {
3863 ExprKind::Struct(Box::new(ast::StructExpr { qself, path: pth, fields, rest: base }))
3864 };
3865 Ok(self.mk_expr(span, expr))
3866 }
3867
3868 fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
3869 if self.token != token::Comma {
3870 return;
3871 }
3872 self.dcx().emit_err(crate::diagnostics::CommaAfterBaseStruct {
3873 span: span.to(self.prev_token.span),
3874 comma: self.token.span,
3875 });
3876 self.recover_stmt();
3877 }
3878
3879 fn recover_struct_field_dots(&mut self, close: &TokenKind) -> bool {
3880 if !self.look_ahead(1, |t| t == close) && self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::DotDotDot,
token_type: crate::parser::token_type::TokenType::DotDotDot,
}exp!(DotDotDot)) {
3881 let span = self.prev_token.span;
3883 self.dcx()
3884 .emit_err(crate::diagnostics::MissingDotDot { token_span: span, sugg_span: span });
3885 return true;
3886 }
3887 false
3888 }
3889
3890 fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
3892 let label = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}", ident.name))
})format!("'{}", ident.name);
3895 let ident = Ident::new(Symbol::intern(&label), ident.span);
3896
3897 self.dcx().emit_err(crate::diagnostics::ExpectedLabelFoundIdent {
3898 span: ident.span,
3899 start: ident.span.shrink_to_lo(),
3900 });
3901
3902 Label { ident }
3903 }
3904
3905 fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
3907 let attrs = self.parse_outer_attributes()?;
3908 self.recover_vcs_conflict_marker();
3909 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3910 let lo = this.token.span;
3911
3912 let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
3914 let is_wrong = this.token.is_non_reserved_ident()
3916 && !this.look_ahead(1, |t| {
3917 t == &token::Colon
3918 || t == &token::Eq
3919 || t == &token::Comma
3920 || t == &token::CloseBrace
3921 || t == &token::CloseParen
3922 });
3923 if is_wrong {
3924 return Err(this.dcx().create_err(crate::diagnostics::ExpectedStructField {
3925 span: this.look_ahead(1, |t| t.span),
3926 ident_span: this.token.span,
3927 token: pprust::token_to_string(&this.look_ahead(1, |t| *t)),
3928 }));
3929 }
3930 let (ident, expr) = if is_shorthand {
3931 let ident = this.parse_ident_common(false)?;
3933 let path = ast::Path::from_ident(ident);
3934 (ident, this.mk_expr(ident.span, ExprKind::Path(None, path)))
3935 } else {
3936 let ident = this.parse_field_name()?;
3937 this.error_on_eq_field_init(ident);
3938 this.bump(); (ident, this.parse_expr()?)
3940 };
3941
3942 Ok((
3943 ast::ExprField {
3944 ident,
3945 span: lo.to(expr.span),
3946 expr,
3947 is_shorthand,
3948 attrs,
3949 id: DUMMY_NODE_ID,
3950 is_placeholder: false,
3951 },
3952 Trailing::from(this.token == token::Comma),
3953 UsePreAttrPos::No,
3954 ))
3955 })
3956 }
3957
3958 fn error_on_eq_field_init(&self, field_name: Ident) {
3961 if self.token != token::Eq {
3962 return;
3963 }
3964
3965 self.dcx().emit_err(crate::diagnostics::EqFieldInit {
3966 span: self.token.span,
3967 eq: field_name.span.shrink_to_hi().to(self.token.span),
3968 });
3969 }
3970
3971 fn mk_assign_op(&self, assign_op: AssignOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
3972 ExprKind::AssignOp(assign_op, lhs, rhs)
3973 }
3974
3975 fn mk_range(
3976 &mut self,
3977 start: Option<Box<Expr>>,
3978 end: Option<Box<Expr>>,
3979 limits: RangeLimits,
3980 ) -> ExprKind {
3981 if end.is_none() && limits == RangeLimits::Closed {
3982 let guar = self.inclusive_range_with_incorrect_end();
3983 ExprKind::Err(guar)
3984 } else {
3985 ExprKind::Range(start, end, limits)
3986 }
3987 }
3988
3989 fn mk_unary(&self, unop: UnOp, expr: Box<Expr>) -> ExprKind {
3990 ExprKind::Unary(unop, expr)
3991 }
3992
3993 fn mk_binary(&self, binop: BinOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
3994 ExprKind::Binary(binop, lhs, rhs)
3995 }
3996
3997 fn mk_index(&self, expr: Box<Expr>, idx: Box<Expr>, brackets_span: Span) -> ExprKind {
3998 ExprKind::Index(expr, idx, brackets_span)
3999 }
4000
4001 fn mk_call(&self, f: Box<Expr>, args: ThinVec<Box<Expr>>) -> ExprKind {
4002 ExprKind::Call(f, args)
4003 }
4004
4005 fn mk_await_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4006 let span = lo.to(self.prev_token.span);
4007 let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
4008 self.recover_from_await_method_call();
4009 await_expr
4010 }
4011
4012 fn mk_use_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4013 let span = lo.to(self.prev_token.span);
4014 let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
4015 self.recover_from_use();
4016 use_expr
4017 }
4018
4019 pub(crate) fn mk_expr_with_attrs(
4020 &self,
4021 span: Span,
4022 kind: ExprKind,
4023 attrs: AttrVec,
4024 ) -> Box<Expr> {
4025 Box::new(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
4026 }
4027
4028 pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> Box<Expr> {
4029 self.mk_expr_with_attrs(span, kind, AttrVec::new())
4030 }
4031
4032 pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Expr> {
4033 self.mk_expr(span, ExprKind::Err(guar))
4034 }
4035
4036 pub(crate) fn mk_unit_expr(&self, span: Span) -> Box<Expr> {
4037 self.mk_expr(span, ExprKind::Tup(Default::default()))
4038 }
4039
4040 pub(crate) fn mk_closure_expr(&self, span: Span, body: Box<Expr>) -> Box<Expr> {
4041 self.mk_expr(
4042 span,
4043 ast::ExprKind::Closure(Box::new(ast::Closure {
4044 binder: rustc_ast::ClosureBinder::NotPresent,
4045 constness: rustc_ast::Const::No,
4046 movability: rustc_ast::Movability::Movable,
4047 capture_clause: rustc_ast::CaptureBy::Ref,
4048 coroutine_marker: None,
4049 fn_decl: Box::new(rustc_ast::FnDecl {
4050 inputs: Default::default(),
4051 output: rustc_ast::FnRetTy::Default(span),
4052 }),
4053 fn_arg_span: span,
4054 fn_decl_span: span,
4055 body,
4056 })),
4057 )
4058 }
4059
4060 fn mk_expr_sp(&self, lhs: &Box<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span {
4063 lhs.attrs
4064 .iter()
4065 .find(|a| a.style == AttrStyle::Outer)
4066 .map_or(lhs_span, |a| a.span)
4067 .to(op_span)
4068 .to(rhs_span)
4069 }
4070
4071 fn collect_tokens_for_expr(
4072 &mut self,
4073 attrs: AttrWrapper,
4074 f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, Box<Expr>>,
4075 ) -> PResult<'a, Box<Expr>> {
4076 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4077 let res = f(this, attrs)?;
4078 let trailing = Trailing::from(
4079 this.restrictions.contains(Restrictions::STMT_EXPR)
4080 && this.token == token::Semi
4081 || this.token == token::Comma,
4085 );
4086 Ok((res, trailing, UsePreAttrPos::No))
4087 })
4088 }
4089}
4090
4091pub(crate) fn could_be_unclosed_char_literal(ident: Ident) -> bool {
4094 ident.name.as_str().starts_with('\'')
4095 && unescape_char(ident.without_first_quote().name.as_str()).is_ok()
4096}
4097
4098pub enum LetChainsPolicy {
4101 AlwaysAllowed,
4102 EditionDependent { current_edition: Edition },
4103}
4104
4105struct CondChecker<'a> {
4115 parser: &'a Parser<'a>,
4116 let_chains_policy: LetChainsPolicy,
4117 depth: u32,
4118 forbid_let_reason: Option<crate::diagnostics::ForbiddenLetReason>,
4119 missing_let: Option<crate::diagnostics::MaybeMissingLet>,
4120 comparison: Option<crate::diagnostics::MaybeComparison>,
4121 found_incorrect_let_chain: Option<ErrorGuaranteed>,
4122}
4123
4124impl<'a> CondChecker<'a> {
4125 fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4126 CondChecker {
4127 parser,
4128 forbid_let_reason: None,
4129 missing_let: None,
4130 comparison: None,
4131 let_chains_policy,
4132 found_incorrect_let_chain: None,
4133 depth: 0,
4134 }
4135 }
4136}
4137
4138impl MutVisitor for CondChecker<'_> {
4139 fn visit_expr(&mut self, e: &mut Expr) {
4140 self.depth += 1;
4141
4142 let span = e.span;
4143 match e.kind {
4144 ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
4145 if let Some(reason) = self.forbid_let_reason {
4146 let error = match reason {
4147 crate::diagnostics::ForbiddenLetReason::NotSupportedOr(or_span) => self
4148 .parser
4149 .dcx()
4150 .emit_err(crate::diagnostics::OrInLetChain { span: or_span }),
4151 _ => {
4152 let guar = self.parser.dcx().emit_err(
4153 crate::diagnostics::ExpectedExpressionFoundLet {
4154 span,
4155 reason,
4156 missing_let: self.missing_let,
4157 comparison: self.comparison,
4158 },
4159 );
4160 if let Some(_) = self.missing_let {
4161 self.found_incorrect_let_chain = Some(guar);
4162 }
4163 guar
4164 }
4165 };
4166 *recovered = Recovered::Yes(error);
4167 } else if self.depth > 1 {
4168 match self.let_chains_policy {
4170 LetChainsPolicy::AlwaysAllowed => (),
4171 LetChainsPolicy::EditionDependent { current_edition } => {
4172 if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4173 self.parser
4174 .dcx()
4175 .emit_err(crate::diagnostics::LetChainPre2024 { span });
4176 }
4177 }
4178 }
4179 }
4180 }
4181 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
4182 mut_visit::walk_expr(self, e);
4183 }
4184 ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
4185 if let None | Some(crate::diagnostics::ForbiddenLetReason::NotSupportedOr(_)) =
4186 self.forbid_let_reason =>
4187 {
4188 let forbid_let_reason = self.forbid_let_reason;
4189 self.forbid_let_reason =
4190 Some(crate::diagnostics::ForbiddenLetReason::NotSupportedOr(or_span));
4191 mut_visit::walk_expr(self, e);
4192 self.forbid_let_reason = forbid_let_reason;
4193 }
4194 ExprKind::Paren(ref inner)
4195 if let None
4196 | Some(crate::diagnostics::ForbiddenLetReason::NotSupportedParentheses(_)) =
4197 self.forbid_let_reason =>
4198 {
4199 let forbid_let_reason = self.forbid_let_reason;
4200 self.forbid_let_reason = Some(
4201 crate::diagnostics::ForbiddenLetReason::NotSupportedParentheses(inner.span),
4202 );
4203 mut_visit::walk_expr(self, e);
4204 self.forbid_let_reason = forbid_let_reason;
4205 }
4206 ExprKind::Assign(ref lhs, ref rhs, span) => {
4207 if let ExprKind::Call(_, _) = &lhs.kind {
4208 fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
4209 fn inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
4210 match &e.kind {
4211 ExprKind::Binary(_, lhs, _) => inner(lhs, depth + 1),
4212 ExprKind::Path(_, path) => Some((depth, path)),
4213 _ => None,
4214 }
4215 }
4216
4217 inner(e, 0)
4218 }
4219
4220 if let Some((depth, path)) = get_path_from_rhs(rhs) {
4221 fn find_let_some(expr: &Expr) -> Option<&Expr> {
4224 match &expr.kind {
4225 ExprKind::Let(..) => Some(expr),
4226
4227 ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => {
4228 find_let_some(lhs).or_else(|| find_let_some(rhs))
4229 }
4230
4231 _ => None,
4232 }
4233 }
4234
4235 let expr_span = lhs.span.to(path.span);
4236
4237 if let Some(later_rhs) = find_let_some(rhs)
4238 && depth > 0
4239 {
4240 let guar = self.parser.dcx().emit_err(
4241 crate::diagnostics::LetChainMissingLet {
4242 span: lhs.span,
4243 label_span: expr_span,
4244 rhs_span: later_rhs.span,
4245 sug_span: lhs.span.shrink_to_lo(),
4246 },
4247 );
4248
4249 self.found_incorrect_let_chain = Some(guar);
4250 }
4251 }
4252 }
4253
4254 let forbid_let_reason = self.forbid_let_reason;
4255 self.forbid_let_reason =
4256 Some(crate::diagnostics::ForbiddenLetReason::OtherForbidden);
4257 let missing_let = self.missing_let;
4258 if let ExprKind::Binary(_, _, rhs) = &lhs.kind
4259 && let ExprKind::Path(_, _)
4260 | ExprKind::Struct(_)
4261 | ExprKind::Call(_, _)
4262 | ExprKind::Array(_) = rhs.kind
4263 {
4264 self.missing_let =
4265 Some(crate::diagnostics::MaybeMissingLet { span: rhs.span.shrink_to_lo() });
4266 }
4267 let comparison = self.comparison;
4268 self.comparison =
4269 Some(crate::diagnostics::MaybeComparison { span: span.shrink_to_hi() });
4270 mut_visit::walk_expr(self, e);
4271 self.forbid_let_reason = forbid_let_reason;
4272 self.missing_let = missing_let;
4273 self.comparison = comparison;
4274 }
4275 ExprKind::Unary(_, _)
4276 | ExprKind::Await(_, _)
4277 | ExprKind::Move(_, _)
4278 | ExprKind::Use(_, _)
4279 | ExprKind::AssignOp(_, _, _)
4280 | ExprKind::Range(_, _, _)
4281 | ExprKind::Try(_)
4282 | ExprKind::AddrOf(_, _, _)
4283 | ExprKind::Binary(_, _, _)
4284 | ExprKind::Field(_, _)
4285 | ExprKind::Index(_, _, _)
4286 | ExprKind::Call(_, _)
4287 | ExprKind::MethodCall(_)
4288 | ExprKind::Tup(_)
4289 | ExprKind::Paren(_) => {
4290 let forbid_let_reason = self.forbid_let_reason;
4291 self.forbid_let_reason =
4292 Some(crate::diagnostics::ForbiddenLetReason::OtherForbidden);
4293 mut_visit::walk_expr(self, e);
4294 self.forbid_let_reason = forbid_let_reason;
4295 }
4296 ExprKind::Cast(ref mut op, _)
4297 | ExprKind::Type(ref mut op, _)
4298 | ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
4299 let forbid_let_reason = self.forbid_let_reason;
4300 self.forbid_let_reason =
4301 Some(crate::diagnostics::ForbiddenLetReason::OtherForbidden);
4302 self.visit_expr(op);
4303 self.forbid_let_reason = forbid_let_reason;
4304 }
4305 ExprKind::Let(_, _, _, Recovered::Yes(_))
4306 | ExprKind::Array(_)
4307 | ExprKind::ConstBlock(_)
4308 | ExprKind::Lit(_)
4309 | ExprKind::If(_, _, _)
4310 | ExprKind::While(_, _, _)
4311 | ExprKind::ForLoop { .. }
4312 | ExprKind::Loop(_, _, _)
4313 | ExprKind::Match(_, _, _)
4314 | ExprKind::Closure(_)
4315 | ExprKind::Block(_, _)
4316 | ExprKind::Gen(_, _, _, _)
4317 | ExprKind::TryBlock(_, _)
4318 | ExprKind::Underscore
4319 | ExprKind::Path(_, _)
4320 | ExprKind::Break(_, _)
4321 | ExprKind::Continue(_)
4322 | ExprKind::Ret(_)
4323 | ExprKind::InlineAsm(_)
4324 | ExprKind::OffsetOf(_, _)
4325 | ExprKind::MacCall(_)
4326 | ExprKind::Struct(_)
4327 | ExprKind::Repeat(_, _)
4328 | ExprKind::Yield(_)
4329 | ExprKind::Yeet(_)
4330 | ExprKind::Become(_)
4331 | ExprKind::IncludedBytes(_)
4332 | ExprKind::FormatArgs(_)
4333 | ExprKind::Err(_)
4334 | ExprKind::DirectConstArg(_)
4335 | ExprKind::Dummy => {
4336 }
4338 }
4339 self.depth -= 1;
4340 }
4341}