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