1use core::mem;
4use core::ops::{Bound, ControlFlow};
5
6use ast::mut_visit::{self, MutVisitor};
7use ast::token::IdentIsRaw;
8use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
9use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind};
10use rustc_ast::tokenstream::TokenTree;
11use rustc_ast::util::case::Case;
12use rustc_ast::util::classify;
13use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
14use rustc_ast::visit::{Visitor, walk_expr};
15use rustc_ast::{
16 self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
17 BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl,
18 FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits,
19 StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
20};
21use rustc_data_structures::stack::ensure_sufficient_stack;
22use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
23use rustc_literal_escaper::unescape_char;
24use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};
25use rustc_session::lint::BuiltinLintDiag;
26use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
27use rustc_span::edition::Edition;
28use rustc_span::source_map::{self, Spanned};
29use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Symbol, kw, sym};
30use thin_vec::{ThinVec, thin_vec};
31use tracing::instrument;
32
33use super::diagnostics::SnapshotParser;
34use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
35use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
36use super::{
37 AttrWrapper, BlockMode, ClosureSpans, ExpTokenPair, ForceCollect, Parser, PathStyle,
38 Restrictions, SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,
39};
40use crate::{errors, exp, maybe_recover_from_interpolated_ty_qpath};
41
42#[derive(#[automatically_derived]
impl ::core::fmt::Debug for DestructuredFloat {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
DestructuredFloat::Single(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f, "Single",
__self_0, &__self_1),
DestructuredFloat::TrailingDot(__self_0, __self_1, __self_2) =>
::core::fmt::Formatter::debug_tuple_field3_finish(f,
"TrailingDot", __self_0, __self_1, &__self_2),
DestructuredFloat::MiddleDot(__self_0, __self_1, __self_2,
__self_3, __self_4) =>
::core::fmt::Formatter::debug_tuple_field5_finish(f,
"MiddleDot", __self_0, __self_1, __self_2, __self_3,
&__self_4),
DestructuredFloat::Error =>
::core::fmt::Formatter::write_str(f, "Error"),
}
}
}Debug)]
43pub(super) enum DestructuredFloat {
44 Single(Symbol, Span),
46 TrailingDot(Symbol, Span, Span),
48 MiddleDot(Symbol, Span, Span, Symbol, Span),
50 Error,
52}
53
54impl<'a> Parser<'a> {
55 #[inline]
57 pub fn parse_expr(&mut self) -> PResult<'a, Box<Expr>> {
58 self.current_closure.take();
59
60 let attrs = self.parse_outer_attributes()?;
61 self.parse_expr_res(Restrictions::empty(), attrs).map(|res| res.0)
62 }
63
64 pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box<Expr>> {
66 self.current_closure.take();
67
68 let pre_attr_pos = self.collect_pos();
73 let attrs = self.parse_outer_attributes()?;
74 self.collect_tokens(
75 Some(pre_attr_pos),
76 AttrWrapper::empty(),
77 ForceCollect::Yes,
78 |this, _empty_attrs| {
79 let (expr, is_assoc) = this.parse_expr_res(Restrictions::empty(), attrs)?;
80 let use_pre_attr_pos =
81 if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };
82 Ok((expr, Trailing::No, use_pre_attr_pos))
83 },
84 )
85 }
86
87 pub fn parse_expr_anon_const(
88 &mut self,
89 mgca_disambiguation: impl FnOnce(&Self, &Expr) -> MgcaDisambiguation,
90 ) -> PResult<'a, AnonConst> {
91 self.parse_expr().map(|value| AnonConst {
92 id: DUMMY_NODE_ID,
93 mgca_disambiguation: mgca_disambiguation(self, &value),
94 value,
95 })
96 }
97
98 fn parse_expr_catch_underscore(
99 &mut self,
100 restrictions: Restrictions,
101 ) -> PResult<'a, Box<Expr>> {
102 let attrs = self.parse_outer_attributes()?;
103 match self.parse_expr_res(restrictions, attrs) {
104 Ok((expr, _)) => Ok(expr),
105 Err(err) => match self.token.ident() {
106 Some((Ident { name: kw::Underscore, .. }, IdentIsRaw::No))
107 if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>
108 {
109 let guar = err.emit();
111 self.bump();
112 Ok(self.mk_expr(self.prev_token.span, ExprKind::Err(guar)))
113 }
114 _ => Err(err),
115 },
116 }
117 }
118
119 fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<Box<Expr>>> {
121 self.parse_paren_comma_seq(|p| p.parse_expr_catch_underscore(Restrictions::empty()))
122 .map(|(r, _)| r)
123 }
124
125 #[inline]
127 pub(super) fn parse_expr_res(
128 &mut self,
129 r: Restrictions,
130 attrs: AttrWrapper,
131 ) -> PResult<'a, (Box<Expr>, bool)> {
132 self.with_res(r, |this| this.parse_expr_assoc_with(Bound::Unbounded, attrs))
133 }
134
135 pub(super) fn parse_expr_assoc_with(
139 &mut self,
140 min_prec: Bound<ExprPrecedence>,
141 attrs: AttrWrapper,
142 ) -> PResult<'a, (Box<Expr>, bool)> {
143 let lhs = if self.token.is_range_separator() {
144 return self.parse_expr_prefix_range(attrs).map(|res| (res, false));
145 } else {
146 self.parse_expr_prefix(attrs)?
147 };
148 self.parse_expr_assoc_rest_with(min_prec, false, lhs)
149 }
150
151 pub(super) fn parse_expr_assoc_rest_with(
155 &mut self,
156 min_prec: Bound<ExprPrecedence>,
157 starts_stmt: bool,
158 mut lhs: Box<Expr>,
159 ) -> PResult<'a, (Box<Expr>, bool)> {
160 let mut parsed_something = false;
161 if !self.should_continue_as_assoc_expr(&lhs) {
162 return Ok((lhs, parsed_something));
163 }
164
165 self.expected_token_types.insert(TokenType::Operator);
166 while let Some(op) = self.check_assoc_op() {
167 let lhs_span = self.interpolated_or_expr_span(&lhs);
168 let cur_op_span = self.token.span;
169 let restrictions = if op.node.is_assign_like() {
170 self.restrictions & Restrictions::NO_STRUCT_LITERAL
171 } else {
172 self.restrictions
173 };
174 let prec = op.node.precedence();
175 if match min_prec {
176 Bound::Included(min_prec) => prec < min_prec,
177 Bound::Excluded(min_prec) => prec <= min_prec,
178 Bound::Unbounded => false,
179 } {
180 break;
181 }
182 if self.token == token::DotDotDot && op.node == AssocOp::Range(RangeLimits::Closed) {
184 self.err_dotdotdot_syntax(self.token.span);
185 }
186
187 if self.token == token::LArrow {
188 self.err_larrow_operator(self.token.span);
189 }
190
191 parsed_something = true;
192 self.bump();
193 if op.node.is_comparison() {
194 if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
195 return Ok((expr, parsed_something));
196 }
197 }
198
199 if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node
201 && self.token == token::Eq
202 && self.prev_token.span.hi() == self.token.span.lo()
203 {
204 let sp = op.span.to(self.token.span);
205 let sugg = bop.as_str().into();
206 let invalid = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}=", sugg))
})format!("{sugg}=");
207 self.dcx().emit_err(errors::InvalidComparisonOperator {
208 span: sp,
209 invalid: invalid.clone(),
210 sub: errors::InvalidComparisonOperatorSub::Correctable {
211 span: sp,
212 invalid,
213 correct: sugg,
214 },
215 });
216 self.bump();
217 }
218
219 if op.node == AssocOp::Binary(BinOpKind::Lt)
221 && self.token == token::Gt
222 && self.prev_token.span.hi() == self.token.span.lo()
223 {
224 let sp = op.span.to(self.token.span);
225 self.dcx().emit_err(errors::InvalidComparisonOperator {
226 span: sp,
227 invalid: "<>".into(),
228 sub: errors::InvalidComparisonOperatorSub::Correctable {
229 span: sp,
230 invalid: "<>".into(),
231 correct: "!=".into(),
232 },
233 });
234 self.bump();
235 }
236
237 if op.node == AssocOp::Binary(BinOpKind::Le)
239 && self.token == token::Gt
240 && self.prev_token.span.hi() == self.token.span.lo()
241 {
242 let sp = op.span.to(self.token.span);
243 self.dcx().emit_err(errors::InvalidComparisonOperator {
244 span: sp,
245 invalid: "<=>".into(),
246 sub: errors::InvalidComparisonOperatorSub::Spaceship(sp),
247 });
248 self.bump();
249 }
250
251 if self.prev_token == token::Plus
252 && self.token == token::Plus
253 && self.prev_token.span.between(self.token.span).is_empty()
254 {
255 let op_span = self.prev_token.span.to(self.token.span);
256 self.bump();
258 lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?;
259 continue;
260 }
261
262 if self.prev_token == token::Minus
263 && self.token == token::Minus
264 && self.prev_token.span.between(self.token.span).is_empty()
265 && !self.look_ahead(1, |tok| tok.can_begin_expr())
266 {
267 let op_span = self.prev_token.span.to(self.token.span);
268 self.bump();
270 lhs = self.recover_from_postfix_decrement(lhs, op_span, starts_stmt)?;
271 continue;
272 }
273
274 let op_span = op.span;
275 let op = op.node;
276 if op == AssocOp::Cast {
278 lhs = self.parse_assoc_op_cast(lhs, lhs_span, op_span, ExprKind::Cast)?;
279 continue;
280 } else if let AssocOp::Range(limits) = op {
281 lhs = self.parse_expr_range(prec, lhs, limits, cur_op_span)?;
284 break;
285 }
286
287 let min_prec = match op.fixity() {
288 Fixity::Right => Bound::Included(prec),
289 Fixity::Left | Fixity::None => Bound::Excluded(prec),
290 };
291 let (rhs, _) = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
292 let attrs = this.parse_outer_attributes()?;
293 this.parse_expr_assoc_with(min_prec, attrs)
294 })?;
295
296 let span = self.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);
297 lhs = match op {
298 AssocOp::Binary(ast_op) => {
299 let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs);
300 self.mk_expr(span, binary)
301 }
302 AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)),
303 AssocOp::AssignOp(aop) => {
304 let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
305 self.mk_expr(span, aopexpr)
306 }
307 AssocOp::Cast | AssocOp::Range(_) => {
308 self.dcx().span_bug(span, "AssocOp should have been handled by special case")
309 }
310 };
311 }
312
313 Ok((lhs, parsed_something))
314 }
315
316 fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
317 match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) {
318 (true, None) => false,
321 (false, _) => true, (true, Some(AssocOp::Binary(
326 BinOpKind::Mul | BinOpKind::Sub | BinOpKind::Add | BinOpKind::And | BinOpKind::Or | BinOpKind::BitOr ))) => {
333 let sp = self.psess.source_map().start_point(self.token.span);
340 self.psess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
341 false
342 }
343 (true, Some(op)) if !op.can_continue_expr_unambiguously() => false,
344 (true, Some(_)) => {
345 self.error_found_expr_would_be_stmt(lhs);
346 true
347 }
348 }
349 }
350
351 fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
355 self.dcx().emit_err(errors::FoundExprWouldBeStmt {
356 span: self.token.span,
357 token: self.token,
358 suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
359 });
360 }
361
362 pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
367 let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
368 (
370 Some(
371 AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
372 | AssocOp::AssignOp(AssignOpKind::ShrAssign),
373 ),
374 _,
375 ) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
376 return None;
377 }
378 (
381 Some(
382 AssocOp::Assign
383 | AssocOp::AssignOp(_)
384 | AssocOp::Binary(BinOpKind::BitOr)
385 | AssocOp::Range(_),
386 ),
387 _,
388 ) if self.restrictions.contains(Restrictions::IS_PAT) => {
389 return None;
390 }
391 (Some(op), _) => (op, self.token.span),
392 (None, Some((Ident { name: sym::and, span }, IdentIsRaw::No)))
393 if self.may_recover() =>
394 {
395 self.dcx().emit_err(errors::InvalidLogicalOperator {
396 span: self.token.span,
397 incorrect: "and".into(),
398 sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span),
399 });
400 (AssocOp::Binary(BinOpKind::And), span)
401 }
402 (None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => {
403 self.dcx().emit_err(errors::InvalidLogicalOperator {
404 span: self.token.span,
405 incorrect: "or".into(),
406 sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span),
407 });
408 (AssocOp::Binary(BinOpKind::Or), span)
409 }
410 _ => return None,
411 };
412 Some(source_map::respan(span, op))
413 }
414
415 fn expr_is_complete(&self, e: &Expr) -> bool {
417 self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)
418 }
419
420 fn parse_expr_range(
423 &mut self,
424 prec: ExprPrecedence,
425 lhs: Box<Expr>,
426 limits: RangeLimits,
427 cur_op_span: Span,
428 ) -> PResult<'a, Box<Expr>> {
429 let rhs = if self.is_at_start_of_range_notation_rhs() {
430 let maybe_lt = self.token;
431 let attrs = self.parse_outer_attributes()?;
432 Some(
433 self.parse_expr_assoc_with(Bound::Excluded(prec), attrs)
434 .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?
435 .0,
436 )
437 } else {
438 None
439 };
440 let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
441 let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span);
442 let range = self.mk_range(Some(lhs), rhs, limits);
443 Ok(self.mk_expr(span, range))
444 }
445
446 fn is_at_start_of_range_notation_rhs(&self) -> bool {
447 if self.token.can_begin_expr() {
448 if self.token == token::OpenBrace {
450 return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
451 }
452 true
453 } else {
454 false
455 }
456 }
457
458 fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
460 if !attrs.is_empty() {
461 let err = errors::DotDotRangeAttribute { span: self.token.span };
462 self.dcx().emit_err(err);
463 }
464
465 if self.token == token::DotDotDot {
467 self.err_dotdotdot_syntax(self.token.span);
468 }
469
470 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!(
471 self.token.is_range_separator(),
472 "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
473 self.token
474 );
475
476 let limits = match self.token.kind {
477 token::DotDot => RangeLimits::HalfOpen,
478 _ => RangeLimits::Closed,
479 };
480 let op = AssocOp::from_token(&self.token);
481 let attrs = self.parse_outer_attributes()?;
482 self.collect_tokens_for_expr(attrs, |this, attrs| {
483 let lo = this.token.span;
484 let maybe_lt = this.look_ahead(1, |t| t.clone());
485 this.bump();
486 let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
487 let attrs = this.parse_outer_attributes()?;
489 this.parse_expr_assoc_with(Bound::Excluded(op.unwrap().precedence()), attrs)
490 .map(|(x, _)| (lo.to(x.span), Some(x)))
491 .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
492 } else {
493 (lo, None)
494 };
495 let range = this.mk_range(None, opt_end, limits);
496 Ok(this.mk_expr_with_attrs(span, range, attrs))
497 })
498 }
499
500 fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
502 let lo = self.token.span;
503
504 macro_rules! make_it {
505 ($this:ident, $attrs:expr, |this, _| $body:expr) => {
506 $this.collect_tokens_for_expr($attrs, |$this, attrs| {
507 let (hi, ex) = $body?;
508 Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
509 })
510 };
511 }
512
513 let this = self;
514
515 match this.token.uninterpolate().kind {
517 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)),
519 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)),
521 token::Minus => {
523 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))
524 }
525 token::Star => {
527 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))
528 }
529 token::And | token::AndAnd => {
531 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))
532 }
533 token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
535 let mut err = errors::LeadingPlusNotSupported {
536 span: lo,
537 remove_plus: None,
538 add_parentheses: None,
539 };
540
541 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
543 err.add_parentheses = Some(ExprParenthesesNeeded::surrounding(*sp));
544 } else {
545 err.remove_plus = Some(lo);
546 }
547 this.dcx().emit_err(err);
548
549 this.bump();
550 let attrs = this.parse_outer_attributes()?;
551 this.parse_expr_prefix(attrs)
552 }
553 token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {
555 let starts_stmt =
556 this.prev_token == token::Semi || this.prev_token == token::CloseBrace;
557 let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
558 this.bump();
560 this.bump();
561
562 let operand_expr = this.parse_expr_dot_or_call(attrs)?;
563 this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt)
564 }
565 token::Ident(..) if this.token.is_keyword(kw::Box) => {
566 this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.parse_expr_box(lo)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.parse_expr_box(lo))
567 }
568 token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
569 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))
570 }
571 _ => return this.parse_expr_dot_or_call(attrs),
572 }
573 }
574
575 fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> {
576 self.bump();
577 let attrs = self.parse_outer_attributes()?;
578 let expr = if self.token.is_range_separator() {
579 self.parse_expr_prefix_range(attrs)
580 } else {
581 self.parse_expr_prefix(attrs)
582 }?;
583 let span = self.interpolated_or_expr_span(&expr);
584 Ok((lo.to(span), expr))
585 }
586
587 fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
588 let (span, expr) = self.parse_expr_prefix_common(lo)?;
589 Ok((span, self.mk_unary(op, expr)))
590 }
591
592 fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
594 self.dcx().emit_err(errors::TildeAsUnaryOperator(lo));
595
596 self.parse_expr_unary(lo, UnOp::Not)
597 }
598
599 fn parse_expr_box(&mut self, box_kw: Span) -> PResult<'a, (Span, ExprKind)> {
602 let (span, expr) = self.parse_expr_prefix_common(box_kw)?;
603 let box_kw_and_lo = box_kw.until(self.interpolated_or_expr_span(&expr));
605 let hi = span.shrink_to_hi();
606 let sugg = errors::AddBoxNew { box_kw_and_lo, hi };
607 let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span, sugg });
608 Ok((span, ExprKind::Err(guar)))
609 }
610
611 fn is_mistaken_not_ident_negation(&self) -> bool {
612 let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {
613 token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw),
616 token::Literal(..) | token::Pound => true,
617 _ => t.is_metavar_expr(),
618 };
619 self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)
620 }
621
622 fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
624 let negated_token = self.look_ahead(1, |t| *t);
625
626 let sub_diag = if negated_token.is_numeric_lit() {
627 errors::NotAsNegationOperatorSub::SuggestNotBitwise
628 } else if negated_token.is_bool_lit() {
629 errors::NotAsNegationOperatorSub::SuggestNotLogical
630 } else {
631 errors::NotAsNegationOperatorSub::SuggestNotDefault
632 };
633
634 self.dcx().emit_err(errors::NotAsNegationOperator {
635 negated: negated_token.span,
636 negated_desc: super::token_descr(&negated_token),
637 sub: sub_diag(
640 self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
641 ),
642 });
643
644 self.parse_expr_unary(lo, UnOp::Not)
645 }
646
647 fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
649 match self.prev_token.kind {
650 token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,
651 token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {
652 self.prev_token.span
657 }
658 _ => expr.span,
659 }
660 }
661
662 fn parse_assoc_op_cast(
663 &mut self,
664 lhs: Box<Expr>,
665 lhs_span: Span,
666 op_span: Span,
667 expr_kind: fn(Box<Expr>, Box<Ty>) -> ExprKind,
668 ) -> PResult<'a, Box<Expr>> {
669 let mk_expr = |this: &mut Self, lhs: Box<Expr>, rhs: Box<Ty>| {
670 this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs))
671 };
672
673 let parser_snapshot_before_type = self.clone();
676 let cast_expr = match self.parse_as_cast_ty() {
677 Ok(rhs) => mk_expr(self, lhs, rhs),
678 Err(type_err) => {
679 if !self.may_recover() {
680 return Err(type_err);
681 }
682
683 let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
687
688 match (&lhs.kind, &self.token.kind) {
690 (
691 ExprKind::Path(None, ast::Path { segments, .. }),
693 token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
694 ) if let [segment] = segments.as_slice() => {
695 let snapshot = self.create_snapshot_for_diagnostic();
696 let label = Label {
697 ident: Ident::from_str_and_span(
698 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}", segment.ident))
})format!("'{}", segment.ident),
699 segment.ident.span,
700 ),
701 };
702 match self.parse_expr_labeled(label, false) {
703 Ok(expr) => {
704 type_err.cancel();
705 self.dcx().emit_err(errors::MalformedLoopLabel {
706 span: label.ident.span,
707 suggestion: label.ident.span.shrink_to_lo(),
708 });
709 return Ok(expr);
710 }
711 Err(err) => {
712 err.cancel();
713 self.restore_snapshot(snapshot);
714 }
715 }
716 }
717 _ => {}
718 }
719
720 match self.parse_path(PathStyle::Expr) {
721 Ok(path) => {
722 let span_after_type = parser_snapshot_after_type.token.span;
723 let expr = mk_expr(
724 self,
725 lhs,
726 self.mk_ty(path.span, TyKind::Path(None, path.clone())),
727 );
728
729 let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
730 let suggestion = errors::ComparisonOrShiftInterpretedAsGenericSugg {
731 left: expr.span.shrink_to_lo(),
732 right: expr.span.shrink_to_hi(),
733 };
734
735 match self.token.kind {
736 token::Lt => {
737 self.dcx().emit_err(errors::ComparisonInterpretedAsGeneric {
738 comparison: self.token.span,
739 r#type: path,
740 args: args_span,
741 suggestion,
742 })
743 }
744 token::Shl => self.dcx().emit_err(errors::ShiftInterpretedAsGeneric {
745 shift: self.token.span,
746 r#type: path,
747 args: args_span,
748 suggestion,
749 }),
750 _ => {
751 *self = parser_snapshot_after_type;
756 return Err(type_err);
757 }
758 };
759
760 type_err.cancel();
762
763 expr
765 }
766 Err(path_err) => {
767 path_err.cancel();
769 *self = parser_snapshot_after_type;
770 return Err(type_err);
771 }
772 }
773 }
774 };
775
776 let span = cast_expr.span;
782
783 let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
784
785 if !#[allow(non_exhaustive_omitted_patterns)] match with_postfix.kind {
ExprKind::Cast(_, _) => true,
_ => false,
}matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
788 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cast cannot be followed by {0}",
match with_postfix.kind {
ExprKind::Index(..) => "indexing",
ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
ExprKind::MethodCall(_) => "a method call",
ExprKind::Call(_, _) => "a function call",
ExprKind::Await(_, _) => "`.await`",
ExprKind::Use(_, _) => "`.use`",
ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
ExprKind::Match(_, _, MatchKind::Postfix) =>
"a postfix match",
ExprKind::Err(_) => return Ok(with_postfix),
_ => {
::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)));
}
}))
})format!(
789 "cast cannot be followed by {}",
790 match with_postfix.kind {
791 ExprKind::Index(..) => "indexing",
792 ExprKind::Try(_) => "`?`",
793 ExprKind::Field(_, _) => "a field access",
794 ExprKind::MethodCall(_) => "a method call",
795 ExprKind::Call(_, _) => "a function call",
796 ExprKind::Await(_, _) => "`.await`",
797 ExprKind::Use(_, _) => "`.use`",
798 ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
799 ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
800 ExprKind::Err(_) => return Ok(with_postfix),
801 _ => unreachable!(
802 "did not expect {:?} as an illegal postfix operator following cast",
803 with_postfix.kind
804 ),
805 }
806 );
807 let mut err = self.dcx().struct_span_err(span, msg);
808
809 let suggest_parens = |err: &mut Diag<'_>| {
810 let suggestions = <[_]>::into_vec(::alloc::boxed::box_new([(span.shrink_to_lo(),
"(".to_string()), (span.shrink_to_hi(), ")".to_string())]))vec![
811 (span.shrink_to_lo(), "(".to_string()),
812 (span.shrink_to_hi(), ")".to_string()),
813 ];
814 err.multipart_suggestion(
815 "try surrounding the expression in parentheses",
816 suggestions,
817 Applicability::MachineApplicable,
818 );
819 };
820
821 suggest_parens(&mut err);
822
823 err.emit();
824 };
825 Ok(with_postfix)
826 }
827
828 fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
830 self.expect_and()?;
831 let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
832 let lifetime = has_lifetime.then(|| self.expect_lifetime()); let (borrow_kind, mutbl) = self.parse_borrow_modifiers();
834 let attrs = self.parse_outer_attributes()?;
835 let expr = if self.token.is_range_separator() {
836 self.parse_expr_prefix_range(attrs)
837 } else {
838 self.parse_expr_prefix(attrs)
839 }?;
840 let hi = self.interpolated_or_expr_span(&expr);
841 let span = lo.to(hi);
842 if let Some(lt) = lifetime {
843 self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
844 }
845
846 if borrow_kind == ast::BorrowKind::Ref
850 && mutbl == ast::Mutability::Not
851 && #[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)
852 {
853 self.expected_token_types.insert(TokenType::KwMut);
854 self.expected_token_types.insert(TokenType::KwConst);
855 }
856
857 Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
858 }
859
860 fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
861 self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
862 }
863
864 fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
866 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) {
867 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));
869 if !found_raw { ::core::panicking::panic("assertion failed: found_raw") };assert!(found_raw);
870 let mutability = self.parse_const_or_mut().unwrap();
871 (ast::BorrowKind::Raw, mutability)
872 } else {
873 match self.parse_pin_and_mut() {
874 (ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),
876 (ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),
880 }
881 }
882 }
883
884 fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
886 self.collect_tokens_for_expr(attrs, |this, attrs| {
887 let base = this.parse_expr_bottom()?;
888 let span = this.interpolated_or_expr_span(&base);
889 this.parse_expr_dot_or_call_with(attrs, base, span)
890 })
891 }
892
893 pub(super) fn parse_expr_dot_or_call_with(
894 &mut self,
895 mut attrs: ast::AttrVec,
896 mut e: Box<Expr>,
897 lo: Span,
898 ) -> PResult<'a, Box<Expr>> {
899 let mut res = ensure_sufficient_stack(|| {
900 loop {
901 let has_question =
902 if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
903 self.eat_noexpect(&token::Question)
906 } else {
907 self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Question,
token_type: crate::parser::token_type::TokenType::Question,
}exp!(Question))
908 };
909 if has_question {
910 e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
912 continue;
913 }
914 let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
915 self.eat_noexpect(&token::Dot)
918 } else if self.token == TokenKind::RArrow && self.may_recover() {
919 self.bump();
921 let span = self.prev_token.span;
922 self.dcx().emit_err(errors::ExprRArrowCall { span });
923 true
924 } else {
925 self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Dot,
token_type: crate::parser::token_type::TokenType::Dot,
}exp!(Dot))
926 };
927 if has_dot {
928 e = self.parse_dot_suffix_expr(lo, e)?;
930 continue;
931 }
932 if self.expr_is_complete(&e) {
933 return Ok(e);
934 }
935 e = match self.token.kind {
936 token::OpenParen => self.parse_expr_fn_call(lo, e),
937 token::OpenBracket => self.parse_expr_index(lo, e)?,
938 _ => return Ok(e),
939 }
940 }
941 });
942
943 if !attrs.is_empty()
946 && let Ok(expr) = &mut res
947 {
948 mem::swap(&mut expr.attrs, &mut attrs);
949 expr.attrs.extend(attrs)
950 }
951 res
952 }
953
954 pub(super) fn parse_dot_suffix_expr(
955 &mut self,
956 lo: Span,
957 base: Box<Expr>,
958 ) -> PResult<'a, Box<Expr>> {
959 match self.token.uninterpolate().kind {
962 token::Ident(..) => self.parse_dot_suffix(base, lo),
963 token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
964 let ident_span = self.token.span;
965 self.bump();
966 Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))
967 }
968 token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {
969 Ok(match self.break_up_float(symbol, self.token.span) {
970 DestructuredFloat::Single(sym, _sp) => {
972 let ident_span = self.token.span;
976 self.bump();
977 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)
978 }
979 DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
981 if !suffix.is_none() {
::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
985 self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span);
986 self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
987 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)
988 }
989 DestructuredFloat::MiddleDot(
991 sym1,
992 ident1_span,
993 _dot_span,
994 sym2,
995 ident2_span,
996 ) => {
997 let next_token2 =
1001 Token::new(token::Ident(sym2, IdentIsRaw::No), ident2_span);
1002 self.bump_with((next_token2, self.token_spacing));
1003 self.bump();
1004 let base1 =
1005 self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
1006 self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
1007 }
1008 DestructuredFloat::Error => base,
1009 })
1010 }
1011 _ => {
1012 self.error_unexpected_after_dot();
1013 Ok(base)
1014 }
1015 }
1016 }
1017
1018 fn error_unexpected_after_dot(&self) {
1019 let actual = super::token_descr(&self.token);
1020 let span = self.token.span;
1021 let sm = self.psess.source_map();
1022 let (span, actual) = match (&self.token.kind, self.subparser_name) {
1023 (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {
1024 (span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", snippet))
})format!("`{}`", snippet))
1025 }
1026 (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {
1027 self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");
1042 return;
1043 }
1044 _ => (span, actual),
1045 };
1046 self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual });
1047 }
1048
1049 pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
1060 #[derive(#[automatically_derived]
impl ::core::fmt::Debug for FloatComponent {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
FloatComponent::IdentLike(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"IdentLike", &__self_0),
FloatComponent::Punct(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Punct",
&__self_0),
}
}
}Debug)]
1061 enum FloatComponent {
1062 IdentLike(String),
1063 Punct(char),
1064 }
1065 use FloatComponent::*;
1066
1067 let float_str = float.as_str();
1068 let mut components = Vec::new();
1069 let mut ident_like = String::new();
1070 for c in float_str.chars() {
1071 if c == '_' || c.is_ascii_alphanumeric() {
1072 ident_like.push(c);
1073 } else if #[allow(non_exhaustive_omitted_patterns)] match c {
'.' | '+' | '-' => true,
_ => false,
}matches!(c, '.' | '+' | '-') {
1074 if !ident_like.is_empty() {
1075 components.push(IdentLike(mem::take(&mut ident_like)));
1076 }
1077 components.push(Punct(c));
1078 } else {
1079 {
::core::panicking::panic_fmt(format_args!("unexpected character in a float token: {0:?}",
c));
}panic!("unexpected character in a float token: {c:?}")
1080 }
1081 }
1082 if !ident_like.is_empty() {
1083 components.push(IdentLike(ident_like));
1084 }
1085
1086 let can_take_span_apart =
1090 || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
1091
1092 match &*components {
1093 [IdentLike(i)] => {
1095 DestructuredFloat::Single(Symbol::intern(i), span)
1096 }
1097 [IdentLike(left), Punct('.')] => {
1099 let (left_span, dot_span) = if can_take_span_apart() {
1100 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
1101 let dot_span = span.with_lo(left_span.hi());
1102 (left_span, dot_span)
1103 } else {
1104 (span, span)
1105 };
1106 let left = Symbol::intern(left);
1107 DestructuredFloat::TrailingDot(left, left_span, dot_span)
1108 }
1109 [IdentLike(left), Punct('.'), IdentLike(right)] => {
1111 let (left_span, dot_span, right_span) = if can_take_span_apart() {
1112 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
1113 let dot_span = span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));
1114 let right_span = span.with_lo(dot_span.hi());
1115 (left_span, dot_span, right_span)
1116 } else {
1117 (span, span, span)
1118 };
1119 let left = Symbol::intern(left);
1120 let right = Symbol::intern(right);
1121 DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)
1122 }
1123 [IdentLike(_), Punct('+' | '-')] |
1125 [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |
1127 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |
1129 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
1131 self.error_unexpected_after_dot();
1133 DestructuredFloat::Error
1134 }
1135 _ => {
::core::panicking::panic_fmt(format_args!("unexpected components in a float token: {0:?}",
components));
}panic!("unexpected components in a float token: {components:?}"),
1136 }
1137 }
1138
1139 fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {
1143 let mut fields = Vec::new();
1144 let mut trailing_dot = None;
1145
1146 loop {
1147 let expr = self.parse_expr()?;
1151 let mut current = &expr;
1152 let start_idx = fields.len();
1153 loop {
1154 match current.kind {
1155 ExprKind::Field(ref left, right) => {
1156 fields.insert(start_idx, right);
1158 trailing_dot = None;
1159 current = left;
1160 }
1161 ExprKind::Index(ref left, ref _right, span) => {
1164 self.dcx().emit_err(errors::ArrayIndexInOffsetOf(span));
1165 current = left;
1166 }
1167 ExprKind::Lit(token::Lit {
1168 kind: token::Float | token::Integer,
1169 symbol,
1170 suffix,
1171 }) => {
1172 if let Some(suffix) = suffix {
1173 self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex {
1174 span: current.span,
1175 suffix,
1176 });
1177 }
1178 match self.break_up_float(symbol, current.span) {
1179 DestructuredFloat::Single(sym, sp) => {
1181 trailing_dot = None;
1182 fields.insert(start_idx, Ident::new(sym, sp));
1183 }
1184 DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
1186 if !suffix.is_none() {
::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
1187 trailing_dot = Some(dot_span);
1188 fields.insert(start_idx, Ident::new(sym, sym_span));
1189 }
1190 DestructuredFloat::MiddleDot(
1192 symbol1,
1193 span1,
1194 _dot_span,
1195 symbol2,
1196 span2,
1197 ) => {
1198 trailing_dot = None;
1199 fields.insert(start_idx, Ident::new(symbol2, span2));
1200 fields.insert(start_idx, Ident::new(symbol1, span1));
1201 }
1202 DestructuredFloat::Error => {
1203 trailing_dot = None;
1204 fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
1205 }
1206 }
1207 break;
1208 }
1209 ExprKind::Path(None, Path { ref segments, .. }) => {
1210 match &segments[..] {
1211 [PathSegment { ident, args: None, .. }] => {
1212 trailing_dot = None;
1213 fields.insert(start_idx, *ident)
1214 }
1215 _ => {
1216 self.dcx().emit_err(errors::InvalidOffsetOf(current.span));
1217 break;
1218 }
1219 }
1220 break;
1221 }
1222 _ => {
1223 self.dcx().emit_err(errors::InvalidOffsetOf(current.span));
1224 break;
1225 }
1226 }
1227 }
1228
1229 if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {
1230 break;
1231 } else if trailing_dot.is_none() {
1232 self.dcx().emit_err(errors::InvalidOffsetOf(self.token.span));
1234 break;
1235 }
1236 }
1237 if let Some(dot) = trailing_dot {
1238 self.dcx().emit_err(errors::InvalidOffsetOf(dot));
1239 }
1240 Ok(fields.into_iter().collect())
1241 }
1242
1243 fn mk_expr_tuple_field_access(
1244 &self,
1245 lo: Span,
1246 ident_span: Span,
1247 base: Box<Expr>,
1248 field: Symbol,
1249 suffix: Option<Symbol>,
1250 ) -> Box<Expr> {
1251 if let Some(suffix) = suffix {
1252 self.dcx()
1253 .emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span: ident_span, suffix });
1254 }
1255 self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))
1256 }
1257
1258 fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> {
1260 let snapshot = if self.token == token::OpenParen {
1261 Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
1262 } else {
1263 None
1264 };
1265 let open_paren = self.token.span;
1266
1267 let seq = self
1268 .parse_expr_paren_seq()
1269 .map(|args| self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args)));
1270 match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {
1271 Ok(expr) => expr,
1272 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),
1273 }
1274 }
1275
1276 #[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("compiler/rustc_parse/src/parser/expr.rs"),
::tracing_core::__macro_support::Option::Some(1278u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::expr"),
::tracing_core::field::FieldSet::new(&["lo", "open_paren"],
::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};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&lo)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&open_paren)
as &dyn 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();
self.dcx().create_err(errors::ParenthesesWithStructFields {
span,
r#type: path,
braces_for_struct: errors::BracesForStructLiteral {
first: open_paren,
second: close_paren,
},
no_fields_for_fn: errors::NoFieldsForFnCall {
fields: fields.into_iter().map(|field|
field.span.until(field.expr.span)).collect(),
},
}).emit()
} else { err.emit() };
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")]
1279 fn maybe_recover_struct_lit_bad_delims(
1280 &mut self,
1281 lo: Span,
1282 open_paren: Span,
1283 seq: PResult<'a, Box<Expr>>,
1284 snapshot: Option<(SnapshotParser<'a>, ExprKind)>,
1285 ) -> PResult<'a, Box<Expr>> {
1286 match (self.may_recover(), seq, snapshot) {
1287 (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
1288 snapshot.bump(); match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {
1290 Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {
1291 self.restore_snapshot(snapshot);
1294 let close_paren = self.prev_token.span;
1295 let span = lo.to(close_paren);
1296 let fields: Vec<_> =
1298 fields.into_iter().filter(|field| !field.is_shorthand).collect();
1299
1300 let guar = if !fields.is_empty() &&
1301 self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")
1306 {
1307 err.cancel();
1308 self.dcx()
1309 .create_err(errors::ParenthesesWithStructFields {
1310 span,
1311 r#type: path,
1312 braces_for_struct: errors::BracesForStructLiteral {
1313 first: open_paren,
1314 second: close_paren,
1315 },
1316 no_fields_for_fn: errors::NoFieldsForFnCall {
1317 fields: fields
1318 .into_iter()
1319 .map(|field| field.span.until(field.expr.span))
1320 .collect(),
1321 },
1322 })
1323 .emit()
1324 } else {
1325 err.emit()
1326 };
1327 Ok(self.mk_expr_err(span, guar))
1328 }
1329 Ok(_) => Err(err),
1330 Err(err2) => {
1331 err2.cancel();
1332 Err(err)
1333 }
1334 }
1335 }
1336 (_, seq, _) => seq,
1337 }
1338 }
1339
1340 fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> {
1342 let prev_span = self.prev_token.span;
1343 let open_delim_span = self.token.span;
1344 self.bump(); let index = self.parse_expr()?;
1346 self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
1347 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBracket,
token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket))?;
1348 Ok(self.mk_expr(
1349 lo.to(self.prev_token.span),
1350 self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),
1351 ))
1352 }
1353
1354 fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> {
1356 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)) {
1357 return Ok(self.mk_await_expr(self_arg, lo));
1358 }
1359
1360 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)) {
1361 let use_span = self.prev_token.span;
1362 self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
1363 return Ok(self.mk_use_expr(self_arg, lo));
1364 }
1365
1366 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)) {
1368 let match_span = self.prev_token.span;
1369 self.psess.gated_spans.gate(sym::postfix_match, match_span);
1370 return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
1371 }
1372
1373 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)) {
1375 let yield_span = self.prev_token.span;
1376 self.psess.gated_spans.gate(sym::yield_expr, yield_span);
1377 return Ok(
1378 self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))
1379 );
1380 }
1381
1382 let fn_span_lo = self.token.span;
1383 let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
1384 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)]);
1385 self.check_turbofish_missing_angle_brackets(&mut seg);
1386
1387 if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1388 let args = self.parse_expr_paren_seq()?;
1390 let fn_span = fn_span_lo.to(self.prev_token.span);
1391 let span = lo.to(self.prev_token.span);
1392 Ok(self.mk_expr(
1393 span,
1394 ExprKind::MethodCall(Box::new(ast::MethodCall {
1395 seg,
1396 receiver: self_arg,
1397 args,
1398 span: fn_span,
1399 })),
1400 ))
1401 } else {
1402 let span = lo.to(self.prev_token.span);
1404 if let Some(args) = seg.args {
1405 self.dcx()
1407 .create_err(errors::FieldExpressionWithGeneric(args.span()))
1408 .stash(seg.ident.span, StashKey::GenericInFieldExpr);
1409 }
1410
1411 Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))
1412 }
1413 }
1414
1415 fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> {
1421 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);
1422
1423 let span = self.token.span;
1424 if let Some(expr) = self.eat_metavar_seq_with_matcher(
1425 |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
MetaVarKind::Expr { .. } => true,
_ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
1426 |this| {
1427 let expr = this.parse_expr_force_collect();
1430 if this.token.kind == token::Comma {
1435 this.bump();
1436 }
1437 expr
1438 },
1439 ) {
1440 return Ok(expr);
1441 } else if let Some(lit) =
1442 self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
1443 {
1444 return Ok(lit);
1445 } else if let Some(block) =
1446 self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())
1447 {
1448 return Ok(self.mk_expr(span, ExprKind::Block(block, None)));
1449 } else if let Some(path) =
1450 self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
1451 {
1452 return Ok(self.mk_expr(span, ExprKind::Path(None, path)));
1453 }
1454
1455 let restrictions = self.restrictions;
1459 self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {
1460 let lo = this.token.span;
1462 if let token::Literal(_) = this.token.kind {
1463 this.parse_expr_lit()
1467 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1468 this.parse_expr_tuple_parens(restrictions)
1469 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
1470 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
1471 return Ok(expr);
1472 }
1473 this.parse_expr_block(None, lo, BlockCheckMode::Default)
1474 } 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)) {
1475 this.parse_expr_closure().map_err(|mut err| {
1476 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
1479 err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
1480 }
1481 err
1482 })
1483 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBracket,
token_type: crate::parser::token_type::TokenType::OpenBracket,
}exp!(OpenBracket)) {
1484 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))
1485 } else if this.is_builtin() {
1486 this.parse_expr_builtin()
1487 } else if this.check_path() {
1488 this.parse_expr_path_start()
1489 } 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))
1490 || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Use,
token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use))
1491 || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Static,
token_type: crate::parser::token_type::TokenType::KwStatic,
}exp!(Static))
1492 || this.check_const_closure()
1493 {
1494 this.parse_expr_closure()
1495 } 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)) {
1496 this.parse_expr_if()
1497 } 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)) {
1498 if this.choose_generics_over_qpath(1) {
1499 this.parse_expr_closure()
1500 } else {
1501 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)));
1502 this.parse_expr_for(None, lo)
1503 }
1504 } 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)) {
1505 this.parse_expr_while(None, lo)
1506 } else if let Some(label) = this.eat_label() {
1507 this.parse_expr_labeled(label, true)
1508 } 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)) {
1509 this.parse_expr_loop(None, lo).map_err(|mut err| {
1510 err.span_label(lo, "while parsing this `loop` expression");
1511 err
1512 })
1513 } 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)) {
1514 this.parse_expr_match().map_err(|mut err| {
1515 err.span_label(lo, "while parsing this `match` expression");
1516 err
1517 })
1518 } 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)) {
1519 this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
1520 |mut err| {
1521 err.span_label(lo, "while parsing this `unsafe` expression");
1522 err
1523 },
1524 )
1525 } else if this.check_inline_const(0) {
1526 this.parse_const_block(lo)
1527 } else if this.may_recover() && this.is_do_catch_block() {
1528 this.recover_do_catch()
1529 } else if this.is_try_block() {
1530 this.expect_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Try,
token_type: crate::parser::token_type::TokenType::KwTry,
}exp!(Try))?;
1531 this.parse_try_block(lo)
1532 } 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)) {
1533 this.parse_expr_return()
1534 } 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)) {
1535 this.parse_expr_continue(lo)
1536 } 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)) {
1537 this.parse_expr_break()
1538 } 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)) {
1539 this.parse_expr_yield()
1540 } else if this.is_do_yeet() {
1541 this.parse_expr_yeet()
1542 } 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)) {
1543 this.parse_expr_become()
1544 } 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)) {
1545 this.parse_expr_let(restrictions)
1546 } 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)) {
1547 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
1548 return Ok(expr);
1549 }
1550 Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
1551 } else if this.token_uninterpolated_span().at_least_rust_2018() {
1552 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));
1554 if this.token_uninterpolated_span().at_least_rust_2024()
1559 && this.is_gen_block(kw::Gen, at_async as usize)
1560 {
1561 this.parse_gen_block()
1562 } else if this.is_gen_block(kw::Async, 0) {
1564 this.parse_gen_block()
1565 } else if at_async {
1566 this.parse_expr_closure()
1567 } else if this.eat_keyword_noexpect(kw::Await) {
1568 this.recover_incorrect_await_syntax(lo)
1569 } else {
1570 this.parse_expr_lit()
1571 }
1572 } else {
1573 this.parse_expr_lit()
1574 }
1575 })
1576 }
1577
1578 fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> {
1579 let lo = self.token.span;
1580 match self.parse_opt_token_lit() {
1581 Some((token_lit, _)) => {
1582 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));
1583 self.maybe_recover_from_bad_qpath(expr)
1584 }
1585 None => self.try_macro_suggestion(),
1586 }
1587 }
1588
1589 fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
1590 let lo = self.token.span;
1591 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1592 let (es, trailing_comma) = match self.parse_seq_to_end(
1593 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1594 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
1595 |p| p.parse_expr_catch_underscore(restrictions.intersection(Restrictions::ALLOW_LET)),
1596 ) {
1597 Ok(x) => x,
1598 Err(err) => {
1599 return Ok(self.recover_seq_parse_error(
1600 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen),
1601 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1602 lo,
1603 err,
1604 ));
1605 }
1606 };
1607 let kind = if es.len() == 1 && #[allow(non_exhaustive_omitted_patterns)] match trailing_comma {
Trailing::No => true,
_ => false,
}matches!(trailing_comma, Trailing::No) {
1608 ExprKind::Paren(es.into_iter().next().unwrap())
1610 } else {
1611 ExprKind::Tup(es)
1613 };
1614 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1615 self.maybe_recover_from_bad_qpath(expr)
1616 }
1617
1618 fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> {
1619 let lo = self.token.span;
1620 self.bump(); let kind = if self.eat(close) {
1623 ExprKind::Array(ThinVec::new())
1625 } else {
1626 let first_expr = self.parse_expr()?;
1628 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) {
1629 let count = if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Const,
token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const)) {
1631 self.parse_mgca_const_block(false)?
1637 } else {
1638 self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?
1639 };
1640 self.expect(close)?;
1641 ExprKind::Repeat(first_expr, count)
1642 } else if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1643 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));
1645 let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
1646 exprs.insert(0, first_expr);
1647 ExprKind::Array(exprs)
1648 } else {
1649 self.expect(close)?;
1651 ExprKind::Array({
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(first_expr);
vec
}thin_vec![first_expr])
1652 }
1653 };
1654 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1655 self.maybe_recover_from_bad_qpath(expr)
1656 }
1657
1658 fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> {
1659 let maybe_eq_tok = self.prev_token;
1660 let (qself, path) = if self.eat_lt() {
1661 let lt_span = self.prev_token.span;
1662 let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
1663 if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
1667 let eq_lt = maybe_eq_tok.span.to(lt_span);
1668 err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
1669 }
1670 err
1671 })?;
1672 (Some(qself), path)
1673 } else {
1674 (None, self.parse_path(PathStyle::Expr)?)
1675 };
1676
1677 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)) {
1679 if qself.is_some() {
1681 self.dcx().emit_err(errors::MacroInvocationWithQualifiedPath(path.span));
1682 }
1683 let lo = path.span;
1684 let mac = Box::new(MacCall { path, args: self.parse_delim_args()? });
1685 (lo.to(self.prev_token.span), ExprKind::MacCall(mac))
1686 } else if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
1687 && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
1688 {
1689 if qself.is_some() {
1690 self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);
1691 }
1692 return expr;
1693 } else {
1694 (path.span, ExprKind::Path(qself, path))
1695 };
1696
1697 let expr = self.mk_expr(span, kind);
1698 self.maybe_recover_from_bad_qpath(expr)
1699 }
1700
1701 pub(super) fn parse_expr_labeled(
1703 &mut self,
1704 label_: Label,
1705 mut consume_colon: bool,
1706 ) -> PResult<'a, Box<Expr>> {
1707 let lo = label_.ident.span;
1708 let label = Some(label_);
1709 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));
1710 let tok_sp = self.token.span;
1711 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)) {
1712 self.parse_expr_while(label, lo)
1713 } 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)) {
1714 self.parse_expr_for(label, lo)
1715 } 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)) {
1716 self.parse_expr_loop(label, lo)
1717 } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {
1718 self.parse_expr_block(label, lo, BlockCheckMode::Default)
1719 } else if !ate_colon
1720 && self.may_recover()
1721 && (self.token.kind.close_delim().is_some() || self.token.is_punct())
1722 && could_be_unclosed_char_literal(label_.ident)
1723 {
1724 let (lit, _) =
1725 self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
1726 self_.dcx().create_err(errors::UnexpectedTokenAfterLabel {
1727 span: self_.token.span,
1728 remove_label: None,
1729 enclose_in_block: None,
1730 })
1731 });
1732 consume_colon = false;
1733 Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
1734 } else if !ate_colon
1735 && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
1736 {
1737 let guar = self.dcx().emit_err(errors::UnexpectedTokenAfterLabel {
1739 span: self.token.span,
1740 remove_label: None,
1741 enclose_in_block: None,
1742 });
1743 consume_colon = false;
1744 Ok(self.mk_expr_err(lo, guar))
1745 } else {
1746 let mut err = errors::UnexpectedTokenAfterLabel {
1747 span: self.token.span,
1748 remove_label: None,
1749 enclose_in_block: None,
1750 };
1751
1752 let expr = self.parse_expr().map(|expr| {
1754 let span = expr.span;
1755
1756 let found_labeled_breaks = {
1757 struct FindLabeledBreaksVisitor;
1758
1759 impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {
1760 type Result = ControlFlow<()>;
1761 fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {
1762 if let ExprKind::Break(Some(_label), _) = ex.kind {
1763 ControlFlow::Break(())
1764 } else {
1765 walk_expr(self, ex)
1766 }
1767 }
1768 }
1769
1770 FindLabeledBreaksVisitor.visit_expr(&expr).is_break()
1771 };
1772
1773 if !found_labeled_breaks {
1778 err.remove_label = Some(lo.until(span));
1779
1780 return expr;
1781 }
1782
1783 err.enclose_in_block = Some(errors::UnexpectedTokenAfterLabelSugg {
1784 left: span.shrink_to_lo(),
1785 right: span.shrink_to_hi(),
1786 });
1787
1788 let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
1790 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);
1791 self.mk_expr(span, ExprKind::Block(blk, label))
1792 });
1793
1794 self.dcx().emit_err(err);
1795 expr
1796 }?;
1797
1798 if !ate_colon && consume_colon {
1799 self.dcx().emit_err(errors::RequireColonAfterLabeledExpression {
1800 span: expr.span,
1801 label: lo,
1802 label_end: lo.between(tok_sp),
1803 });
1804 }
1805
1806 Ok(expr)
1807 }
1808
1809 pub(super) fn recover_unclosed_char<L>(
1811 &self,
1812 ident: Ident,
1813 mk_lit_char: impl FnOnce(Symbol, Span) -> L,
1814 err: impl FnOnce(&Self) -> Diag<'a>,
1815 ) -> L {
1816 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));
1817 self.dcx()
1818 .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {
1819 err.span_suggestion_verbose(
1820 ident.span.shrink_to_hi(),
1821 "add `'` to close the char literal",
1822 "'",
1823 Applicability::MaybeIncorrect,
1824 );
1825 })
1826 .unwrap_or_else(|| {
1827 err(self)
1828 .with_span_suggestion_verbose(
1829 ident.span.shrink_to_hi(),
1830 "add `'` to close the char literal",
1831 "'",
1832 Applicability::MaybeIncorrect,
1833 )
1834 .emit()
1835 });
1836 let name = ident.without_first_quote().name;
1837 mk_lit_char(name, ident.span)
1838 }
1839
1840 fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> {
1842 let lo = self.token.span;
1843
1844 self.bump(); self.bump(); let span = lo.to(self.prev_token.span);
1848 self.dcx().emit_err(errors::DoCatchSyntaxRemoved { span });
1849
1850 self.parse_try_block(lo)
1851 }
1852
1853 fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> {
1855 Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })
1856 }
1857
1858 fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> {
1860 let lo = self.prev_token.span;
1861 let kind = ExprKind::Ret(self.parse_expr_opt()?);
1862 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1863 self.maybe_recover_from_bad_qpath(expr)
1864 }
1865
1866 fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> {
1868 let lo = self.token.span;
1869
1870 self.bump(); self.bump(); let kind = ExprKind::Yeet(self.parse_expr_opt()?);
1874
1875 let span = lo.to(self.prev_token.span);
1876 self.psess.gated_spans.gate(sym::yeet_expr, span);
1877 let expr = self.mk_expr(span, kind);
1878 self.maybe_recover_from_bad_qpath(expr)
1879 }
1880
1881 fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> {
1883 let lo = self.prev_token.span;
1884 let kind = ExprKind::Become(self.parse_expr()?);
1885 let span = lo.to(self.prev_token.span);
1886 self.psess.gated_spans.gate(sym::explicit_tail_calls, span);
1887 let expr = self.mk_expr(span, kind);
1888 self.maybe_recover_from_bad_qpath(expr)
1889 }
1890
1891 fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {
1900 let lo = self.prev_token.span;
1901 let mut label = self.eat_label();
1902 let kind = if self.token == token::Colon
1903 && let Some(label) = label.take()
1904 {
1905 let lexpr = self.parse_expr_labeled(label, true)?;
1908 self.dcx().emit_err(errors::LabeledLoopInBreak {
1909 span: lexpr.span,
1910 sub: errors::WrapInParentheses::Expression {
1911 left: lexpr.span.shrink_to_lo(),
1912 right: lexpr.span.shrink_to_hi(),
1913 },
1914 });
1915 Some(lexpr)
1916 } else if self.token != token::OpenBrace
1917 || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
1918 {
1919 let mut expr = self.parse_expr_opt()?;
1920 if let Some(expr) = &mut expr {
1921 if label.is_some()
1922 && match &expr.kind {
1923 ExprKind::While(_, _, None)
1924 | ExprKind::ForLoop { label: None, .. }
1925 | ExprKind::Loop(_, None, _) => true,
1926 ExprKind::Block(block, None) => {
1927 #[allow(non_exhaustive_omitted_patterns)] match block.rules {
BlockCheckMode::Default => true,
_ => false,
}matches!(block.rules, BlockCheckMode::Default)
1928 }
1929 _ => false,
1930 }
1931 {
1932 self.psess.buffer_lint(
1933 BREAK_WITH_LABEL_AND_LOOP,
1934 lo.to(expr.span),
1935 ast::CRATE_NODE_ID,
1936 BuiltinLintDiag::BreakWithLabelAndLoop(expr.span),
1937 );
1938 }
1939
1940 if self.may_recover()
1942 && let ExprKind::Path(None, p) = &expr.kind
1943 && let [segment] = &*p.segments
1944 && let &ast::PathSegment { ident, args: None, .. } = segment
1945 && let Some(next) = self.parse_expr_opt()?
1946 {
1947 label = Some(self.recover_ident_into_label(ident));
1948 *expr = next;
1949 }
1950 }
1951
1952 expr
1953 } else {
1954 None
1955 };
1956 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));
1957 self.maybe_recover_from_bad_qpath(expr)
1958 }
1959
1960 fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
1962 let mut label = self.eat_label();
1963
1964 if self.may_recover()
1966 && label.is_none()
1967 && let Some((ident, _)) = self.token.ident()
1968 {
1969 self.bump();
1970 label = Some(self.recover_ident_into_label(ident));
1971 }
1972
1973 let kind = ExprKind::Continue(label);
1974 Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
1975 }
1976
1977 fn parse_expr_yield(&mut self) -> PResult<'a, Box<Expr>> {
1979 let lo = self.prev_token.span;
1980 let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));
1981 let span = lo.to(self.prev_token.span);
1982 self.psess.gated_spans.gate(sym::yield_expr, span);
1983 let expr = self.mk_expr(span, kind);
1984 self.maybe_recover_from_bad_qpath(expr)
1985 }
1986
1987 fn parse_expr_builtin(&mut self) -> PResult<'a, Box<Expr>> {
1989 self.parse_builtin(|this, lo, ident| {
1990 Ok(match ident.name {
1991 sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
1992 sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
1993 sym::wrap_binder => {
1994 Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
1995 }
1996 sym::unwrap_binder => {
1997 Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
1998 }
1999 _ => None,
2000 })
2001 })
2002 }
2003
2004 pub(crate) fn parse_builtin<T>(
2005 &mut self,
2006 parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
2007 ) -> PResult<'a, T> {
2008 let lo = self.token.span;
2009
2010 self.bump(); self.bump(); let Some((ident, IdentIsRaw::No)) = self.token.ident() else {
2014 let err = self.dcx().create_err(errors::ExpectedBuiltinIdent { span: self.token.span });
2015 return Err(err);
2016 };
2017 self.psess.gated_spans.gate(sym::builtin_syntax, ident.span);
2018 self.bump();
2019
2020 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
2021 let ret = if let Some(res) = parse(self, lo, ident)? {
2022 Ok(res)
2023 } else {
2024 let err = self.dcx().create_err(errors::UnknownBuiltinConstruct {
2025 span: lo.to(ident.span),
2026 name: ident,
2027 });
2028 return Err(err);
2029 };
2030 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
2031
2032 ret
2033 }
2034
2035 pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
2037 let container = self.parse_ty()?;
2038 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
2039
2040 let fields = self.parse_floating_field_access()?;
2041 let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
2042
2043 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)]) {
2044 if trailing_comma {
2045 e.note("unexpected third argument to offset_of");
2046 } else {
2047 e.note("offset_of expects dot-separated field and variant names");
2048 }
2049 e.emit();
2050 }
2051
2052 if self.may_recover() {
2054 while !self.token.kind.is_close_delim_or_eof() {
2055 self.bump();
2056 }
2057 }
2058
2059 let span = lo.to(self.token.span);
2060 Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
2061 }
2062
2063 pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
2065 let expr = self.parse_expr()?;
2066 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
2067 let ty = self.parse_ty()?;
2068 let span = lo.to(self.token.span);
2069 Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
2070 }
2071
2072 pub(crate) fn parse_expr_unsafe_binder_cast(
2073 &mut self,
2074 lo: Span,
2075 kind: UnsafeBinderCastKind,
2076 ) -> PResult<'a, Box<Expr>> {
2077 let expr = self.parse_expr()?;
2078 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 };
2079 let span = lo.to(self.token.span);
2080 Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
2081 }
2082
2083 pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<MetaItemLit>> {
2087 match self.parse_opt_meta_item_lit() {
2088 Some(lit) => match lit.kind {
2089 ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
2090 style,
2091 symbol: lit.symbol,
2092 suffix: lit.suffix,
2093 span: lit.span,
2094 symbol_unescaped,
2095 }),
2096 _ => Err(Some(lit)),
2097 },
2098 None => Err(None),
2099 }
2100 }
2101
2102 pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) {
2103 (token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
2104 }
2105
2106 fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
2107 ast::MetaItemLit {
2108 symbol: name,
2109 suffix: None,
2110 kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),
2111 span,
2112 }
2113 }
2114
2115 fn handle_missing_lit<L>(
2116 &mut self,
2117 mk_lit_char: impl FnOnce(Symbol, Span) -> L,
2118 ) -> PResult<'a, L> {
2119 let token = self.token;
2120 let err = |self_: &Self| {
2121 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));
2122 self_.dcx().struct_span_err(token.span, msg)
2123 };
2124 if let Some((ident, IdentIsRaw::No)) = self.token.lifetime()
2127 && could_be_unclosed_char_literal(ident)
2128 {
2129 let lt = self.expect_lifetime();
2130 Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err))
2131 } else {
2132 Err(err(self))
2133 }
2134 }
2135
2136 pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> {
2137 self.parse_opt_token_lit()
2138 .ok_or(())
2139 .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char))
2140 }
2141
2142 pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> {
2143 self.parse_opt_meta_item_lit()
2144 .ok_or(())
2145 .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char))
2146 }
2147
2148 fn recover_after_dot(&mut self) {
2149 if self.token == token::Dot {
2150 let recovered = self.look_ahead(1, |next_token| {
2153 if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
2160 next_token.kind
2161 && suffix.is_none_or(|s| s == sym::f32 || s == sym::f64)
2162 && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
2163 && self.token.span.hi() == next_token.span.lo()
2164 {
2165 let s = String::from("0.") + symbol.as_str();
2166 let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
2167 Some(Token::new(kind, self.token.span.to(next_token.span)))
2168 } else {
2169 None
2170 }
2171 });
2172 if let Some(recovered) = recovered {
2173 self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart {
2174 span: recovered.span,
2175 suggestion: recovered.span.shrink_to_lo(),
2176 });
2177 self.bump();
2178 self.token = recovered;
2179 }
2180 }
2181 }
2182
2183 pub fn eat_token_lit(&mut self) -> Option<token::Lit> {
2186 let check_expr = |expr: Box<Expr>| {
2187 if let ast::ExprKind::Lit(token_lit) = expr.kind {
2188 Some(token_lit)
2189 } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind
2190 && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner
2191 {
2192 None
2193 } else {
2194 {
::core::panicking::panic_fmt(format_args!("unexpected reparsed expr/literal: {0:?}",
expr.kind));
};panic!("unexpected reparsed expr/literal: {:?}", expr.kind);
2195 }
2196 };
2197 match self.token.uninterpolate().kind {
2198 token::Ident(name, IdentIsRaw::No) if name.is_bool_lit() => {
2199 self.bump();
2200 Some(token::Lit::new(token::Bool, name, None))
2201 }
2202 token::Literal(token_lit) => {
2203 self.bump();
2204 Some(token_lit)
2205 }
2206 token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => {
2207 let lit = self
2208 .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2209 .expect("metavar seq literal");
2210 check_expr(lit)
2211 }
2212 token::OpenInvisible(InvisibleOrigin::MetaVar(
2213 mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. },
2214 )) => {
2215 let expr = self
2216 .eat_metavar_seq(mv_kind, |this| this.parse_expr())
2217 .expect("metavar seq expr");
2218 check_expr(expr)
2219 }
2220 _ => None,
2221 }
2222 }
2223
2224 fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> {
2227 self.recover_after_dot();
2228 let span = self.token.span;
2229 self.eat_token_lit().map(|token_lit| (token_lit, span))
2230 }
2231
2232 fn parse_opt_meta_item_lit(&mut self) -> Option<MetaItemLit> {
2235 self.recover_after_dot();
2236 let span = self.token.span;
2237 let uninterpolated_span = self.token_uninterpolated_span();
2238 self.eat_token_lit().map(|token_lit| {
2239 match MetaItemLit::from_token_lit(token_lit, span) {
2240 Ok(lit) => lit,
2241 Err(err) => {
2242 let guar = report_lit_error(&self.psess, err, token_lit, uninterpolated_span);
2243 let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
2246 let symbol = Symbol::intern(&suffixless_lit.to_string());
2247 let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
2248 MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
2249 }
2250 }
2251 })
2252 }
2253
2254 pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> {
2257 if let Some(expr) = self.eat_metavar_seq_with_matcher(
2258 |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
MetaVarKind::Expr { .. } => true,
_ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
2259 |this| {
2260 this.parse_expr()
2271 },
2272 ) {
2273 return Ok(expr);
2274 } else if let Some(lit) =
2275 self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2276 {
2277 return Ok(lit);
2278 }
2279
2280 let lo = self.token.span;
2281 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));
2282 let (token_lit, span) = self.parse_token_lit()?;
2283 let expr = self.mk_expr(span, ExprKind::Lit(token_lit));
2284
2285 if minus_present {
2286 Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr)))
2287 } else {
2288 Ok(expr)
2289 }
2290 }
2291
2292 fn is_array_like_block(&mut self) -> bool {
2293 self.token.kind == TokenKind::OpenBrace
2294 && self
2295 .look_ahead(1, |t| #[allow(non_exhaustive_omitted_patterns)] match t.kind {
TokenKind::Ident(..) | TokenKind::Literal(_) => true,
_ => false,
}matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
2296 && self.look_ahead(2, |t| t == &token::Comma)
2297 && self.look_ahead(3, |t| t.can_begin_expr())
2298 }
2299
2300 fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<Box<Expr>> {
2304 let mut snapshot = self.create_snapshot_for_diagnostic();
2305 match snapshot.parse_expr_array_or_repeat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
2306 Ok(arr) => {
2307 let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfBraces {
2308 span: arr.span,
2309 sub: errors::ArrayBracketsInsteadOfBracesSugg {
2310 left: lo,
2311 right: snapshot.prev_token.span,
2312 },
2313 });
2314
2315 self.restore_snapshot(snapshot);
2316 Some(self.mk_expr_err(arr.span, guar))
2317 }
2318 Err(e) => {
2319 e.cancel();
2320 None
2321 }
2322 }
2323 }
2324
2325 fn suggest_missing_semicolon_before_array(
2326 &self,
2327 prev_span: Span,
2328 open_delim_span: Span,
2329 ) -> PResult<'a, ()> {
2330 if !self.may_recover() {
2331 return Ok(());
2332 }
2333
2334 if self.token == token::Comma {
2335 if !self.psess.source_map().is_multiline(prev_span.until(self.token.span)) {
2336 return Ok(());
2337 }
2338 let mut snapshot = self.create_snapshot_for_diagnostic();
2339 snapshot.bump();
2340 match snapshot.parse_seq_to_before_end(
2341 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBracket,
token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket),
2342 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2343 |p| p.parse_expr(),
2344 ) {
2345 Ok(_)
2346 if snapshot
2352 .span_to_snippet(snapshot.token.span)
2353 .is_ok_and(|snippet| snippet == "]") =>
2354 {
2355 return Err(self.dcx().create_err(errors::MissingSemicolonBeforeArray {
2356 open_delim: open_delim_span,
2357 semicolon: prev_span.shrink_to_hi(),
2358 }));
2359 }
2360 Ok(_) => (),
2361 Err(err) => err.cancel(),
2362 }
2363 }
2364 Ok(())
2365 }
2366
2367 pub(super) fn parse_expr_block(
2369 &mut self,
2370 opt_label: Option<Label>,
2371 lo: Span,
2372 blk_mode: BlockCheckMode,
2373 ) -> PResult<'a, Box<Expr>> {
2374 if self.may_recover() && self.is_array_like_block() {
2375 if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) {
2376 return Ok(arr);
2377 }
2378 }
2379
2380 if self.token.is_metavar_block() {
2381 self.dcx().emit_err(errors::InvalidBlockMacroSegment {
2382 span: self.token.span,
2383 context: lo.to(self.token.span),
2384 wrap: errors::WrapInExplicitBlock {
2385 lo: self.token.span.shrink_to_lo(),
2386 hi: self.token.span.shrink_to_hi(),
2387 },
2388 });
2389 }
2390
2391 let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?;
2392 Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
2393 }
2394
2395 fn parse_simple_block(&mut self) -> PResult<'a, Box<Expr>> {
2397 let blk = self.parse_block()?;
2398 Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None)))
2399 }
2400
2401 fn parse_expr_closure(&mut self) -> PResult<'a, Box<Expr>> {
2403 let lo = self.token.span;
2404
2405 let before = self.prev_token;
2406 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)) {
2407 let lo = self.token.span;
2408 let (bound_vars, _) = self.parse_higher_ranked_binder()?;
2409 let span = lo.to(self.prev_token.span);
2410
2411 self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
2412
2413 ClosureBinder::For { span, generic_params: bound_vars }
2414 } else {
2415 ClosureBinder::NotPresent
2416 };
2417
2418 let constness = self.parse_closure_constness();
2419
2420 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)) {
2421 self.psess.gated_spans.gate(sym::coroutines, self.prev_token.span);
2422 Movability::Static
2423 } else {
2424 Movability::Movable
2425 };
2426
2427 let coroutine_kind = if self.token_uninterpolated_span().at_least_rust_2018() {
2428 self.parse_coroutine_kind(Case::Sensitive)
2429 } else {
2430 None
2431 };
2432
2433 if let ClosureBinder::NotPresent = binder
2434 && coroutine_kind.is_some()
2435 {
2436 self.expected_token_types.insert(TokenType::OpenBrace);
2439 }
2440
2441 let capture_clause = self.parse_capture_clause()?;
2442 let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
2443 let decl_hi = self.prev_token.span;
2444 let mut body = match &fn_decl.output {
2445 FnRetTy::Default(_) => {
2447 let restrictions =
2448 self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2449 let prev = self.prev_token;
2450 let token = self.token;
2451 let attrs = self.parse_outer_attributes()?;
2452 match self.parse_expr_res(restrictions, attrs) {
2453 Ok((expr, _)) => expr,
2454 Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
2455 }
2456 }
2457 FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
2459 };
2460
2461 match coroutine_kind {
2462 Some(CoroutineKind::Async { .. }) => {}
2463 Some(CoroutineKind::Gen { span, .. }) | Some(CoroutineKind::AsyncGen { span, .. }) => {
2464 self.psess.gated_spans.gate(sym::gen_blocks, span);
2467 }
2468 None => {}
2469 }
2470
2471 if self.token == TokenKind::Semi
2472 && let Some(last) = self.token_cursor.stack.last()
2473 && let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = last.curr()
2474 && self.may_recover()
2475 {
2476 body = self.mk_expr_err(
2480 body.span,
2481 self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"),
2482 );
2483 }
2484
2485 let body_span = body.span;
2486
2487 let closure = self.mk_expr(
2488 lo.to(body.span),
2489 ExprKind::Closure(Box::new(ast::Closure {
2490 binder,
2491 capture_clause,
2492 constness,
2493 coroutine_kind,
2494 movability,
2495 fn_decl,
2496 body,
2497 fn_decl_span: lo.to(decl_hi),
2498 fn_arg_span,
2499 })),
2500 );
2501
2502 let spans =
2504 ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
2505 self.current_closure = Some(spans);
2506
2507 Ok(closure)
2508 }
2509
2510 fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, Box<Expr>> {
2512 if self.may_recover()
2513 && self.token.can_begin_expr()
2514 && self.token.kind != TokenKind::OpenBrace
2515 && !self.token.is_metavar_block()
2516 {
2517 let snapshot = self.create_snapshot_for_diagnostic();
2518 let restrictions =
2519 self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2520 let tok = self.token.clone();
2521 match self.parse_expr_res(restrictions, AttrWrapper::empty()) {
2522 Ok((expr, _)) => {
2523 let descr = super::token_descr(&tok);
2524 let mut diag = self
2525 .dcx()
2526 .struct_span_err(tok.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected `{{`, found {0}", descr))
})format!("expected `{{`, found {descr}"));
2527 diag.span_label(
2528 ret_span,
2529 "explicit return type requires closure body to be enclosed in braces",
2530 );
2531 diag.multipart_suggestion_verbose(
2532 "wrap the expression in curly braces",
2533 <[_]>::into_vec(::alloc::boxed::box_new([(expr.span.shrink_to_lo(),
"{ ".to_string()),
(expr.span.shrink_to_hi(), " }".to_string())]))vec![
2534 (expr.span.shrink_to_lo(), "{ ".to_string()),
2535 (expr.span.shrink_to_hi(), " }".to_string()),
2536 ],
2537 Applicability::MachineApplicable,
2538 );
2539 diag.emit();
2540 return Ok(expr);
2541 }
2542 Err(diag) => {
2543 diag.cancel();
2544 self.restore_snapshot(snapshot);
2545 }
2546 }
2547 }
2548
2549 let body_lo = self.token.span;
2550 self.parse_expr_block(None, body_lo, BlockCheckMode::Default)
2551 }
2552
2553 fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
2555 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)) {
2556 let move_kw_span = self.prev_token.span;
2557 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)) {
2559 let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2560 Err(self
2561 .dcx()
2562 .create_err(errors::AsyncMoveOrderIncorrect { span: move_async_span }))
2563 } else {
2564 Ok(CaptureBy::Value { move_kw: move_kw_span })
2565 }
2566 } 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)) {
2567 let use_kw_span = self.prev_token.span;
2568 self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
2569 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)) {
2571 let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2572 Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span }))
2573 } else {
2574 Ok(CaptureBy::Use { use_kw: use_kw_span })
2575 }
2576 } else {
2577 Ok(CaptureBy::Ref)
2578 }
2579 }
2580
2581 fn parse_fn_block_decl(&mut self) -> PResult<'a, (Box<FnDecl>, Span)> {
2583 let arg_start = self.token.span.lo();
2584
2585 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)) {
2586 ThinVec::new()
2587 } else {
2588 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Or,
token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or))?;
2589 let args = self
2590 .parse_seq_to_before_tokens(
2591 &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Or,
token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or)],
2592 &[&token::OrOr],
2593 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2594 |p| p.parse_fn_block_param(),
2595 )?
2596 .0;
2597 self.expect_or()?;
2598 args
2599 };
2600 let arg_span = self.prev_token.span.with_lo(arg_start);
2601 let output =
2602 self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
2603
2604 Ok((Box::new(FnDecl { inputs, output }), arg_span))
2605 }
2606
2607 fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
2609 let lo = self.token.span;
2610 let attrs = self.parse_outer_attributes()?;
2611 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
2612 let pat = Box::new(this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?);
2613 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)) {
2614 this.parse_ty()?
2615 } else {
2616 this.mk_ty(pat.span, TyKind::Infer)
2617 };
2618
2619 Ok((
2620 Param {
2621 attrs,
2622 ty,
2623 pat,
2624 span: lo.to(this.prev_token.span),
2625 id: DUMMY_NODE_ID,
2626 is_placeholder: false,
2627 },
2628 Trailing::from(this.token == token::Comma),
2629 UsePreAttrPos::No,
2630 ))
2631 })
2632 }
2633
2634 fn parse_expr_if(&mut self) -> PResult<'a, Box<Expr>> {
2636 let lo = self.prev_token.span;
2637 let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2640 let cond = self.parse_expr_cond(let_chains_policy)?;
2641 self.parse_if_after_cond(lo, cond)
2642 }
2643
2644 fn parse_if_after_cond(&mut self, lo: Span, mut cond: Box<Expr>) -> PResult<'a, Box<Expr>> {
2645 let cond_span = cond.span;
2646 let mut recover_block_from_condition = |this: &mut Self| {
2650 let block = match &mut cond.kind {
2651 ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
2652 if let ExprKind::Block(_, None) = right.kind =>
2653 {
2654 let guar = this.dcx().emit_err(errors::IfExpressionMissingThenBlock {
2655 if_span: lo,
2656 missing_then_block_sub:
2657 errors::IfExpressionMissingThenBlockSub::UnfinishedCondition(
2658 cond_span.shrink_to_lo().to(*binop_span),
2659 ),
2660 let_else_sub: None,
2661 });
2662 std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar))
2663 }
2664 ExprKind::Block(_, None) => {
2665 let guar = this.dcx().emit_err(errors::IfExpressionMissingCondition {
2666 if_span: lo.with_neighbor(cond.span).shrink_to_hi(),
2667 block_span: self.psess.source_map().start_point(cond_span),
2668 });
2669 std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar))
2670 }
2671 _ => {
2672 return None;
2673 }
2674 };
2675 if let ExprKind::Block(block, _) = &block.kind {
2676 Some(block.clone())
2677 } else {
2678 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
2679 }
2680 };
2681 let thn = if self.token.is_keyword(kw::Else) {
2683 if let Some(block) = recover_block_from_condition(self) {
2684 block
2685 } else {
2686 let let_else_sub = #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
ExprKind::Let(..) => true,
_ => false,
}matches!(cond.kind, ExprKind::Let(..))
2687 .then(|| errors::IfExpressionLetSomeSub { if_span: lo.until(cond_span) });
2688
2689 let guar = self.dcx().emit_err(errors::IfExpressionMissingThenBlock {
2690 if_span: lo,
2691 missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::AddThenBlock(
2692 cond_span.shrink_to_hi(),
2693 ),
2694 let_else_sub,
2695 });
2696 self.mk_block_err(cond_span.shrink_to_hi(), guar)
2697 }
2698 } else {
2699 let attrs = self.parse_outer_attributes()?; let maybe_fatarrow = self.token;
2701 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)) {
2702 self.parse_block()?
2703 } else if let Some(block) = recover_block_from_condition(self) {
2704 block
2705 } else {
2706 self.error_on_extra_if(&cond)?;
2707 self.parse_block().map_err(|mut err| {
2709 if self.prev_token == token::Semi
2710 && self.token == token::AndAnd
2711 && let maybe_let = self.look_ahead(1, |t| t.clone())
2712 && maybe_let.is_keyword(kw::Let)
2713 {
2714 err.span_suggestion(
2715 self.prev_token.span,
2716 "consider removing this semicolon to parse the `let` as part of the same chain",
2717 "",
2718 Applicability::MachineApplicable,
2719 ).span_note(
2720 self.token.span.to(maybe_let.span),
2721 "you likely meant to continue parsing the let-chain starting here",
2722 );
2723 } else {
2724 if maybe_fatarrow == token::FatArrow {
2726 err.span_suggestion(
2727 maybe_fatarrow.span,
2728 "you might have meant to write a \"greater than or equal to\" comparison",
2729 ">=",
2730 Applicability::MaybeIncorrect,
2731 );
2732 }
2733 err.span_note(
2734 cond_span,
2735 "the `if` expression is missing a block after this condition",
2736 );
2737 }
2738 err
2739 })?
2740 };
2741 self.error_on_if_block_attrs(lo, false, block.span, attrs);
2742 block
2743 };
2744 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 };
2745 Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
2746 }
2747
2748 pub fn parse_expr_cond(
2755 &mut self,
2756 let_chains_policy: LetChainsPolicy,
2757 ) -> PResult<'a, Box<Expr>> {
2758 let attrs = self.parse_outer_attributes()?;
2759 let (mut cond, _) =
2760 self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
2761
2762 let mut checker = CondChecker::new(self, let_chains_policy);
2763 checker.visit_expr(&mut cond);
2764 Ok(if let Some(guar) = checker.found_incorrect_let_chain {
2765 self.mk_expr_err(cond.span, guar)
2766 } else {
2767 cond
2768 })
2769 }
2770
2771 fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
2773 let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
2774 let err = errors::ExpectedExpressionFoundLet {
2775 span: self.token.span,
2776 reason: errors::ForbiddenLetReason::OtherForbidden,
2777 missing_let: None,
2778 comparison: None,
2779 };
2780 if self.prev_token == token::Or {
2781 return Err(self.dcx().create_err(err));
2783 } else {
2784 Recovered::Yes(self.dcx().emit_err(err))
2785 }
2786 } else {
2787 Recovered::No
2788 };
2789 self.bump(); let lo = self.prev_token.span;
2791 let pat = self.parse_pat_no_top_guard(
2792 None,
2793 RecoverComma::Yes,
2794 RecoverColon::Yes,
2795 CommaRecoveryMode::LikelyTuple,
2796 )?;
2797 if self.token == token::EqEq {
2798 self.dcx().emit_err(errors::ExpectedEqForLetExpr {
2799 span: self.token.span,
2800 sugg_span: self.token.span,
2801 });
2802 self.bump();
2803 } else {
2804 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq))?;
2805 }
2806 let attrs = self.parse_outer_attributes()?;
2807 let (expr, _) =
2808 self.parse_expr_assoc_with(Bound::Excluded(prec_let_scrutinee_needs_par()), attrs)?;
2809 let span = lo.to(expr.span);
2810 Ok(self.mk_expr(span, ExprKind::Let(Box::new(pat), expr, span, recovered)))
2811 }
2812
2813 fn parse_expr_else(&mut self) -> PResult<'a, Box<Expr>> {
2815 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)) {
2818 ensure_sufficient_stack(|| self.parse_expr_if())?
2819 } else if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2820 self.parse_simple_block()?
2821 } else {
2822 let snapshot = self.create_snapshot_for_diagnostic();
2823 let first_tok = super::token_descr(&self.token);
2824 let first_tok_span = self.token.span;
2825 match self.parse_expr() {
2826 Ok(cond)
2827 if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
2862 && (classify::expr_requires_semi_to_be_stmt(&cond)
2863 || #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
ExprKind::MacCall(..) => true,
_ => false,
}matches!(cond.kind, ExprKind::MacCall(..)))
2864 =>
2865 {
2866 self.dcx().emit_err(errors::ExpectedElseBlock {
2867 first_tok_span,
2868 first_tok,
2869 else_span,
2870 condition_start: cond.span.shrink_to_lo(),
2871 });
2872 self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
2873 }
2874 Err(e) => {
2875 e.cancel();
2876 self.restore_snapshot(snapshot);
2877 self.parse_simple_block()?
2878 },
2879 Ok(_) => {
2880 self.restore_snapshot(snapshot);
2881 self.parse_simple_block()?
2882 },
2883 }
2884 };
2885 self.error_on_if_block_attrs(else_span, true, expr.span, attrs);
2886 Ok(expr)
2887 }
2888
2889 fn error_on_if_block_attrs(
2890 &self,
2891 ctx_span: Span,
2892 is_ctx_else: bool,
2893 branch_span: Span,
2894 attrs: AttrWrapper,
2895 ) {
2896 if !attrs.is_empty()
2897 && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
2898 {
2899 let attributes = x0.span.until(branch_span);
2900 let last = xn.span;
2901 let ctx = if is_ctx_else { "else" } else { "if" };
2902 self.dcx().emit_err(errors::OuterAttributeNotAllowedOnIfElse {
2903 last,
2904 branch_span,
2905 ctx_span,
2906 ctx: ctx.to_string(),
2907 attributes,
2908 });
2909 }
2910 }
2911
2912 fn error_on_extra_if(&mut self, cond: &Box<Expr>) -> PResult<'a, ()> {
2913 if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind
2914 && let BinOpKind::And = binop
2915 && let ExprKind::If(cond, ..) = &right.kind
2916 {
2917 Err(self.dcx().create_err(errors::UnexpectedIfWithIf(
2918 binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()),
2919 )))
2920 } else {
2921 Ok(())
2922 }
2923 }
2924
2925 pub fn parse_for_head(&mut self) -> PResult<'a, (Pat, Box<Expr>)> {
2927 let begin_paren = if self.token == token::OpenParen {
2928 let start_span = self.token.span;
2932 let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2933 Some((start_span, left))
2934 } else {
2935 None
2936 };
2937 let pat = match (
2939 self.parse_pat_allow_top_guard(
2940 None,
2941 RecoverComma::Yes,
2942 RecoverColon::Yes,
2943 CommaRecoveryMode::LikelyTuple,
2944 ),
2945 begin_paren,
2946 ) {
2947 (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)) => {
2949 let attrs = self.parse_outer_attributes()?;
2952 let (expr, _) = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs) {
2953 Ok(expr) => expr,
2954 Err(expr_err) => {
2955 expr_err.cancel();
2958 return Err(err);
2959 }
2960 };
2961 return if self.token == token::CloseParen {
2962 let span = <[_]>::into_vec(::alloc::boxed::box_new([start_span, self.token.span]))vec![start_span, self.token.span];
2965 let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2966 self.bump(); err.cancel();
2968 self.dcx().emit_err(errors::ParenthesesInForHead {
2969 span,
2970 sugg: errors::ParenthesesInForHeadSugg { left, right },
2974 });
2975 Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
2976 } else {
2977 Err(err) };
2979 }
2980 (Err(err), _) => return Err(err), };
2982 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)) {
2983 self.error_missing_in_for_loop();
2984 }
2985 self.check_for_for_in_in_typo(self.prev_token.span);
2986 let attrs = self.parse_outer_attributes()?;
2987 let (expr, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?;
2988 Ok((pat, expr))
2989 }
2990
2991 fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
2993 let is_await =
2994 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));
2995
2996 if is_await {
2997 self.psess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
2998 }
2999
3000 let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For };
3001
3002 let (pat, expr) = self.parse_for_head()?;
3003 let pat = Box::new(pat);
3004 if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ExprKind::Block(..) => true,
_ => false,
}matches!(expr.kind, ExprKind::Block(..))
3006 && self.token.kind != token::OpenBrace
3007 && self.may_recover()
3008 {
3009 let guar = self
3010 .dcx()
3011 .emit_err(errors::MissingExpressionInForLoop { span: expr.span.shrink_to_lo() });
3012 let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar));
3013 let block = self.mk_block(::thin_vec::ThinVec::new()thin_vec![], BlockCheckMode::Default, self.prev_token.span);
3014 return Ok(self.mk_expr(
3015 lo.to(self.prev_token.span),
3016 ExprKind::ForLoop { pat, iter: err_expr, body: block, label: opt_label, kind },
3017 ));
3018 }
3019
3020 let (attrs, loop_block) = self.parse_inner_attrs_and_block(
3021 opt_label.is_none().then_some(lo),
3024 )?;
3025
3026 let kind = ExprKind::ForLoop { pat, iter: expr, body: loop_block, label: opt_label, kind };
3027
3028 self.recover_loop_else("for", lo)?;
3029
3030 Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3031 }
3032
3033 fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> {
3035 if self.token.is_keyword(kw::Else) && self.may_recover() {
3036 let else_span = self.token.span;
3037 self.bump();
3038 let else_clause = self.parse_expr_else()?;
3039 self.dcx().emit_err(errors::LoopElseNotSupported {
3040 span: else_span.to(else_clause.span),
3041 loop_kind,
3042 loop_kw,
3043 });
3044 }
3045 Ok(())
3046 }
3047
3048 fn error_missing_in_for_loop(&mut self) {
3049 let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) {
3050 let span = self.token.span;
3052 self.bump();
3053 (span, errors::MissingInInForLoopSub::InNotOf)
3054 } else if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) {
3055 (self.prev_token.span, errors::MissingInInForLoopSub::InNotEq)
3056 } else {
3057 (self.prev_token.span.between(self.token.span), errors::MissingInInForLoopSub::AddIn)
3058 };
3059
3060 self.dcx().emit_err(errors::MissingInInForLoop { span, sub: sub(span) });
3061 }
3062
3063 fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3065 let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
3066 let cond = self.parse_expr_cond(policy).map_err(|mut err| {
3067 err.span_label(lo, "while parsing the condition of this `while` expression");
3068 err
3069 })?;
3070 let (attrs, body) = self
3071 .parse_inner_attrs_and_block(
3072 opt_label.is_none().then_some(lo),
3075 )
3076 .map_err(|mut err| {
3077 err.span_label(lo, "while parsing the body of this `while` expression");
3078 err.span_label(cond.span, "this `while` condition successfully parsed");
3079 err
3080 })?;
3081
3082 self.recover_loop_else("while", lo)?;
3083
3084 Ok(self.mk_expr_with_attrs(
3085 lo.to(self.prev_token.span),
3086 ExprKind::While(cond, body, opt_label),
3087 attrs,
3088 ))
3089 }
3090
3091 fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3093 let loop_span = self.prev_token.span;
3094 let (attrs, body) = self.parse_inner_attrs_and_block(
3095 opt_label.is_none().then_some(lo),
3098 )?;
3099 self.recover_loop_else("loop", lo)?;
3100 Ok(self.mk_expr_with_attrs(
3101 lo.to(self.prev_token.span),
3102 ExprKind::Loop(body, opt_label, loop_span),
3103 attrs,
3104 ))
3105 }
3106
3107 pub(crate) fn eat_label(&mut self) -> Option<Label> {
3108 if let Some((ident, is_raw)) = self.token.lifetime() {
3109 if is_raw == IdentIsRaw::No && ident.without_first_quote().is_reserved() {
3111 self.dcx().emit_err(errors::KeywordLabel { span: ident.span });
3112 }
3113
3114 self.bump();
3115 Some(Label { ident })
3116 } else {
3117 None
3118 }
3119 }
3120
3121 fn parse_expr_match(&mut self) -> PResult<'a, Box<Expr>> {
3123 let match_span = self.prev_token.span;
3124 let attrs = self.parse_outer_attributes()?;
3125 let (scrutinee, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?;
3126
3127 self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
3128 }
3129
3130 fn parse_match_block(
3133 &mut self,
3134 lo: Span,
3135 match_span: Span,
3136 scrutinee: Box<Expr>,
3137 match_kind: MatchKind,
3138 ) -> PResult<'a, Box<Expr>> {
3139 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)) {
3140 if self.token == token::Semi {
3141 e.span_suggestion_short(
3142 match_span,
3143 "try removing this `match`",
3144 "",
3145 Applicability::MaybeIncorrect, );
3147 }
3148 if self.maybe_recover_unexpected_block_label(None) {
3149 e.cancel();
3150 self.bump();
3151 } else {
3152 return Err(e);
3153 }
3154 }
3155 let attrs = self.parse_inner_attributes()?;
3156
3157 let mut arms = ThinVec::new();
3158 while self.token != token::CloseBrace {
3159 match self.parse_arm() {
3160 Ok(arm) => arms.push(arm),
3161 Err(e) => {
3162 let guar = e.emit();
3164 self.recover_stmt();
3165 let span = lo.to(self.token.span);
3166 if self.token == token::CloseBrace {
3167 self.bump();
3168 }
3169 arms.push(Arm {
3171 attrs: Default::default(),
3172 pat: Box::new(self.mk_pat(span, ast::PatKind::Err(guar))),
3173 guard: None,
3174 body: Some(self.mk_expr_err(span, guar)),
3175 span,
3176 id: DUMMY_NODE_ID,
3177 is_placeholder: false,
3178 });
3179 return Ok(self.mk_expr_with_attrs(
3180 span,
3181 ExprKind::Match(scrutinee, arms, match_kind),
3182 attrs,
3183 ));
3184 }
3185 }
3186 }
3187 let hi = self.token.span;
3188 self.bump();
3189 Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
3190 }
3191
3192 fn parse_arm_body_missing_braces(
3194 &mut self,
3195 first_expr: &Box<Expr>,
3196 arrow_span: Span,
3197 ) -> Option<(Span, ErrorGuaranteed)> {
3198 if self.token != token::Semi {
3199 return None;
3200 }
3201 let start_snapshot = self.create_snapshot_for_diagnostic();
3202 let semi_sp = self.token.span;
3203 self.bump(); let mut stmts =
3205 <[_]>::into_vec(::alloc::boxed::box_new([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()))];
3206 let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
3207 let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
3208
3209 let guar = this.dcx().emit_err(errors::MatchArmBodyWithoutBraces {
3210 statements: span,
3211 arrow: arrow_span,
3212 num_statements: stmts.len(),
3213 sub: if stmts.len() > 1 {
3214 errors::MatchArmBodyWithoutBracesSugg::AddBraces {
3215 left: span.shrink_to_lo(),
3216 right: span.shrink_to_hi(),
3217 }
3218 } else {
3219 errors::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
3220 },
3221 });
3222 (span, guar)
3223 };
3224 loop {
3227 if self.token == token::CloseBrace {
3228 return Some(err(self, stmts));
3230 }
3231 if self.token == token::Comma {
3232 self.restore_snapshot(start_snapshot);
3233 return None;
3234 }
3235 let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
3236 match self.parse_pat_no_top_alt(None, None) {
3237 Ok(_pat) => {
3238 if self.token == token::FatArrow {
3239 self.restore_snapshot(pre_pat_snapshot);
3241 return Some(err(self, stmts));
3242 }
3243 }
3244 Err(err) => {
3245 err.cancel();
3246 }
3247 }
3248
3249 self.restore_snapshot(pre_pat_snapshot);
3250 match self.parse_stmt_without_recovery(true, ForceCollect::No, false) {
3251 Ok(Some(stmt)) => {
3253 stmts.push(stmt);
3254 }
3255 Ok(None) => {
3256 self.restore_snapshot(start_snapshot);
3257 break;
3258 }
3259 Err(stmt_err) => {
3262 stmt_err.cancel();
3263 self.restore_snapshot(start_snapshot);
3264 break;
3265 }
3266 }
3267 }
3268 None
3269 }
3270
3271 pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
3272 let attrs = self.parse_outer_attributes()?;
3273 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3274 let lo = this.token.span;
3275 let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
3276 let pat = Box::new(pat);
3277
3278 let span_before_body = this.prev_token.span;
3279 let arm_body;
3280 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));
3281 let is_almost_fat_arrow =
3282 TokenKind::FatArrow.similar_tokens().contains(&this.token.kind);
3283
3284 let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
3287 || #[allow(non_exhaustive_omitted_patterns)] match this.token.kind {
token::Comma | token::CloseBrace => true,
_ => false,
}matches!(this.token.kind, token::Comma | token::CloseBrace);
3288
3289 let mut result = if armless {
3290 arm_body = None;
3292 let span = lo.to(this.prev_token.span);
3293 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| {
3294 if !pat.contains_never_pattern() {
3296 this.psess.gated_spans.gate(sym::never_patterns, span);
3297 }
3298 x
3299 })
3300 } else {
3301 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)) {
3302 if is_almost_fat_arrow {
3304 err.span_suggestion(
3305 this.token.span,
3306 "use a fat arrow to start a match arm",
3307 "=>",
3308 Applicability::MachineApplicable,
3309 );
3310 if #[allow(non_exhaustive_omitted_patterns)] match (&this.prev_token.kind,
&this.token.kind) {
(token::DotDotEq, token::Gt) => true,
_ => false,
}matches!(
3311 (&this.prev_token.kind, &this.token.kind),
3312 (token::DotDotEq, token::Gt)
3313 ) {
3314 err.delay_as_bug();
3317 } else {
3318 err.emit();
3319 }
3320 this.bump();
3321 } else {
3322 return Err(err);
3323 }
3324 }
3325 let arrow_span = this.prev_token.span;
3326 let arm_start_span = this.token.span;
3327
3328 let attrs = this.parse_outer_attributes()?;
3329 let (expr, _) =
3330 this.parse_expr_res(Restrictions::STMT_EXPR, attrs).map_err(|mut err| {
3331 err.span_label(arrow_span, "while parsing the `match` arm starting here");
3332 err
3333 })?;
3334
3335 let require_comma =
3336 !classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
3337
3338 if !require_comma {
3339 arm_body = Some(expr);
3340 let _ = this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3342 Ok(Recovered::No)
3343 } else if let Some((span, guar)) =
3344 this.parse_arm_body_missing_braces(&expr, arrow_span)
3345 {
3346 let body = this.mk_expr_err(span, guar);
3347 arm_body = Some(body);
3348 Ok(Recovered::Yes(guar))
3349 } else {
3350 let expr_span = expr.span;
3351 arm_body = Some(expr);
3352 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| {
3353 if this.token == token::FatArrow {
3354 let sm = this.psess.source_map();
3355 if let Ok(expr_lines) = sm.span_to_lines(expr_span)
3356 && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
3357 && expr_lines.lines.len() == 2
3358 {
3359 if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col {
3360 err.span_suggestion_short(
3372 arm_start_span.shrink_to_hi(),
3373 "missing a comma here to end this `match` arm",
3374 ",",
3375 Applicability::MachineApplicable,
3376 );
3377 } else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1)
3378 == expr_lines.lines[0].end_col
3379 {
3380 let comma_span = arm_start_span
3382 .shrink_to_hi()
3383 .with_hi(arm_start_span.hi() + rustc_span::BytePos(1));
3384 if let Ok(res) = sm.span_to_snippet(comma_span)
3385 && (res == "." || res == "/")
3386 {
3387 err.span_suggestion_short(
3388 comma_span,
3389 "you might have meant to write a `,` to end this `match` arm",
3390 ",",
3391 Applicability::MachineApplicable,
3392 );
3393 }
3394 }
3395 }
3396 } else {
3397 err.span_label(
3398 arrow_span,
3399 "while parsing the `match` arm starting here",
3400 );
3401 }
3402 err
3403 })
3404 }
3405 };
3406
3407 let hi_span = arm_body.as_ref().map_or(span_before_body, |body| body.span);
3408 let arm_span = lo.to(hi_span);
3409
3410 let recover_missing_comma = arm_body.is_some() || pat.could_be_never_pattern();
3424 if recover_missing_comma {
3425 result = result.or_else(|err| {
3426 let mut snapshot = this.create_snapshot_for_diagnostic();
3431 let pattern_follows = snapshot
3432 .parse_pat_no_top_guard(
3433 None,
3434 RecoverComma::Yes,
3435 RecoverColon::Yes,
3436 CommaRecoveryMode::EitherTupleOrPipe,
3437 )
3438 .map_err(|err| err.cancel())
3439 .is_ok();
3440 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)) {
3441 err.cancel();
3442 let guar = this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
3443 span: arm_span.shrink_to_hi(),
3444 });
3445 return Ok(Recovered::Yes(guar));
3446 }
3447 Err(err)
3448 });
3449 }
3450 result?;
3451
3452 Ok((
3453 ast::Arm {
3454 attrs,
3455 pat,
3456 guard,
3457 body: arm_body,
3458 span: arm_span,
3459 id: DUMMY_NODE_ID,
3460 is_placeholder: false,
3461 },
3462 Trailing::No,
3463 UsePreAttrPos::No,
3464 ))
3465 })
3466 }
3467
3468 fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Expr>>> {
3469 fn has_let_expr(expr: &Expr) -> bool {
3472 match &expr.kind {
3473 ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
3474 let lhs_rslt = has_let_expr(lhs);
3475 let rhs_rslt = has_let_expr(rhs);
3476 lhs_rslt || rhs_rslt
3477 }
3478 ExprKind::Let(..) => true,
3479 _ => false,
3480 }
3481 }
3482 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)) {
3483 return Ok(None);
3485 }
3486
3487 let if_span = self.prev_token.span;
3488 let mut cond = self.parse_match_guard_condition()?;
3489
3490 let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3491 checker.visit_expr(&mut cond);
3492
3493 if has_let_expr(&cond) {
3494 let span = if_span.to(cond.span);
3495 self.psess.gated_spans.gate(sym::if_let_guard, span);
3496 }
3497
3498 Ok(Some(if let Some(guar) = checker.found_incorrect_let_chain {
3499 self.mk_expr_err(cond.span, guar)
3500 } else {
3501 cond
3502 }))
3503 }
3504
3505 fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr>>)> {
3506 if self.token == token::OpenParen {
3507 let left = self.token.span;
3508 let pat = self.parse_pat_no_top_guard(
3509 None,
3510 RecoverComma::Yes,
3511 RecoverColon::Yes,
3512 CommaRecoveryMode::EitherTupleOrPipe,
3513 )?;
3514 if let ast::PatKind::Paren(subpat) = &pat.kind
3515 && let ast::PatKind::Guard(..) = &subpat.kind
3516 {
3517 let span = pat.span;
3520 let ast::PatKind::Paren(subpat) = pat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3521 let ast::PatKind::Guard(_, mut cond) = subpat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3522 self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
3523 let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3524 checker.visit_expr(&mut cond);
3525
3526 let right = self.prev_token.span;
3527 self.dcx().emit_err(errors::ParenthesesInMatchPat {
3528 span: <[_]>::into_vec(::alloc::boxed::box_new([left, right]))vec![left, right],
3529 sugg: errors::ParenthesesInMatchPatSugg { left, right },
3530 });
3531
3532 Ok((
3533 self.mk_pat(span, ast::PatKind::Wild),
3534 (if let Some(guar) = checker.found_incorrect_let_chain {
3535 Some(self.mk_expr_err(cond.span, guar))
3536 } else {
3537 Some(cond)
3538 }),
3539 ))
3540 } else {
3541 Ok((pat, self.parse_match_arm_guard()?))
3542 }
3543 } else {
3544 let pat = self.parse_pat_no_top_guard(
3546 None,
3547 RecoverComma::Yes,
3548 RecoverColon::Yes,
3549 CommaRecoveryMode::EitherTupleOrPipe,
3550 )?;
3551 Ok((pat, self.parse_match_arm_guard()?))
3552 }
3553 }
3554
3555 fn parse_match_guard_condition(&mut self) -> PResult<'a, Box<Expr>> {
3556 let attrs = self.parse_outer_attributes()?;
3557 match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) {
3558 Ok((expr, _)) => Ok(expr),
3559 Err(mut err) => {
3560 if self.prev_token == token::OpenBrace {
3561 let sugg_sp = self.prev_token.span.shrink_to_lo();
3562 self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
3565 let msg = "you might have meant to start a match arm after the match guard";
3566 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
3567 let applicability = if self.token != token::FatArrow {
3568 Applicability::MachineApplicable
3573 } else {
3574 Applicability::MaybeIncorrect
3575 };
3576 err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
3577 }
3578 }
3579 Err(err)
3580 }
3581 }
3582 }
3583
3584 pub(crate) fn is_builtin(&self) -> bool {
3585 self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
3586 }
3587
3588 fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box<Expr>> {
3590 let annotation =
3591 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 };
3592
3593 let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3594 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)) {
3595 Err(self.dcx().create_err(errors::CatchAfterTry { span: self.prev_token.span }))
3596 } else {
3597 let span = span_lo.to(body.span);
3598 let gate_sym =
3599 if annotation.is_none() { sym::try_blocks } else { sym::try_blocks_heterogeneous };
3600 self.psess.gated_spans.gate(gate_sym, span);
3601 Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body, annotation), attrs))
3602 }
3603 }
3604
3605 fn is_do_catch_block(&self) -> bool {
3606 self.token.is_keyword(kw::Do)
3607 && self.is_keyword_ahead(1, &[kw::Catch])
3608 && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
3609 && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3610 }
3611
3612 fn is_do_yeet(&self) -> bool {
3613 self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
3614 }
3615
3616 fn is_try_block(&self) -> bool {
3617 self.token.is_keyword(kw::Try)
3618 && self.look_ahead(1, |t| {
3619 *t == token::OpenBrace
3620 || t.is_metavar_block()
3621 || t.kind == TokenKind::Ident(sym::bikeshed, IdentIsRaw::No)
3622 })
3623 && self.token_uninterpolated_span().at_least_rust_2018()
3624 }
3625
3626 fn parse_gen_block(&mut self) -> PResult<'a, Box<Expr>> {
3628 let lo = self.token.span;
3629 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)) {
3630 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)) { GenBlockKind::AsyncGen } else { GenBlockKind::Async }
3631 } else {
3632 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)));
3633 GenBlockKind::Gen
3634 };
3635 match kind {
3636 GenBlockKind::Async => {
3637 }
3639 GenBlockKind::Gen | GenBlockKind::AsyncGen => {
3640 self.psess.gated_spans.gate(sym::gen_blocks, lo.to(self.prev_token.span));
3641 }
3642 }
3643 let capture_clause = self.parse_capture_clause()?;
3644 let decl_span = lo.to(self.prev_token.span);
3645 let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3646 let kind = ExprKind::Gen(capture_clause, body, kind, decl_span);
3647 Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3648 }
3649
3650 fn is_gen_block(&self, kw: Symbol, lookahead: usize) -> bool {
3651 self.is_keyword_ahead(lookahead, &[kw])
3652 && ((
3653 self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
3655 && self.look_ahead(lookahead + 2, |t| {
3656 *t == token::OpenBrace || t.is_metavar_block()
3657 })
3658 ) || (
3659 self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
3661 ))
3662 }
3663
3664 pub(super) fn is_async_gen_block(&self) -> bool {
3665 self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1)
3666 }
3667
3668 fn is_likely_struct_lit(&self) -> bool {
3669 self.look_ahead(1, |t| t.is_ident())
3671 && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
3672 }
3673
3674 fn maybe_parse_struct_expr(
3675 &mut self,
3676 qself: &Option<Box<ast::QSelf>>,
3677 path: &ast::Path,
3678 ) -> Option<PResult<'a, Box<Expr>>> {
3679 let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
3680 match (struct_allowed, self.is_likely_struct_lit()) {
3681 (false, false) => None,
3686 (true, _) => {
3687 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)) {
3690 return Some(Err(err));
3691 }
3692 Some(self.parse_expr_struct(qself.clone(), path.clone(), true))
3693 }
3694 (false, true) => {
3695 let snapshot = self.create_snapshot_for_diagnostic();
3699 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)) {
3700 return Some(Err(err));
3701 }
3702 match self.parse_expr_struct(qself.clone(), path.clone(), false) {
3703 Ok(expr) => {
3704 self.dcx().emit_err(errors::StructLiteralNotAllowedHere {
3706 span: expr.span,
3707 sub: errors::StructLiteralNotAllowedHereSugg {
3708 left: path.span.shrink_to_lo(),
3709 right: expr.span.shrink_to_hi(),
3710 },
3711 });
3712 Some(Ok(expr))
3713 }
3714 Err(err) => {
3715 err.cancel();
3718 self.restore_snapshot(snapshot);
3719 None
3720 }
3721 }
3722 }
3723 }
3724 }
3725
3726 fn maybe_recover_bad_struct_literal_path(
3727 &mut self,
3728 is_underscore_entry_point: bool,
3729 ) -> PResult<'a, Option<Box<Expr>>> {
3730 if self.may_recover()
3731 && self.check_noexpect(&token::OpenBrace)
3732 && (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3733 && self.is_likely_struct_lit())
3734 {
3735 let span = if is_underscore_entry_point {
3736 self.prev_token.span
3737 } else {
3738 self.token.span.shrink_to_lo()
3739 };
3740
3741 self.bump(); let expr = self.parse_expr_struct(
3743 None,
3744 Path::from_ident(Ident::new(kw::Underscore, span)),
3745 false,
3746 )?;
3747
3748 let guar = if is_underscore_entry_point {
3749 self.dcx().create_err(errors::StructLiteralPlaceholderPath { span }).emit()
3750 } else {
3751 self.dcx()
3752 .create_err(errors::StructLiteralWithoutPathLate {
3753 span: expr.span,
3754 suggestion_span: expr.span.shrink_to_lo(),
3755 })
3756 .emit()
3757 };
3758
3759 Ok(Some(self.mk_expr_err(expr.span, guar)))
3760 } else {
3761 Ok(None)
3762 }
3763 }
3764
3765 pub(super) fn parse_struct_fields(
3766 &mut self,
3767 pth: ast::Path,
3768 recover: bool,
3769 close: ExpTokenPair,
3770 ) -> PResult<
3771 'a,
3772 (
3773 ThinVec<ExprField>,
3774 ast::StructRest,
3775 Option<ErrorGuaranteed>, ),
3777 > {
3778 let mut fields = ThinVec::new();
3779 let mut base = ast::StructRest::None;
3780 let mut recovered_async = None;
3781 let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);
3782
3783 let async_block_err = |e: &mut Diag<'_>, span: Span| {
3784 errors::AsyncBlockIn2015 { span }.add_to_diag(e);
3785 errors::HelpUseLatestEdition::new().add_to_diag(e);
3786 };
3787
3788 while self.token != close.tok {
3789 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) {
3790 let exp_span = self.prev_token.span;
3791 if self.check(close) {
3793 base = ast::StructRest::Rest(self.prev_token.span);
3794 break;
3795 }
3796 match self.parse_expr() {
3797 Ok(e) => base = ast::StructRest::Base(e),
3798 Err(e) if recover => {
3799 e.emit();
3800 self.recover_stmt();
3801 }
3802 Err(e) => return Err(e),
3803 }
3804 self.recover_struct_comma_after_dotdot(exp_span);
3805 break;
3806 }
3807
3808 let peek = self
3810 .token
3811 .ident()
3812 .filter(|(ident, is_raw)| {
3813 (!ident.is_reserved() || #[allow(non_exhaustive_omitted_patterns)] match is_raw {
IdentIsRaw::Yes => true,
_ => false,
}matches!(is_raw, IdentIsRaw::Yes))
3814 && self.look_ahead(1, |tok| *tok == token::Colon)
3815 })
3816 .map(|(ident, _)| ident);
3817
3818 let field_ident = |this: &Self, guar: ErrorGuaranteed| {
3820 peek.map(|ident| {
3821 let span = ident.span;
3822 ExprField {
3823 ident,
3824 span,
3825 expr: this.mk_expr_err(span, guar),
3826 is_shorthand: false,
3827 attrs: AttrVec::new(),
3828 id: DUMMY_NODE_ID,
3829 is_placeholder: false,
3830 }
3831 })
3832 };
3833
3834 let parsed_field = match self.parse_expr_field() {
3835 Ok(f) => Ok(f),
3836 Err(mut e) => {
3837 if pth == kw::Async {
3838 async_block_err(&mut e, pth.span);
3839 } else {
3840 e.span_label(pth.span, "while parsing this struct");
3841 }
3842
3843 if let Some((ident, _)) = self.token.ident()
3844 && !self.token.is_reserved_ident()
3845 && self.look_ahead(1, |t| {
3846 AssocOp::from_token(t).is_some()
3847 || #[allow(non_exhaustive_omitted_patterns)] match t.kind {
token::OpenParen | token::OpenBracket | token::OpenBrace => true,
_ => false,
}matches!(
3848 t.kind,
3849 token::OpenParen | token::OpenBracket | token::OpenBrace
3850 )
3851 || *t == token::Dot
3852 })
3853 {
3854 e.span_suggestion_verbose(
3857 self.token.span.shrink_to_lo(),
3858 "try naming a field",
3859 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: ", ident))
})format!("{ident}: ",),
3860 Applicability::MaybeIncorrect,
3861 );
3862 }
3863 if in_if_guard && close.token_type == TokenType::CloseBrace {
3864 return Err(e);
3865 }
3866
3867 if !recover {
3868 return Err(e);
3869 }
3870
3871 let guar = e.emit();
3872 if pth == kw::Async {
3873 recovered_async = Some(guar);
3874 }
3875
3876 if self.token != token::Comma {
3880 self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3881 if self.token != token::Comma {
3882 break;
3883 }
3884 }
3885
3886 Err(guar)
3887 }
3888 };
3889
3890 let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
3891 self.check_or_expected(!is_shorthand, TokenType::Colon);
3894
3895 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]) {
3896 Ok(_) => {
3897 if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
3898 {
3899 fields.push(f);
3901 }
3902 }
3903 Err(mut e) => {
3904 if pth == kw::Async {
3905 async_block_err(&mut e, pth.span);
3906 } else {
3907 e.span_label(pth.span, "while parsing this struct");
3908 if peek.is_some() {
3909 e.span_suggestion(
3910 self.prev_token.span.shrink_to_hi(),
3911 "try adding a comma",
3912 ",",
3913 Applicability::MachineApplicable,
3914 );
3915 }
3916 }
3917 if !recover {
3918 return Err(e);
3919 }
3920 let guar = e.emit();
3921 if pth == kw::Async {
3922 recovered_async = Some(guar);
3923 } else if let Some(f) = field_ident(self, guar) {
3924 fields.push(f);
3925 }
3926 self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3927 let _ = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3928 }
3929 }
3930 }
3931 Ok((fields, base, recovered_async))
3932 }
3933
3934 pub(super) fn parse_expr_struct(
3936 &mut self,
3937 qself: Option<Box<ast::QSelf>>,
3938 pth: ast::Path,
3939 recover: bool,
3940 ) -> PResult<'a, Box<Expr>> {
3941 let lo = pth.span;
3942 let (fields, base, recovered_async) =
3943 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))?;
3944 let span = lo.to(self.token.span);
3945 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace))?;
3946 let expr = if let Some(guar) = recovered_async {
3947 ExprKind::Err(guar)
3948 } else {
3949 ExprKind::Struct(Box::new(ast::StructExpr { qself, path: pth, fields, rest: base }))
3950 };
3951 Ok(self.mk_expr(span, expr))
3952 }
3953
3954 fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
3955 if self.token != token::Comma {
3956 return;
3957 }
3958 self.dcx().emit_err(errors::CommaAfterBaseStruct {
3959 span: span.to(self.prev_token.span),
3960 comma: self.token.span,
3961 });
3962 self.recover_stmt();
3963 }
3964
3965 fn recover_struct_field_dots(&mut self, close: &TokenKind) -> bool {
3966 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)) {
3967 let span = self.prev_token.span;
3969 self.dcx().emit_err(errors::MissingDotDot { token_span: span, sugg_span: span });
3970 return true;
3971 }
3972 false
3973 }
3974
3975 fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
3977 let label = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}", ident.name))
})format!("'{}", ident.name);
3980 let ident = Ident::new(Symbol::intern(&label), ident.span);
3981
3982 self.dcx().emit_err(errors::ExpectedLabelFoundIdent {
3983 span: ident.span,
3984 start: ident.span.shrink_to_lo(),
3985 });
3986
3987 Label { ident }
3988 }
3989
3990 fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
3992 let attrs = self.parse_outer_attributes()?;
3993 self.recover_vcs_conflict_marker();
3994 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3995 let lo = this.token.span;
3996
3997 let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
3999 let is_wrong = this.token.is_non_reserved_ident()
4001 && !this.look_ahead(1, |t| {
4002 t == &token::Colon
4003 || t == &token::Eq
4004 || t == &token::Comma
4005 || t == &token::CloseBrace
4006 || t == &token::CloseParen
4007 });
4008 if is_wrong {
4009 return Err(this.dcx().create_err(errors::ExpectedStructField {
4010 span: this.look_ahead(1, |t| t.span),
4011 ident_span: this.token.span,
4012 token: this.look_ahead(1, |t| *t),
4013 }));
4014 }
4015 let (ident, expr) = if is_shorthand {
4016 let ident = this.parse_ident_common(false)?;
4018 let path = ast::Path::from_ident(ident);
4019 (ident, this.mk_expr(ident.span, ExprKind::Path(None, path)))
4020 } else {
4021 let ident = this.parse_field_name()?;
4022 this.error_on_eq_field_init(ident);
4023 this.bump(); (ident, this.parse_expr()?)
4025 };
4026
4027 Ok((
4028 ast::ExprField {
4029 ident,
4030 span: lo.to(expr.span),
4031 expr,
4032 is_shorthand,
4033 attrs,
4034 id: DUMMY_NODE_ID,
4035 is_placeholder: false,
4036 },
4037 Trailing::from(this.token == token::Comma),
4038 UsePreAttrPos::No,
4039 ))
4040 })
4041 }
4042
4043 fn error_on_eq_field_init(&self, field_name: Ident) {
4046 if self.token != token::Eq {
4047 return;
4048 }
4049
4050 self.dcx().emit_err(errors::EqFieldInit {
4051 span: self.token.span,
4052 eq: field_name.span.shrink_to_hi().to(self.token.span),
4053 });
4054 }
4055
4056 fn err_dotdotdot_syntax(&self, span: Span) {
4057 self.dcx().emit_err(errors::DotDotDot { span });
4058 }
4059
4060 fn err_larrow_operator(&self, span: Span) {
4061 self.dcx().emit_err(errors::LeftArrowOperator { span });
4062 }
4063
4064 fn mk_assign_op(&self, assign_op: AssignOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
4065 ExprKind::AssignOp(assign_op, lhs, rhs)
4066 }
4067
4068 fn mk_range(
4069 &mut self,
4070 start: Option<Box<Expr>>,
4071 end: Option<Box<Expr>>,
4072 limits: RangeLimits,
4073 ) -> ExprKind {
4074 if end.is_none() && limits == RangeLimits::Closed {
4075 let guar = self.inclusive_range_with_incorrect_end();
4076 ExprKind::Err(guar)
4077 } else {
4078 ExprKind::Range(start, end, limits)
4079 }
4080 }
4081
4082 fn mk_unary(&self, unop: UnOp, expr: Box<Expr>) -> ExprKind {
4083 ExprKind::Unary(unop, expr)
4084 }
4085
4086 fn mk_binary(&self, binop: BinOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
4087 ExprKind::Binary(binop, lhs, rhs)
4088 }
4089
4090 fn mk_index(&self, expr: Box<Expr>, idx: Box<Expr>, brackets_span: Span) -> ExprKind {
4091 ExprKind::Index(expr, idx, brackets_span)
4092 }
4093
4094 fn mk_call(&self, f: Box<Expr>, args: ThinVec<Box<Expr>>) -> ExprKind {
4095 ExprKind::Call(f, args)
4096 }
4097
4098 fn mk_await_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4099 let span = lo.to(self.prev_token.span);
4100 let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
4101 self.recover_from_await_method_call();
4102 await_expr
4103 }
4104
4105 fn mk_use_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4106 let span = lo.to(self.prev_token.span);
4107 let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
4108 self.recover_from_use();
4109 use_expr
4110 }
4111
4112 pub(crate) fn mk_expr_with_attrs(
4113 &self,
4114 span: Span,
4115 kind: ExprKind,
4116 attrs: AttrVec,
4117 ) -> Box<Expr> {
4118 Box::new(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
4119 }
4120
4121 pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> Box<Expr> {
4122 self.mk_expr_with_attrs(span, kind, AttrVec::new())
4123 }
4124
4125 pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Expr> {
4126 self.mk_expr(span, ExprKind::Err(guar))
4127 }
4128
4129 pub(crate) fn mk_unit_expr(&self, span: Span) -> Box<Expr> {
4130 self.mk_expr(span, ExprKind::Tup(Default::default()))
4131 }
4132
4133 pub(crate) fn mk_closure_expr(&self, span: Span, body: Box<Expr>) -> Box<Expr> {
4134 self.mk_expr(
4135 span,
4136 ast::ExprKind::Closure(Box::new(ast::Closure {
4137 binder: rustc_ast::ClosureBinder::NotPresent,
4138 constness: rustc_ast::Const::No,
4139 movability: rustc_ast::Movability::Movable,
4140 capture_clause: rustc_ast::CaptureBy::Ref,
4141 coroutine_kind: None,
4142 fn_decl: Box::new(rustc_ast::FnDecl {
4143 inputs: Default::default(),
4144 output: rustc_ast::FnRetTy::Default(span),
4145 }),
4146 fn_arg_span: span,
4147 fn_decl_span: span,
4148 body,
4149 })),
4150 )
4151 }
4152
4153 fn mk_expr_sp(&self, lhs: &Box<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span {
4156 lhs.attrs
4157 .iter()
4158 .find(|a| a.style == AttrStyle::Outer)
4159 .map_or(lhs_span, |a| a.span)
4160 .to(op_span)
4161 .to(rhs_span)
4162 }
4163
4164 fn collect_tokens_for_expr(
4165 &mut self,
4166 attrs: AttrWrapper,
4167 f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, Box<Expr>>,
4168 ) -> PResult<'a, Box<Expr>> {
4169 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4170 let res = f(this, attrs)?;
4171 let trailing = Trailing::from(
4172 this.restrictions.contains(Restrictions::STMT_EXPR)
4173 && this.token == token::Semi
4174 || this.token == token::Comma,
4178 );
4179 Ok((res, trailing, UsePreAttrPos::No))
4180 })
4181 }
4182}
4183
4184pub(crate) fn could_be_unclosed_char_literal(ident: Ident) -> bool {
4187 ident.name.as_str().starts_with('\'')
4188 && unescape_char(ident.without_first_quote().name.as_str()).is_ok()
4189}
4190
4191pub enum LetChainsPolicy {
4194 AlwaysAllowed,
4195 EditionDependent { current_edition: Edition },
4196}
4197
4198struct CondChecker<'a> {
4208 parser: &'a Parser<'a>,
4209 let_chains_policy: LetChainsPolicy,
4210 depth: u32,
4211 forbid_let_reason: Option<errors::ForbiddenLetReason>,
4212 missing_let: Option<errors::MaybeMissingLet>,
4213 comparison: Option<errors::MaybeComparison>,
4214 found_incorrect_let_chain: Option<ErrorGuaranteed>,
4215}
4216
4217impl<'a> CondChecker<'a> {
4218 fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4219 CondChecker {
4220 parser,
4221 forbid_let_reason: None,
4222 missing_let: None,
4223 comparison: None,
4224 let_chains_policy,
4225 found_incorrect_let_chain: None,
4226 depth: 0,
4227 }
4228 }
4229}
4230
4231impl MutVisitor for CondChecker<'_> {
4232 fn visit_expr(&mut self, e: &mut Expr) {
4233 self.depth += 1;
4234
4235 let span = e.span;
4236 match e.kind {
4237 ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
4238 if let Some(reason) = self.forbid_let_reason {
4239 let error = match reason {
4240 errors::ForbiddenLetReason::NotSupportedOr(or_span) => {
4241 self.parser.dcx().emit_err(errors::OrInLetChain { span: or_span })
4242 }
4243 _ => {
4244 let guar =
4245 self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
4246 span,
4247 reason,
4248 missing_let: self.missing_let,
4249 comparison: self.comparison,
4250 });
4251 if let Some(_) = self.missing_let {
4252 self.found_incorrect_let_chain = Some(guar);
4253 }
4254 guar
4255 }
4256 };
4257 *recovered = Recovered::Yes(error);
4258 } else if self.depth > 1 {
4259 match self.let_chains_policy {
4261 LetChainsPolicy::AlwaysAllowed => (),
4262 LetChainsPolicy::EditionDependent { current_edition } => {
4263 if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4264 self.parser.dcx().emit_err(errors::LetChainPre2024 { span });
4265 }
4266 }
4267 }
4268 }
4269 }
4270 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
4271 mut_visit::walk_expr(self, e);
4272 }
4273 ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
4274 if let None | Some(errors::ForbiddenLetReason::NotSupportedOr(_)) =
4275 self.forbid_let_reason =>
4276 {
4277 let forbid_let_reason = self.forbid_let_reason;
4278 self.forbid_let_reason = Some(errors::ForbiddenLetReason::NotSupportedOr(or_span));
4279 mut_visit::walk_expr(self, e);
4280 self.forbid_let_reason = forbid_let_reason;
4281 }
4282 ExprKind::Paren(ref inner)
4283 if let None | Some(errors::ForbiddenLetReason::NotSupportedParentheses(_)) =
4284 self.forbid_let_reason =>
4285 {
4286 let forbid_let_reason = self.forbid_let_reason;
4287 self.forbid_let_reason =
4288 Some(errors::ForbiddenLetReason::NotSupportedParentheses(inner.span));
4289 mut_visit::walk_expr(self, e);
4290 self.forbid_let_reason = forbid_let_reason;
4291 }
4292 ExprKind::Assign(ref lhs, _, span) => {
4293 let forbid_let_reason = self.forbid_let_reason;
4294 self.forbid_let_reason = Some(errors::ForbiddenLetReason::OtherForbidden);
4295 let missing_let = self.missing_let;
4296 if let ExprKind::Binary(_, _, rhs) = &lhs.kind
4297 && let ExprKind::Path(_, _)
4298 | ExprKind::Struct(_)
4299 | ExprKind::Call(_, _)
4300 | ExprKind::Array(_) = rhs.kind
4301 {
4302 self.missing_let =
4303 Some(errors::MaybeMissingLet { span: rhs.span.shrink_to_lo() });
4304 }
4305 let comparison = self.comparison;
4306 self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() });
4307 mut_visit::walk_expr(self, e);
4308 self.forbid_let_reason = forbid_let_reason;
4309 self.missing_let = missing_let;
4310 self.comparison = comparison;
4311 }
4312 ExprKind::Unary(_, _)
4313 | ExprKind::Await(_, _)
4314 | ExprKind::Use(_, _)
4315 | ExprKind::AssignOp(_, _, _)
4316 | ExprKind::Range(_, _, _)
4317 | ExprKind::Try(_)
4318 | ExprKind::AddrOf(_, _, _)
4319 | ExprKind::Binary(_, _, _)
4320 | ExprKind::Field(_, _)
4321 | ExprKind::Index(_, _, _)
4322 | ExprKind::Call(_, _)
4323 | ExprKind::MethodCall(_)
4324 | ExprKind::Tup(_)
4325 | ExprKind::Paren(_) => {
4326 let forbid_let_reason = self.forbid_let_reason;
4327 self.forbid_let_reason = Some(errors::ForbiddenLetReason::OtherForbidden);
4328 mut_visit::walk_expr(self, e);
4329 self.forbid_let_reason = forbid_let_reason;
4330 }
4331 ExprKind::Cast(ref mut op, _)
4332 | ExprKind::Type(ref mut op, _)
4333 | ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
4334 let forbid_let_reason = self.forbid_let_reason;
4335 self.forbid_let_reason = Some(errors::ForbiddenLetReason::OtherForbidden);
4336 self.visit_expr(op);
4337 self.forbid_let_reason = forbid_let_reason;
4338 }
4339 ExprKind::Let(_, _, _, Recovered::Yes(_))
4340 | ExprKind::Array(_)
4341 | ExprKind::ConstBlock(_)
4342 | ExprKind::Lit(_)
4343 | ExprKind::If(_, _, _)
4344 | ExprKind::While(_, _, _)
4345 | ExprKind::ForLoop { .. }
4346 | ExprKind::Loop(_, _, _)
4347 | ExprKind::Match(_, _, _)
4348 | ExprKind::Closure(_)
4349 | ExprKind::Block(_, _)
4350 | ExprKind::Gen(_, _, _, _)
4351 | ExprKind::TryBlock(_, _)
4352 | ExprKind::Underscore
4353 | ExprKind::Path(_, _)
4354 | ExprKind::Break(_, _)
4355 | ExprKind::Continue(_)
4356 | ExprKind::Ret(_)
4357 | ExprKind::InlineAsm(_)
4358 | ExprKind::OffsetOf(_, _)
4359 | ExprKind::MacCall(_)
4360 | ExprKind::Struct(_)
4361 | ExprKind::Repeat(_, _)
4362 | ExprKind::Yield(_)
4363 | ExprKind::Yeet(_)
4364 | ExprKind::Become(_)
4365 | ExprKind::IncludedBytes(_)
4366 | ExprKind::FormatArgs(_)
4367 | ExprKind::Err(_)
4368 | ExprKind::Dummy => {
4369 }
4371 }
4372 self.depth -= 1;
4373 }
4374}