1use core::mem;
4use core::ops::{Bound, ControlFlow};
5
6use ast::mut_visit::{self, MutVisitor};
7use ast::token::IdentIsRaw;
8use ast::{ForLoopKind, MatchKind, Pat, Path, PathSegment, Recovered};
9use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, Token, TokenKind};
10use rustc_ast::util::case::Case;
11use rustc_ast::util::classify;
12use rustc_ast::util::parser::{AssocOp, ExprPrecedence, Fixity, prec_let_scrutinee_needs_par};
13use rustc_ast::visit::{Visitor, walk_expr};
14use rustc_ast::{
15 self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
16 BlockCheckMode, CaptureBy, ClosureBinder, CoroutineKind, DUMMY_NODE_ID, Expr, ExprField,
17 ExprKind, FnDecl, FnRetTy, ForLoop, Guard, Label, MacCall, MetaItemLit, Movability, Param,
18 RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
19};
20use rustc_ast_pretty::pprust;
21use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
22use rustc_lint_defs::builtin::BREAK_WITH_LABEL_AND_LOOP;
23use rustc_literal_escaper::unescape_char;
24use rustc_session::diagnostics::report_lit_error;
25use rustc_span::edition::Edition;
26use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Spanned, Symbol, kw, respan, sym};
27use thin_vec::{ThinVec, thin_vec};
28use tracing::instrument;
29
30use super::diagnostics::SnapshotParser;
31use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
32use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
33use super::{
34 AttrWrapper, BlockMode, ClosureSpans, ExpTokenPair, ForceCollect, Parser, PathStyle,
35 Restrictions, SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,
36};
37use crate::diagnostics::ExprParenthesesNeeded;
38use crate::{diagnostics, exp, maybe_recover_from_interpolated_ty_qpath};
39
40#[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)]
41pub(super) enum DestructuredFloat {
42 Single(Symbol, Span),
44 TrailingDot(Symbol, Span, Span),
46 MiddleDot(Symbol, Span, Span, Symbol, Span),
48 Error,
50}
51
52impl<'a> Parser<'a> {
53 #[inline]
55 pub fn parse_expr(&mut self) -> PResult<'a, Box<Expr>> {
56 self.current_closure.take();
57 self.parse_expr_res(Restrictions::empty())
58 }
59
60 pub fn parse_expr_force_collect(&mut self) -> PResult<'a, Box<Expr>> {
62 self.current_closure.take();
63
64 let pre_attr_pos = self.collect_pos();
69 let attrs = self.parse_outer_attributes()?;
70 self.collect_tokens(
71 Some(pre_attr_pos),
72 AttrWrapper::empty(),
73 ForceCollect::Yes,
74 |this, _empty_attrs| {
75 let (expr, is_assoc) =
76 this.parse_expr_res_after_attrs(Restrictions::empty(), attrs)?;
77 let use_pre_attr_pos =
78 if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };
79 Ok((expr, Trailing::No, use_pre_attr_pos))
80 },
81 )
82 }
83
84 pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
85 self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value })
86 }
87
88 fn parse_expr_paren_seq(&mut self) -> PResult<'a, ThinVec<Box<Expr>>> {
90 self.parse_paren_comma_seq(Self::parse_expr).map(|(r, _)| r)
91 }
92
93 #[inline]
95 pub(super) fn parse_expr_res(&mut self, r: Restrictions) -> PResult<'a, Box<Expr>> {
96 let attrs = self.parse_outer_attributes()?;
97 self.parse_expr_res_after_attrs(r, attrs).map(|(expr, _)| expr)
98 }
99
100 #[inline]
104 pub(super) fn parse_expr_res_after_attrs(
105 &mut self,
106 r: Restrictions,
107 attrs: AttrWrapper,
108 ) -> PResult<'a, (Box<Expr>, bool)> {
109 self.with_res(r, |this| this.parse_expr_assoc_after_attrs(Bound::Unbounded, attrs))
110 }
111
112 pub(super) fn parse_expr_assoc(
114 &mut self,
115 min_prec: Bound<ExprPrecedence>,
116 ) -> PResult<'a, Box<Expr>> {
117 let attrs = self.parse_outer_attributes()?;
118 self.parse_expr_assoc_after_attrs(min_prec, attrs).map(|(expr, _)| expr)
119 }
120
121 pub(super) fn parse_expr_assoc_after_attrs(
125 &mut self,
126 min_prec: Bound<ExprPrecedence>,
127 attrs: AttrWrapper,
128 ) -> PResult<'a, (Box<Expr>, bool)> {
129 let lhs = if self.token.is_range_separator() {
130 return self.parse_expr_prefix_range(attrs).map(|res| (res, false));
131 } else {
132 self.parse_expr_prefix(attrs)?
133 };
134 self.parse_expr_assoc_rest(min_prec, false, lhs)
135 }
136
137 pub(super) fn parse_expr_assoc_rest(
141 &mut self,
142 min_prec: Bound<ExprPrecedence>,
143 starts_stmt: bool,
144 mut lhs: Box<Expr>,
145 ) -> PResult<'a, (Box<Expr>, bool)> {
146 let mut parsed_something = false;
147 if !self.should_continue_as_assoc_expr(&lhs) {
148 return Ok((lhs, parsed_something));
149 }
150
151 self.expected_token_types.insert(TokenType::Operator);
152 while let Some(op) = self.check_assoc_op() {
153 let lhs_span = self.interpolated_or_expr_span(&lhs);
154 let cur_op_span = self.token.span;
155 let restrictions = if op.node.is_assign_like() {
156 self.restrictions & Restrictions::NO_STRUCT_LITERAL
157 } else {
158 self.restrictions
159 };
160 let prec = op.node.precedence();
161 if match min_prec {
162 Bound::Included(min_prec) => prec < min_prec,
163 Bound::Excluded(min_prec) => prec <= min_prec,
164 Bound::Unbounded => false,
165 } {
166 break;
167 }
168 if self.token == token::DotDotDot && op.node == AssocOp::Range(RangeLimits::Closed) {
170 self.err_dotdotdot_syntax(self.token.span);
171 }
172
173 if self.token == token::LArrow {
174 self.err_larrow_operator(self.token.span);
175 }
176
177 parsed_something = true;
178 self.bump();
179 if op.node.is_comparison() {
180 if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
181 return Ok((expr, parsed_something));
182 }
183 }
184
185 if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node
187 && self.token == token::Eq
188 && self.prev_token.span.hi() == self.token.span.lo()
189 {
190 let sp = op.span.to(self.token.span);
191 let sugg = bop.as_str().into();
192 let invalid = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}=", sugg))
})format!("{sugg}=");
193 self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
194 span: sp,
195 invalid: invalid.clone(),
196 sub: diagnostics::InvalidComparisonOperatorSub::Correctable {
197 span: sp,
198 invalid,
199 correct: sugg,
200 },
201 });
202 self.bump();
203 }
204
205 if op.node == AssocOp::Binary(BinOpKind::Lt)
207 && self.token == token::Gt
208 && self.prev_token.span.hi() == self.token.span.lo()
209 {
210 let sp = op.span.to(self.token.span);
211 self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
212 span: sp,
213 invalid: "<>".into(),
214 sub: diagnostics::InvalidComparisonOperatorSub::Correctable {
215 span: sp,
216 invalid: "<>".into(),
217 correct: "!=".into(),
218 },
219 });
220 self.bump();
221 }
222
223 if op.node == AssocOp::Binary(BinOpKind::Le)
225 && self.token == token::Gt
226 && self.prev_token.span.hi() == self.token.span.lo()
227 {
228 let sp = op.span.to(self.token.span);
229 self.dcx().emit_err(diagnostics::InvalidComparisonOperator {
230 span: sp,
231 invalid: "<=>".into(),
232 sub: diagnostics::InvalidComparisonOperatorSub::Spaceship(sp),
233 });
234 self.bump();
235 }
236
237 if self.prev_token == token::Plus
238 && self.token == token::Plus
239 && self.prev_token.span.between(self.token.span).is_empty()
240 {
241 let op_span = self.prev_token.span.to(self.token.span);
242 self.bump();
244 lhs = self.recover_from_postfix_increment(lhs, op_span, starts_stmt)?;
245 continue;
246 }
247
248 if self.prev_token == token::Minus
249 && self.token == token::Minus
250 && self.prev_token.span.between(self.token.span).is_empty()
251 && !self.look_ahead(1, |tok| tok.can_begin_expr())
252 {
253 let op_span = self.prev_token.span.to(self.token.span);
254 self.bump();
256 lhs = self.recover_from_postfix_decrement(lhs, op_span, starts_stmt)?;
257 continue;
258 }
259
260 let op_span = op.span;
261 let op = op.node;
262 if op == AssocOp::Cast {
264 lhs = self.parse_assoc_op_cast(lhs, lhs_span, op_span, ExprKind::Cast)?;
265 continue;
266 } else if let AssocOp::Range(limits) = op {
267 lhs = self.parse_expr_range(prec, lhs, limits, cur_op_span)?;
270 break;
271 }
272
273 let min_prec = match op.fixity() {
274 Fixity::Right => Bound::Included(prec),
275 Fixity::Left | Fixity::None => Bound::Excluded(prec),
276 };
277 let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
278 this.parse_expr_assoc(min_prec)
279 })?;
280
281 let span = self.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);
282 lhs = match op {
283 AssocOp::Binary(ast_op) => {
284 let binary = self.mk_binary(respan(cur_op_span, ast_op), lhs, rhs);
285 self.mk_expr(span, binary)
286 }
287 AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)),
288 AssocOp::AssignOp(aop) => {
289 let aopexpr = self.mk_assign_op(respan(cur_op_span, aop), lhs, rhs);
290 self.mk_expr(span, aopexpr)
291 }
292 AssocOp::Cast | AssocOp::Range(_) => {
293 self.dcx().span_bug(span, "AssocOp should have been handled by special case")
294 }
295 };
296 }
297
298 Ok((lhs, parsed_something))
299 }
300
301 fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
302 match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) {
303 (true, None) => false,
306 (false, _) => true, (true, Some(AssocOp::Binary(
311 BinOpKind::Mul | BinOpKind::Sub | BinOpKind::Add | BinOpKind::And | BinOpKind::Or | BinOpKind::BitOr ))) => {
318 let sp = self.psess.source_map().start_point(self.token.span);
325 self.psess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
326 false
327 }
328 (true, Some(op)) if !op.can_continue_expr_unambiguously() => false,
329 (true, Some(_)) => {
330 self.error_found_expr_would_be_stmt(lhs);
331 true
332 }
333 }
334 }
335
336 fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
340 self.dcx().emit_err(diagnostics::FoundExprWouldBeStmt {
341 span: self.token.span,
342 token: pprust::token_to_string(&self.token),
343 suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
344 });
345 }
346
347 pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
352 let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
353 (
355 Some(
356 AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge)
357 | AssocOp::AssignOp(AssignOpKind::ShrAssign),
358 ),
359 _,
360 ) if self.restrictions.contains(Restrictions::CONST_EXPR) => {
361 return None;
362 }
363 (
366 Some(
367 AssocOp::Assign
368 | AssocOp::AssignOp(_)
369 | AssocOp::Binary(BinOpKind::BitOr)
370 | AssocOp::Range(_),
371 ),
372 _,
373 ) if self.restrictions.contains(Restrictions::IS_PAT) => {
374 return None;
375 }
376 (Some(op), _) => (op, self.token.span),
377 (None, Some((Ident { name: sym::and, span }, IdentIsRaw::No)))
378 if self.may_recover() =>
379 {
380 self.dcx().emit_err(diagnostics::InvalidLogicalOperator {
381 span: self.token.span,
382 incorrect: "and".into(),
383 sub: diagnostics::InvalidLogicalOperatorSub::Conjunction(self.token.span),
384 });
385 (AssocOp::Binary(BinOpKind::And), span)
386 }
387 (None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => {
388 self.dcx().emit_err(diagnostics::InvalidLogicalOperator {
389 span: self.token.span,
390 incorrect: "or".into(),
391 sub: diagnostics::InvalidLogicalOperatorSub::Disjunction(self.token.span),
392 });
393 (AssocOp::Binary(BinOpKind::Or), span)
394 }
395 _ => return None,
396 };
397 Some(respan(span, op))
398 }
399
400 fn expr_is_complete(&self, e: &Expr) -> bool {
402 self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)
403 }
404
405 fn parse_expr_range(
408 &mut self,
409 prec: ExprPrecedence,
410 lhs: Box<Expr>,
411 limits: RangeLimits,
412 cur_op_span: Span,
413 ) -> PResult<'a, Box<Expr>> {
414 let rhs = if self.is_at_start_of_range_notation_rhs() {
415 let maybe_lt = self.token;
416 Some(
417 self.parse_expr_assoc(Bound::Excluded(prec))
418 .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,
419 )
420 } else {
421 None
422 };
423 let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
424 let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span);
425 let range = self.mk_range(Some(lhs), rhs, limits);
426 Ok(self.mk_expr(span, range))
427 }
428
429 fn is_at_start_of_range_notation_rhs(&self) -> bool {
430 if self.token.can_begin_expr() {
431 if self.token == token::OpenBrace {
433 return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
434 }
435 true
436 } else {
437 false
438 }
439 }
440
441 fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
443 if !attrs.is_empty() {
444 let err = diagnostics::DotDotRangeAttribute { span: self.token.span };
445 self.dcx().emit_err(err);
446 }
447
448 if self.token == token::DotDotDot {
450 self.err_dotdotdot_syntax(self.token.span);
451 }
452
453 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!(
454 self.token.is_range_separator(),
455 "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
456 self.token
457 );
458
459 let limits = match self.token.kind {
460 token::DotDot => RangeLimits::HalfOpen,
461 _ => RangeLimits::Closed,
462 };
463 let op = AssocOp::from_token(&self.token);
464 self.collect_tokens_for_expr(AttrWrapper::empty(), |this, _empty_attrs| {
465 let lo = this.token.span;
466 let maybe_lt = this.look_ahead(1, |t| t.clone());
467 this.bump();
468 let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
469 this.parse_expr_assoc(Bound::Excluded(op.unwrap().precedence()))
471 .map(|expr| (lo.to(expr.span), Some(expr)))
472 .map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
473 } else {
474 (lo, None)
475 };
476 let range = this.mk_range(None, opt_end, limits);
477 Ok(this.mk_expr(span, range))
478 })
479 }
480
481 fn parse_expr_prefix(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
483 let lo = self.token.span;
484
485 macro_rules! make_it {
486 ($this:ident, $attrs:expr, |this, _| $body:expr) => {
487 $this.collect_tokens_for_expr($attrs, |$this, attrs| {
488 let (hi, ex) = $body?;
489 Ok($this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
490 })
491 };
492 }
493
494 let this = self;
495
496 match this.token.uninterpolate().kind {
498 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)),
500 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)),
502 token::Minus => {
504 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))
505 }
506 token::Star => {
508 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))
509 }
510 token::And | token::AndAnd => {
512 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))
513 }
514 token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => {
516 let mut err = diagnostics::LeadingPlusNotSupported {
517 span: lo,
518 remove_plus: None,
519 add_parentheses: None,
520 };
521
522 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
524 err.add_parentheses = Some(ExprParenthesesNeeded::surrounding(*sp));
525 } else {
526 err.remove_plus = Some(lo);
527 }
528 this.dcx().emit_err(err);
529
530 this.bump(); Ok(this.parse_expr_prefix_common(lo)?.1)
532 }
533 token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {
535 let starts_stmt =
536 this.prev_token == token::Semi || this.prev_token == token::CloseBrace;
537 let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
538 this.bump();
540 this.bump();
541
542 let operand_expr = this.parse_expr_dot_or_call(attrs)?;
543 this.recover_from_prefix_increment(operand_expr, pre_span, starts_stmt)
544 }
545 token::Ident(..)
546 if this.token.is_keyword(kw::Move)
547 && this.look_ahead(1, |t| *t == token::OpenParen) =>
548 {
549 this.collect_tokens_for_expr(attrs,
|this, attrs|
{
let (hi, ex) = this.parse_expr_move(lo)?;
Ok(this.mk_expr_with_attrs(lo.to(hi), ex, attrs))
})make_it!(this, attrs, |this, _| this.parse_expr_move(lo))
550 }
551 token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
552 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))
553 }
554 _ => return this.parse_expr_dot_or_call(attrs),
555 }
556 }
557
558 fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, Box<Expr>)> {
559 let attrs = self.parse_outer_attributes()?;
560 let expr = if self.token.is_range_separator() {
561 self.parse_expr_prefix_range(attrs)
562 } else {
563 self.parse_expr_prefix(attrs)
564 }?;
565 let span = self.interpolated_or_expr_span(&expr);
566 Ok((lo.to(span), expr))
567 }
568
569 fn parse_expr_unary(&mut self, lo: Span, op: UnOp) -> PResult<'a, (Span, ExprKind)> {
570 self.bump(); let (span, expr) = self.parse_expr_prefix_common(lo)?;
572 Ok((span, self.mk_unary(op, expr)))
573 }
574
575 fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
577 self.dcx().emit_err(diagnostics::TildeAsUnaryOperator(lo));
578
579 self.parse_expr_unary(lo, UnOp::Not)
580 }
581
582 fn parse_expr_move(&mut self, move_kw: Span) -> PResult<'a, (Span, ExprKind)> {
583 self.bump();
584 self.psess.gated_spans.gate(sym::move_expr, move_kw);
585 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
586 let expr = self.parse_expr()?;
587 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
588 let span = move_kw.to(self.prev_token.span);
589 Ok((span, ExprKind::Move(expr, move_kw)))
590 }
591
592 fn is_mistaken_not_ident_negation(&self) -> bool {
593 let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind {
594 token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw),
597 token::Literal(..) | token::Pound => true,
598 _ => t.is_metavar_expr(),
599 };
600 self.token.is_ident_named(sym::not) && self.look_ahead(1, token_cannot_continue_expr)
601 }
602
603 fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
605 let negated_token = self.look_ahead(1, |t| *t);
606
607 let sub_diag = if negated_token.is_numeric_lit() {
608 diagnostics::NotAsNegationOperatorSub::SuggestNotBitwise
609 } else if negated_token.is_bool_lit() {
610 diagnostics::NotAsNegationOperatorSub::SuggestNotLogical
611 } else {
612 diagnostics::NotAsNegationOperatorSub::SuggestNotDefault
613 };
614
615 self.dcx().emit_err(diagnostics::NotAsNegationOperator {
616 negated: negated_token.span,
617 negated_desc: super::token_descr(&negated_token),
618 sub: sub_diag(
621 self.psess.source_map().span_until_non_whitespace(lo.to(negated_token.span)),
622 ),
623 });
624
625 self.parse_expr_unary(lo, UnOp::Not)
626 }
627
628 fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
630 match self.prev_token.kind {
631 token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,
632 token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {
633 self.prev_token.span
638 }
639 _ => expr.span,
640 }
641 }
642
643 fn parse_assoc_op_cast(
644 &mut self,
645 lhs: Box<Expr>,
646 lhs_span: Span,
647 op_span: Span,
648 expr_kind: fn(Box<Expr>, Box<Ty>) -> ExprKind,
649 ) -> PResult<'a, Box<Expr>> {
650 let mk_expr = |this: &mut Self, lhs: Box<Expr>, rhs: Box<Ty>| {
651 this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs))
652 };
653
654 let parser_snapshot_before_type = self.clone();
657 let cast_expr = match self.parse_as_cast_ty() {
658 Ok(rhs) => mk_expr(self, lhs, rhs),
659 Err(type_err) => {
660 if !self.may_recover() {
661 return Err(type_err);
662 }
663
664 let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
668
669 match (&lhs.kind, &self.token.kind) {
671 (
672 ExprKind::Path(None, ast::Path { segments, .. }),
674 token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
675 ) if let [segment] = segments.as_slice() => {
676 let snapshot = self.create_snapshot_for_diagnostic();
677 let label = Label {
678 ident: Ident::from_str_and_span(
679 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}", segment.ident))
})format!("'{}", segment.ident),
680 segment.ident.span,
681 ),
682 };
683 match self.parse_expr_labeled(label, false) {
684 Ok(expr) => {
685 type_err.cancel();
686 self.dcx().emit_err(diagnostics::MalformedLoopLabel {
687 span: label.ident.span,
688 suggestion: label.ident.span.shrink_to_lo(),
689 });
690 return Ok(expr);
691 }
692 Err(err) => {
693 err.cancel();
694 self.restore_snapshot(snapshot);
695 }
696 }
697 }
698 _ => {}
699 }
700
701 match self.parse_path(PathStyle::Expr) {
702 Ok(path) => {
703 let span_after_type = parser_snapshot_after_type.token.span;
704 let expr = mk_expr(
705 self,
706 lhs,
707 self.mk_ty(path.span, TyKind::Path(None, path.clone())),
708 );
709
710 let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
711 match self.token.kind {
712 token::Lt => {
713 self.dcx().emit_err(diagnostics::ComparisonInterpretedAsGeneric {
714 comparison: self.token.span,
715 r#type: pprust::path_to_string(&path),
716 args: args_span,
717 suggestion: diagnostics::ComparisonInterpretedAsGenericSugg {
718 left: expr.span.shrink_to_lo(),
719 right: expr.span.shrink_to_hi(),
720 },
721 })
722 }
723 token::Shl => {
724 self.dcx().emit_err(diagnostics::ShiftInterpretedAsGeneric {
725 shift: self.token.span,
726 r#type: pprust::path_to_string(&path),
727 args: args_span,
728 suggestion: diagnostics::ShiftInterpretedAsGenericSugg {
729 left: expr.span.shrink_to_lo(),
730 right: expr.span.shrink_to_hi(),
731 },
732 })
733 }
734 _ => {
735 *self = parser_snapshot_after_type;
740 return Err(type_err);
741 }
742 };
743
744 type_err.cancel();
746
747 expr
749 }
750 Err(path_err) => {
751 path_err.cancel();
753 *self = parser_snapshot_after_type;
754 return Err(type_err);
755 }
756 }
757 }
758 };
759
760 let span = cast_expr.span;
766
767 let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
768
769 if !#[allow(non_exhaustive_omitted_patterns)] match with_postfix.kind {
ExprKind::Cast(_, _) => true,
_ => false,
}matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
772 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!(
773 "cast cannot be followed by {}",
774 match with_postfix.kind {
775 ExprKind::Index(..) => "indexing",
776 ExprKind::Try(_) => "`?`",
777 ExprKind::Field(_, _) => "a field access",
778 ExprKind::MethodCall(_) => "a method call",
779 ExprKind::Call(_, _) => "a function call",
780 ExprKind::Await(_, _) => "`.await`",
781 ExprKind::Use(_, _) => "`.use`",
782 ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
783 ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
784 ExprKind::Err(_) => return Ok(with_postfix),
785 _ => unreachable!(
786 "did not expect {:?} as an illegal postfix operator following cast",
787 with_postfix.kind
788 ),
789 }
790 );
791 let mut err = self.dcx().struct_span_err(span, msg);
792
793 let suggest_parens = |err: &mut Diag<'_>| {
794 let suggestions = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(span.shrink_to_lo(), "(".to_string()),
(span.shrink_to_hi(), ")".to_string())]))vec![
795 (span.shrink_to_lo(), "(".to_string()),
796 (span.shrink_to_hi(), ")".to_string()),
797 ];
798 err.multipart_suggestion(
799 "try surrounding the expression in parentheses",
800 suggestions,
801 Applicability::MachineApplicable,
802 );
803 };
804
805 suggest_parens(&mut err);
806
807 err.emit();
808 };
809 Ok(with_postfix)
810 }
811
812 fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
814 self.expect_and()?;
815 let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
816 let lifetime = has_lifetime.then(|| self.expect_lifetime()); let (borrow_kind, mutbl) = self.parse_borrow_modifiers();
818 let (span, expr) = self.parse_expr_prefix_common(lo)?;
819 if let Some(lt) = lifetime {
820 self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
821 }
822
823 if borrow_kind == ast::BorrowKind::Ref
827 && mutbl == ast::Mutability::Not
828 && #[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)
829 {
830 self.expected_token_types.insert(TokenType::KwMut);
831 self.expected_token_types.insert(TokenType::KwConst);
832 }
833
834 Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
835 }
836
837 fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
838 self.dcx()
839 .emit_err(diagnostics::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
840 }
841
842 fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
844 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) {
845 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));
847 if !found_raw { ::core::panicking::panic("assertion failed: found_raw") };assert!(found_raw);
848 let mutability = self.parse_mut_or_const().unwrap();
849 (ast::BorrowKind::Raw, mutability)
850 } else {
851 match self.parse_pin_and_mut() {
852 (ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),
854 (ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),
858 }
859 }
860 }
861
862 fn parse_expr_dot_or_call(&mut self, attrs: AttrWrapper) -> PResult<'a, Box<Expr>> {
864 self.collect_tokens_for_expr(attrs, |this, attrs| {
865 let base = this.parse_expr_bottom()?;
866 let span = this.interpolated_or_expr_span(&base);
867 this.parse_expr_dot_or_call_with(attrs, base, span)
868 })
869 }
870
871 pub(super) fn parse_expr_dot_or_call_with(
872 &mut self,
873 mut attrs: ast::AttrVec,
874 mut e: Box<Expr>,
875 lo: Span,
876 ) -> PResult<'a, Box<Expr>> {
877 let mut res = loop {
878 let has_question = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
879 self.eat_noexpect(&token::Question)
882 } else {
883 self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Question,
token_type: crate::parser::token_type::TokenType::Question,
}exp!(Question))
884 };
885 if has_question {
886 e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
888 continue;
889 }
890 let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
891 self.eat_noexpect(&token::Dot)
894 } else if self.token == TokenKind::RArrow && self.may_recover() {
895 self.bump();
897 let span = self.prev_token.span;
898 self.dcx().emit_err(diagnostics::ExprRArrowCall { span });
899 true
900 } else {
901 self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Dot,
token_type: crate::parser::token_type::TokenType::Dot,
}exp!(Dot))
902 };
903 if has_dot {
904 e = self.parse_dot_suffix_expr(lo, e)?;
906 continue;
907 }
908 if self.expr_is_complete(&e) {
909 break Ok(e);
910 }
911 e = match self.token.kind {
912 token::OpenParen => self.parse_expr_fn_call(lo, e),
913 token::OpenBracket => self.parse_expr_index(lo, e)?,
914 _ => break Ok(e),
915 }
916 };
917
918 if !attrs.is_empty()
921 && let Ok(expr) = &mut res
922 {
923 mem::swap(&mut expr.attrs, &mut attrs);
924 expr.attrs.extend(attrs)
925 }
926 res
927 }
928
929 pub(super) fn parse_dot_suffix_expr(
930 &mut self,
931 lo: Span,
932 base: Box<Expr>,
933 ) -> PResult<'a, Box<Expr>> {
934 match self.token.uninterpolate().kind {
937 token::Ident(..) => self.parse_dot_suffix(base, lo),
938 token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
939 let ident_span = self.token.span;
940 self.bump();
941 Ok(self.mk_expr_tuple_field_access(lo, ident_span, base, symbol, suffix))
942 }
943 token::Literal(token::Lit { kind: token::Float, symbol, suffix }) => {
944 Ok(match self.break_up_float(symbol, self.token.span) {
945 DestructuredFloat::Single(sym, _sp) => {
947 let ident_span = self.token.span;
951 self.bump();
952 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, suffix)
953 }
954 DestructuredFloat::TrailingDot(sym, ident_span, dot_span) => {
956 if !suffix.is_none() {
::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
960 self.token = Token::new(token::Ident(sym, IdentIsRaw::No), ident_span);
961 self.bump_with((Token::new(token::Dot, dot_span), self.token_spacing));
962 self.mk_expr_tuple_field_access(lo, ident_span, base, sym, None)
963 }
964 DestructuredFloat::MiddleDot(
966 sym1,
967 ident1_span,
968 _dot_span,
969 sym2,
970 ident2_span,
971 ) => {
972 let next_token2 =
976 Token::new(token::Ident(sym2, IdentIsRaw::No), ident2_span);
977 self.bump_with((next_token2, self.token_spacing));
978 self.bump();
979 let base1 =
980 self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
981 self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
982 }
983 DestructuredFloat::Error => base,
984 })
985 }
986 _ => {
987 self.error_unexpected_after_dot();
988 Ok(base)
989 }
990 }
991 }
992
993 fn error_unexpected_after_dot(&self) {
994 let actual = super::token_descr(&self.token);
995 let span = self.token.span;
996 let sm = self.psess.source_map();
997 let (span, actual) = match (&self.token.kind, self.subparser_name) {
998 (token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {
999 (span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", snippet))
})format!("`{}`", snippet))
1000 }
1001 (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {
1002 self.dcx().span_delayed_bug(span, "bad dot expr in metavariable");
1017 return;
1018 }
1019 _ => (span, actual),
1020 };
1021 self.dcx().emit_err(diagnostics::UnexpectedTokenAfterDot { span, actual });
1022 }
1023
1024 pub(super) fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
1035 #[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)]
1036 enum FloatComponent {
1037 IdentLike(String),
1038 Punct(char),
1039 }
1040 use FloatComponent::*;
1041
1042 let float_str = float.as_str();
1043 let mut components = Vec::new();
1044 let mut ident_like = String::new();
1045 for c in float_str.chars() {
1046 if c == '_' || c.is_ascii_alphanumeric() {
1047 ident_like.push(c);
1048 } else if #[allow(non_exhaustive_omitted_patterns)] match c {
'.' | '+' | '-' => true,
_ => false,
}matches!(c, '.' | '+' | '-') {
1049 if !ident_like.is_empty() {
1050 components.push(IdentLike(mem::take(&mut ident_like)));
1051 }
1052 components.push(Punct(c));
1053 } else {
1054 {
::core::panicking::panic_fmt(format_args!("unexpected character in a float token: {0:?}",
c));
}panic!("unexpected character in a float token: {c:?}")
1055 }
1056 }
1057 if !ident_like.is_empty() {
1058 components.push(IdentLike(ident_like));
1059 }
1060
1061 let can_take_span_apart =
1065 || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
1066
1067 match &*components {
1068 [IdentLike(i)] => DestructuredFloat::Single(Symbol::intern(i), span),
1070 [IdentLike(left), Punct('.')] => {
1072 let (left_span, dot_span) = if can_take_span_apart() {
1073 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
1074 let dot_span = span.with_lo(left_span.hi());
1075 (left_span, dot_span)
1076 } else {
1077 (span, span)
1078 };
1079 let left = Symbol::intern(left);
1080 DestructuredFloat::TrailingDot(left, left_span, dot_span)
1081 }
1082 [IdentLike(left), Punct('.'), IdentLike(right)] => {
1084 let (left_span, dot_span, right_span) = if can_take_span_apart() {
1085 let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
1086 let dot_span =
1087 span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));
1088 let right_span = span.with_lo(dot_span.hi());
1089 (left_span, dot_span, right_span)
1090 } else {
1091 (span, span, span)
1092 };
1093 let left = Symbol::intern(left);
1094 let right = Symbol::intern(right);
1095 DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)
1096 }
1097 [IdentLike(_), Punct('+' | '-')] |
1099 [IdentLike(_), Punct('+' | '-'), IdentLike(_)] |
1101 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-')] |
1103 [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
1105 self.error_unexpected_after_dot();
1107 DestructuredFloat::Error
1108 }
1109 _ => {
::core::panicking::panic_fmt(format_args!("unexpected components in a float token: {0:?}",
components));
}panic!("unexpected components in a float token: {components:?}"),
1110 }
1111 }
1112
1113 pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, ThinVec<Ident>> {
1117 let mut fields = ThinVec::new();
1118 let mut trailing_dot = None;
1119
1120 loop {
1121 let expr = self.parse_expr()?;
1125 let mut current = &expr;
1126 let start_idx = fields.len();
1127 loop {
1128 match current.kind {
1129 ExprKind::Field(ref left, right) => {
1130 fields.insert(start_idx, right);
1132 trailing_dot = None;
1133 current = left;
1134 }
1135 ExprKind::Index(ref left, ref _right, span) => {
1138 self.dcx().emit_err(diagnostics::ArrayIndexInOffsetOf(span));
1139 current = left;
1140 }
1141 ExprKind::Lit(token::Lit {
1142 kind: token::Float | token::Integer,
1143 symbol,
1144 suffix,
1145 }) => {
1146 if let Some(suffix) = suffix {
1147 self.dcx().emit_err(diagnostics::InvalidLiteralSuffixOnTupleIndex {
1148 span: current.span,
1149 suffix,
1150 });
1151 }
1152 match self.break_up_float(symbol, current.span) {
1153 DestructuredFloat::Single(sym, sp) => {
1155 trailing_dot = None;
1156 fields.insert(start_idx, Ident::new(sym, sp));
1157 }
1158 DestructuredFloat::TrailingDot(sym, sym_span, dot_span) => {
1160 if !suffix.is_none() {
::core::panicking::panic("assertion failed: suffix.is_none()")
};assert!(suffix.is_none());
1161 trailing_dot = Some(dot_span);
1162 fields.insert(start_idx, Ident::new(sym, sym_span));
1163 }
1164 DestructuredFloat::MiddleDot(
1166 symbol1,
1167 span1,
1168 _dot_span,
1169 symbol2,
1170 span2,
1171 ) => {
1172 trailing_dot = None;
1173 fields.insert(start_idx, Ident::new(symbol2, span2));
1174 fields.insert(start_idx, Ident::new(symbol1, span1));
1175 }
1176 DestructuredFloat::Error => {
1177 trailing_dot = None;
1178 fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
1179 }
1180 }
1181 break;
1182 }
1183 ExprKind::Path(None, Path { ref segments, .. }) => {
1184 match &segments[..] {
1185 [PathSegment { ident, args: None, .. }] => {
1186 trailing_dot = None;
1187 fields.insert(start_idx, *ident)
1188 }
1189 _ => {
1190 self.dcx().emit_err(diagnostics::InvalidOffsetOf(current.span));
1191 break;
1192 }
1193 }
1194 break;
1195 }
1196 _ => {
1197 self.dcx().emit_err(diagnostics::InvalidOffsetOf(current.span));
1198 break;
1199 }
1200 }
1201 }
1202
1203 if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {
1204 break;
1205 } else if trailing_dot.is_none() {
1206 self.dcx().emit_err(diagnostics::InvalidOffsetOf(self.token.span));
1208 break;
1209 }
1210 }
1211 if let Some(dot) = trailing_dot {
1212 self.dcx().emit_err(diagnostics::InvalidOffsetOf(dot));
1213 }
1214 Ok(fields.into_iter().collect())
1215 }
1216
1217 fn mk_expr_tuple_field_access(
1218 &self,
1219 lo: Span,
1220 ident_span: Span,
1221 base: Box<Expr>,
1222 field: Symbol,
1223 suffix: Option<Symbol>,
1224 ) -> Box<Expr> {
1225 if let Some(suffix) = suffix {
1226 self.dcx().emit_err(diagnostics::InvalidLiteralSuffixOnTupleIndex {
1227 span: ident_span,
1228 suffix,
1229 });
1230 }
1231 self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span)))
1232 }
1233
1234 fn parse_expr_fn_call(&mut self, lo: Span, fun: Box<Expr>) -> Box<Expr> {
1236 let snapshot = if self.token == token::OpenParen {
1237 Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
1238 } else {
1239 None
1240 };
1241 let open_paren = self.token.span;
1242 let call_depth = self.token_cursor.depth();
1243
1244 let seq = match self.parse_expr_paren_seq() {
1245 Ok(args) => Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args))),
1246 Err(err)
1247 if self.is_expected_raw_ref_mut() && self.token_cursor.depth() == call_depth =>
1248 {
1249 let guar = err.emit();
1250 let args = self.recover_raw_ref_call_args(guar);
1253 return self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args));
1254 }
1255 Err(err) => Err(err),
1256 };
1257 match self.maybe_recover_struct_lit_bad_delims(lo, open_paren, seq, snapshot) {
1258 Ok(expr) => expr,
1259 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),
1260 }
1261 }
1262
1263 fn recover_raw_ref_call_args(&mut self, guar: ErrorGuaranteed) -> ThinVec<Box<Expr>> {
1264 let err_span = self.prev_token.span.to(self.token.span);
1265 let mut args = {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(self.mk_expr_err(err_span, guar));
vec
}thin_vec![self.mk_expr_err(err_span, guar)];
1266 while !self.token.kind.is_close_delim_or_eof() {
1267 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1268 if !self.token.kind.is_close_delim_or_eof() {
1269 args.push(self.mk_expr_err(self.prev_token.span.shrink_to_hi(), guar));
1270 }
1271 } else {
1272 self.parse_token_tree();
1273 }
1274 }
1275 let _ = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen));
1276 args
1277 }
1278
1279 {}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("maybe_recover_struct_lit_bad_delims",
"rustc_parse::parser::expr", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_parse/src/parser/expr.rs"),
::tracing_core::__macro_support::Option::Some(1281u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::expr"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("lo")
}> =
::tracing::__macro_support::FieldName::new("lo");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("open_paren")
}> =
::tracing::__macro_support::FieldName::new("open_paren");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&lo)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&open_paren)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: PResult<'a, Box<Expr>> = loop {};
return __tracing_attr_fake_return;
}
{
match (self.may_recover(), seq, snapshot) {
(true, Err(err),
Some((mut snapshot, ExprKind::Path(None, path)))) => {
snapshot.bump();
match snapshot.parse_struct_fields(path.clone(), false,
crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}) {
Ok((fields, ..)) if
snapshot.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}) => {
self.restore_snapshot(snapshot);
let close_paren = self.prev_token.span;
let span = lo.to(close_paren);
let fields: Vec<_> =
fields.into_iter().filter(|field|
!field.is_shorthand).collect();
let guar =
if !fields.is_empty() &&
self.span_to_snippet(close_paren).is_ok_and(|snippet|
snippet == ")") {
err.cancel();
let type_str = pprust::path_to_string(&path);
self.dcx().create_err(diagnostics::ParenthesesWithStructFields {
span,
braces_for_struct: diagnostics::BracesForStructLiteral {
first: open_paren,
second: close_paren,
r#type: type_str.clone(),
},
no_fields_for_fn: diagnostics::NoFieldsForFnCall {
r#type: type_str,
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")]
1282 fn maybe_recover_struct_lit_bad_delims(
1283 &mut self,
1284 lo: Span,
1285 open_paren: Span,
1286 seq: PResult<'a, Box<Expr>>,
1287 snapshot: Option<(SnapshotParser<'a>, ExprKind)>,
1288 ) -> PResult<'a, Box<Expr>> {
1289 match (self.may_recover(), seq, snapshot) {
1290 (true, Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
1291 snapshot.bump(); match snapshot.parse_struct_fields(path.clone(), false, exp!(CloseParen)) {
1293 Ok((fields, ..)) if snapshot.eat(exp!(CloseParen)) => {
1294 self.restore_snapshot(snapshot);
1297 let close_paren = self.prev_token.span;
1298 let span = lo.to(close_paren);
1299 let fields: Vec<_> =
1301 fields.into_iter().filter(|field| !field.is_shorthand).collect();
1302
1303 let guar = if !fields.is_empty() &&
1304 self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")
1309 {
1310 err.cancel();
1311 let type_str = pprust::path_to_string(&path);
1312 self.dcx()
1313 .create_err(diagnostics::ParenthesesWithStructFields {
1314 span,
1315 braces_for_struct: diagnostics::BracesForStructLiteral {
1316 first: open_paren,
1317 second: close_paren,
1318 r#type: type_str.clone(),
1319 },
1320 no_fields_for_fn: diagnostics::NoFieldsForFnCall {
1321 r#type: type_str,
1322 fields: fields
1323 .into_iter()
1324 .map(|field| field.span.until(field.expr.span))
1325 .collect(),
1326 },
1327 })
1328 .emit()
1329 } else {
1330 err.emit()
1331 };
1332 Ok(self.mk_expr_err(span, guar))
1333 }
1334 Ok(_) => Err(err),
1335 Err(err2) => {
1336 err2.cancel();
1337 Err(err)
1338 }
1339 }
1340 }
1341 (_, seq, _) => seq,
1342 }
1343 }
1344
1345 fn parse_expr_index(&mut self, lo: Span, base: Box<Expr>) -> PResult<'a, Box<Expr>> {
1347 let prev_token = self.prev_token;
1348 let open_delim_span = self.token.span;
1349 self.bump(); let index = self.parse_expr()?;
1351 self.suggest_missing_semicolon_before_array(prev_token.span, open_delim_span)?;
1352 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBracket,
token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket)).map_err(|mut err| {
1353 if prev_token.is_non_reserved_ident() {
1354 err.span_suggestion_verbose(
1355 prev_token.span.shrink_to_hi(),
1356 "you might have meant to call a macro",
1357 "!".to_string(),
1358 Applicability::MaybeIncorrect,
1359 );
1360 }
1361 err
1362 })?;
1363 Ok(self.mk_expr(
1364 lo.to(self.prev_token.span),
1365 self.mk_index(base, index, open_delim_span.to(self.prev_token.span)),
1366 ))
1367 }
1368
1369 fn parse_dot_suffix(&mut self, self_arg: Box<Expr>, lo: Span) -> PResult<'a, Box<Expr>> {
1371 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)) {
1372 return Ok(self.mk_await_expr(self_arg, lo));
1373 }
1374
1375 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)) {
1376 let use_span = self.prev_token.span;
1377 self.psess.gated_spans.gate(sym::ergonomic_clones, use_span);
1378 return Ok(self.mk_use_expr(self_arg, lo));
1379 }
1380
1381 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)) {
1383 let match_span = self.prev_token.span;
1384 self.psess.gated_spans.gate(sym::postfix_match, match_span);
1385 return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
1386 }
1387
1388 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)) {
1390 let yield_span = self.prev_token.span;
1391 self.psess.gated_spans.gate(sym::yield_expr, yield_span);
1392 return Ok(
1393 self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg)))
1394 );
1395 }
1396
1397 let fn_span_lo = self.token.span;
1398 let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
1399 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)]);
1400 self.check_turbofish_missing_angle_brackets(&mut seg);
1401
1402 if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1403 let args = self.parse_expr_paren_seq()?;
1405 let fn_span = fn_span_lo.to(self.prev_token.span);
1406 let span = lo.to(self.prev_token.span);
1407 Ok(self.mk_expr(
1408 span,
1409 ExprKind::MethodCall(Box::new(ast::MethodCall {
1410 seg,
1411 receiver: self_arg,
1412 args,
1413 span: fn_span,
1414 })),
1415 ))
1416 } else {
1417 let span = lo.to(self.prev_token.span);
1419 if let Some(args) = seg.args {
1420 self.dcx()
1422 .create_err(diagnostics::FieldExpressionWithGeneric(args.span()))
1423 .stash(seg.ident.span, StashKey::GenericInFieldExpr);
1424 }
1425
1426 Ok(self.mk_expr(span, ExprKind::Field(self_arg, seg.ident)))
1427 }
1428 }
1429
1430 fn parse_expr_bottom(&mut self) -> PResult<'a, Box<Expr>> {
1436 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);
1437
1438 let span = self.token.span;
1439 if let Some(expr) = self.eat_metavar_seq_with_matcher(
1440 |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
MetaVarKind::Expr { .. } => true,
_ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
1441 |this| {
1442 let expr = this.parse_expr_force_collect();
1445 if this.token.kind == token::Comma {
1450 this.bump();
1451 }
1452 expr
1453 },
1454 ) {
1455 return Ok(expr);
1456 } else if let Some(lit) =
1457 self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
1458 {
1459 return Ok(lit);
1460 } else if let Some(block) =
1461 self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())
1462 {
1463 return Ok(self.mk_expr(span, ExprKind::Block(block, None)));
1464 } else if let Some(path) =
1465 self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
1466 {
1467 return Ok(self.mk_expr(span, ExprKind::Path(None, path)));
1468 }
1469
1470 let restrictions = self.restrictions;
1474 self.with_res(restrictions - Restrictions::ALLOW_LET, |this| {
1475 let lo = this.token.span;
1477 if let token::Literal(_) = this.token.kind {
1478 this.parse_expr_lit()
1482 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen)) {
1483 this.parse_expr_tuple_parens(restrictions)
1484 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
1485 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
1486 return Ok(expr);
1487 }
1488 this.parse_expr_block(None, lo, BlockCheckMode::Default)
1489 } 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)) {
1490 this.parse_expr_closure().map_err(|mut err| {
1491 if let Some(sp) = this.psess.ambiguous_block_expr_parse.borrow().get(&lo) {
1494 err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
1495 }
1496 err
1497 })
1498 } else if this.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBracket,
token_type: crate::parser::token_type::TokenType::OpenBracket,
}exp!(OpenBracket)) {
1499 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))
1500 } else if this.is_builtin() {
1501 this.parse_expr_builtin()
1502 } else if this.check_path() {
1503 this.parse_expr_path_start()
1504 } 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))
1505 || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Use,
token_type: crate::parser::token_type::TokenType::KwUse,
}exp!(Use))
1506 || this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Static,
token_type: crate::parser::token_type::TokenType::KwStatic,
}exp!(Static))
1507 || this.check_const_closure()
1508 {
1509 this.parse_expr_closure()
1510 } 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)) {
1511 this.parse_expr_if()
1512 } 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)) {
1513 if this.choose_generics_over_qpath(1) {
1514 this.parse_expr_closure()
1515 } else {
1516 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)));
1517 this.parse_expr_for(None, lo)
1518 }
1519 } 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)) {
1520 this.parse_expr_while(None, lo)
1521 } else if let Some(label) = this.eat_label() {
1522 this.parse_expr_labeled(label, true)
1523 } 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)) {
1524 this.parse_expr_loop(None, lo).map_err(|mut err| {
1525 err.span_label(lo, "while parsing this `loop` expression");
1526 err
1527 })
1528 } 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)) {
1529 this.parse_expr_match().map_err(|mut err| {
1530 err.span_label(lo, "while parsing this `match` expression");
1531 err
1532 })
1533 } 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)) {
1534 this.parse_expr_block(None, lo, BlockCheckMode::Unsafe(ast::UserProvided)).map_err(
1535 |mut err| {
1536 err.span_label(lo, "while parsing this `unsafe` expression");
1537 err
1538 },
1539 )
1540 } else if this.check_inline_const(0) {
1541 this.parse_const_block(lo, false)
1542 } else if this.may_recover() && this.is_do_catch_block() {
1543 this.recover_do_catch()
1544 } else if this.is_try_block() {
1545 this.expect_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Try,
token_type: crate::parser::token_type::TokenType::KwTry,
}exp!(Try))?;
1546 this.parse_try_block(lo)
1547 } 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)) {
1548 this.parse_expr_return()
1549 } 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)) {
1550 this.parse_expr_continue(lo)
1551 } 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)) {
1552 this.parse_expr_break()
1553 } 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)) {
1554 this.parse_expr_yield()
1555 } else if this.is_do_yeet() {
1556 this.parse_expr_yeet()
1557 } 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)) {
1558 this.parse_expr_become()
1559 } 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)) {
1560 this.parse_expr_let(restrictions)
1561 } 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)) {
1562 if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
1563 return Ok(expr);
1564 }
1565 Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
1566 } else if this.token_uninterpolated_span().at_least_rust_2018() {
1567 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));
1569 if this.token_uninterpolated_span().at_least_rust_2024()
1574 && this.is_gen_block(kw::Gen, at_async as usize)
1575 {
1576 this.parse_gen_block()
1577 } else if this.is_gen_block(kw::Async, 0) {
1579 this.parse_gen_block()
1580 } else if at_async {
1581 this.parse_expr_closure()
1582 } else if this.eat_keyword_noexpect(kw::Await) {
1583 this.recover_incorrect_await_syntax(lo)
1584 } else {
1585 this.parse_expr_lit()
1586 }
1587 } else {
1588 this.parse_expr_lit()
1589 }
1590 })
1591 }
1592
1593 fn parse_expr_lit(&mut self) -> PResult<'a, Box<Expr>> {
1594 let lo = self.token.span;
1595 match self.parse_opt_token_lit() {
1596 Some((token_lit, _)) => {
1597 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(token_lit));
1598 self.maybe_recover_from_bad_qpath(expr)
1599 }
1600 None => self.try_macro_suggestion(),
1601 }
1602 }
1603
1604 fn parse_expr_tuple_parens(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
1605 let lo = self.token.span;
1606 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1607 let (es, trailing_comma) = match self.parse_seq_to_end(
1608 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1609 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
1610 |p| p.parse_expr_res(restrictions.intersection(Restrictions::ALLOW_LET)),
1611 ) {
1612 Ok(x) => x,
1613 Err(err) => {
1614 return Ok(self.recover_seq_parse_error(
1615 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen),
1616 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen),
1617 lo,
1618 err,
1619 ));
1620 }
1621 };
1622 let kind = if es.len() == 1 && #[allow(non_exhaustive_omitted_patterns)] match trailing_comma {
Trailing::No => true,
_ => false,
}matches!(trailing_comma, Trailing::No) {
1623 ExprKind::Paren(es.into_iter().next().unwrap())
1625 } else {
1626 ExprKind::Tup(es)
1628 };
1629 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1630 self.maybe_recover_from_bad_qpath(expr)
1631 }
1632
1633 fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair) -> PResult<'a, Box<Expr>> {
1634 let lo = self.token.span;
1635 self.bump(); let kind = if self.eat(close) {
1638 ExprKind::Array(ThinVec::new())
1640 } else {
1641 let first_expr = self.parse_expr()?;
1643 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) {
1644 let count = self.parse_expr_anon_const()?;
1646 self.expect(close)?;
1647 ExprKind::Repeat(first_expr, count)
1648 } else if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
1649 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));
1651 let (mut exprs, _) = self.parse_seq_to_end(close, sep, |p| p.parse_expr())?;
1652 exprs.insert(0, first_expr);
1653 ExprKind::Array(exprs)
1654 } else {
1655 self.expect(close)?;
1657 ExprKind::Array({
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(first_expr);
vec
}thin_vec![first_expr])
1658 }
1659 };
1660 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1661 self.maybe_recover_from_bad_qpath(expr)
1662 }
1663
1664 fn parse_expr_path_start(&mut self) -> PResult<'a, Box<Expr>> {
1665 let maybe_eq_tok = self.prev_token;
1666 let (qself, path) = if self.eat_lt() {
1667 let lt_span = self.prev_token.span;
1668 let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
1669 if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
1673 let eq_lt = maybe_eq_tok.span.to(lt_span);
1674 err.span_suggestion_verbose(
1675 eq_lt,
1676 "you might have meant to write a \"less than or equal to\" comparison",
1677 "<=",
1678 Applicability::Unspecified,
1679 );
1680 }
1681 err
1682 })?;
1683 (Some(qself), path)
1684 } else {
1685 (None, self.parse_path(PathStyle::Expr)?)
1686 };
1687
1688 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)) {
1690 if qself.is_some() {
1692 self.dcx().emit_err(diagnostics::MacroInvocationWithQualifiedPath(path.span));
1693 }
1694 let lo = path.span;
1695 let mac = Box::new(MacCall { path, args: self.parse_delim_args()? });
1696 (lo.to(self.prev_token.span), ExprKind::MacCall(mac))
1697 } else if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
1698 && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path)
1699 {
1700 if qself.is_some() {
1701 self.psess.gated_spans.gate(sym::more_qualified_paths, path.span);
1702 }
1703 return expr;
1704 } else {
1705 (path.span, ExprKind::Path(qself, path))
1706 };
1707
1708 let expr = self.mk_expr(span, kind);
1709 self.maybe_recover_from_bad_qpath(expr)
1710 }
1711
1712 pub(super) fn parse_expr_labeled(
1714 &mut self,
1715 label_: Label,
1716 mut consume_colon: bool,
1717 ) -> PResult<'a, Box<Expr>> {
1718 let lo = label_.ident.span;
1719 let label = Some(label_);
1720 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));
1721 let tok_sp = self.token.span;
1722 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)) {
1723 self.parse_expr_while(label, lo)
1724 } 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)) {
1725 self.parse_expr_for(label, lo)
1726 } 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)) {
1727 self.parse_expr_loop(label, lo)
1728 } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {
1729 self.parse_expr_block(label, lo, BlockCheckMode::Default)
1730 } else if !ate_colon
1731 && self.may_recover()
1732 && (self.token.kind.close_delim().is_some() || self.token.is_punct())
1733 && could_be_unclosed_char_literal(label_.ident)
1734 {
1735 let (lit, _) =
1736 self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
1737 self_.dcx().create_err(diagnostics::UnexpectedTokenAfterLabel {
1738 span: self_.token.span,
1739 remove_label: None,
1740 enclose_in_block: None,
1741 })
1742 });
1743 consume_colon = false;
1744 Ok(self.mk_expr(lo, ExprKind::Lit(lit)))
1745 } else if !ate_colon
1746 && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
1747 {
1748 let guar = self.dcx().emit_err(diagnostics::UnexpectedTokenAfterLabel {
1750 span: self.token.span,
1751 remove_label: None,
1752 enclose_in_block: None,
1753 });
1754 consume_colon = false;
1755 Ok(self.mk_expr_err(lo, guar))
1756 } else {
1757 let mut err = diagnostics::UnexpectedTokenAfterLabel {
1758 span: self.token.span,
1759 remove_label: None,
1760 enclose_in_block: None,
1761 };
1762
1763 let expr = self.parse_expr().map(|expr| {
1765 let span = expr.span;
1766
1767 let found_labeled_breaks = {
1768 struct FindLabeledBreaksVisitor;
1769
1770 impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {
1771 type Result = ControlFlow<()>;
1772 fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {
1773 if let ExprKind::Break(Some(_label), _) = ex.kind {
1774 ControlFlow::Break(())
1775 } else {
1776 walk_expr(self, ex)
1777 }
1778 }
1779 }
1780
1781 FindLabeledBreaksVisitor.visit_expr(&expr).is_break()
1782 };
1783
1784 if !found_labeled_breaks {
1789 err.remove_label = Some(lo.until(span));
1790
1791 return expr;
1792 }
1793
1794 err.enclose_in_block = Some(diagnostics::UnexpectedTokenAfterLabelSugg {
1795 left: span.shrink_to_lo(),
1796 right: span.shrink_to_hi(),
1797 });
1798
1799 let stmt = self.mk_stmt(span, StmtKind::Expr(expr));
1801 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);
1802 self.mk_expr(span, ExprKind::Block(blk, label))
1803 });
1804
1805 self.dcx().emit_err(err);
1806 expr
1807 }?;
1808
1809 if !ate_colon && consume_colon {
1810 self.dcx().emit_err(diagnostics::RequireColonAfterLabeledExpression {
1811 span: expr.span,
1812 label: lo,
1813 label_end: lo.between(tok_sp),
1814 });
1815 }
1816
1817 Ok(expr)
1818 }
1819
1820 pub(super) fn recover_unclosed_char<L>(
1822 &self,
1823 ident: Ident,
1824 mk_lit_char: impl FnOnce(Symbol, Span) -> L,
1825 err: impl FnOnce(&Self) -> Diag<'a>,
1826 ) -> L {
1827 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));
1828 self.dcx()
1829 .try_steal_modify_and_emit_err(ident.span, StashKey::LifetimeIsChar, |err| {
1830 err.span_suggestion_verbose(
1831 ident.span.shrink_to_hi(),
1832 "add `'` to close the char literal",
1833 "'",
1834 Applicability::MaybeIncorrect,
1835 );
1836 })
1837 .unwrap_or_else(|| {
1838 err(self)
1839 .with_span_suggestion_verbose(
1840 ident.span.shrink_to_hi(),
1841 "add `'` to close the char literal",
1842 "'",
1843 Applicability::MaybeIncorrect,
1844 )
1845 .emit()
1846 });
1847 let name = ident.without_first_quote().name;
1848 mk_lit_char(name, ident.span)
1849 }
1850
1851 fn recover_do_catch(&mut self) -> PResult<'a, Box<Expr>> {
1853 let lo = self.token.span;
1854
1855 self.bump(); self.bump(); let span = lo.to(self.prev_token.span);
1859 self.dcx().emit_err(diagnostics::DoCatchSyntaxRemoved { span });
1860
1861 self.parse_try_block(lo)
1862 }
1863
1864 fn parse_expr_opt(&mut self) -> PResult<'a, Option<Box<Expr>>> {
1866 Ok(if self.token.can_begin_expr() { Some(self.parse_expr()?) } else { None })
1867 }
1868
1869 fn parse_expr_return(&mut self) -> PResult<'a, Box<Expr>> {
1871 let lo = self.prev_token.span;
1872 let kind = ExprKind::Ret(self.parse_expr_opt()?);
1873 let expr = self.mk_expr(lo.to(self.prev_token.span), kind);
1874 self.maybe_recover_from_bad_qpath(expr)
1875 }
1876
1877 fn parse_expr_yeet(&mut self) -> PResult<'a, Box<Expr>> {
1879 let lo = self.token.span;
1880
1881 self.bump(); self.bump(); let kind = ExprKind::Yeet(self.parse_expr_opt()?);
1885
1886 let span = lo.to(self.prev_token.span);
1887 self.psess.gated_spans.gate(sym::yeet_expr, span);
1888 let expr = self.mk_expr(span, kind);
1889 self.maybe_recover_from_bad_qpath(expr)
1890 }
1891
1892 fn parse_expr_become(&mut self) -> PResult<'a, Box<Expr>> {
1894 let lo = self.prev_token.span;
1895 let kind = ExprKind::Become(self.parse_expr()?);
1896 let span = lo.to(self.prev_token.span);
1897 self.psess.gated_spans.gate(sym::explicit_tail_calls, span);
1898 let expr = self.mk_expr(span, kind);
1899 self.maybe_recover_from_bad_qpath(expr)
1900 }
1901
1902 fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {
1911 let lo = self.prev_token.span;
1912 let mut label = self.eat_label();
1913 let kind = if self.token == token::Colon
1914 && let Some(label) = label.take()
1915 {
1916 let lexpr = self.parse_expr_labeled(label, true)?;
1919 self.dcx().emit_err(diagnostics::LabeledLoopInBreak {
1920 span: lexpr.span,
1921 sub: diagnostics::WrapInParentheses::Expression {
1922 left: lexpr.span.shrink_to_lo(),
1923 right: lexpr.span.shrink_to_hi(),
1924 },
1925 });
1926 Some(lexpr)
1927 } else if self.token != token::OpenBrace
1928 || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
1929 {
1930 let mut expr = self.parse_expr_opt()?;
1931 if let Some(expr) = &mut expr {
1932 if label.is_some()
1933 && match &expr.kind {
1934 ExprKind::While(_, _, None)
1935 | ExprKind::ForLoop(ForLoop { label: None, .. })
1936 | ExprKind::Loop(_, None, _) => true,
1937 ExprKind::Block(block, None) => {
1938 #[allow(non_exhaustive_omitted_patterns)] match block.rules {
BlockCheckMode::Default => true,
_ => false,
}matches!(block.rules, BlockCheckMode::Default)
1939 }
1940 _ => false,
1941 }
1942 {
1943 let span = expr.span;
1944 self.psess.buffer_lint(
1945 BREAK_WITH_LABEL_AND_LOOP,
1946 lo.to(expr.span),
1947 ast::CRATE_NODE_ID,
1948 diagnostics::BreakWithLabelAndLoop {
1949 sub: diagnostics::BreakWithLabelAndLoopSub {
1950 left: span.shrink_to_lo(),
1951 right: span.shrink_to_hi(),
1952 },
1953 },
1954 );
1955 }
1956
1957 if self.may_recover()
1959 && let ExprKind::Path(None, p) = &expr.kind
1960 && let [segment] = &*p.segments
1961 && let &ast::PathSegment { ident, args: None, .. } = segment
1962 && let Some(next) = self.parse_expr_opt()?
1963 {
1964 label = Some(self.recover_ident_into_label(ident));
1965 *expr = next;
1966 }
1967 }
1968
1969 expr
1970 } else {
1971 None
1972 };
1973 let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind));
1974 self.maybe_recover_from_bad_qpath(expr)
1975 }
1976
1977 fn parse_expr_continue(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
1979 let mut label = self.eat_label();
1980
1981 if self.may_recover()
1983 && label.is_none()
1984 && let Some((ident, _)) = self.token.ident()
1985 {
1986 self.bump();
1987 label = Some(self.recover_ident_into_label(ident));
1988 }
1989
1990 let kind = ExprKind::Continue(label);
1991 Ok(self.mk_expr(lo.to(self.prev_token.span), kind))
1992 }
1993
1994 fn parse_expr_yield(&mut self) -> PResult<'a, Box<Expr>> {
1996 let lo = self.prev_token.span;
1997 let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?));
1998 let span = lo.to(self.prev_token.span);
1999 self.psess.gated_spans.gate(sym::yield_expr, span);
2000 let expr = self.mk_expr(span, kind);
2001 self.maybe_recover_from_bad_qpath(expr)
2002 }
2003
2004 fn parse_expr_builtin(&mut self) -> PResult<'a, Box<Expr>> {
2006 self.parse_builtin(|this, lo, ident| {
2007 Ok(match ident.name {
2008 sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
2009 sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
2010 sym::wrap_binder => {
2011 Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Wrap)?)
2012 }
2013 sym::unwrap_binder => {
2014 Some(this.parse_expr_unsafe_binder_cast(lo, UnsafeBinderCastKind::Unwrap)?)
2015 }
2016 _ => None,
2017 })
2018 })
2019 }
2020
2021 pub(crate) fn parse_builtin<T>(
2022 &mut self,
2023 parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
2024 ) -> PResult<'a, T> {
2025 let lo = self.token.span;
2026
2027 self.bump(); self.bump(); let Some((ident, IdentIsRaw::No)) = self.token.ident() else {
2031 let err =
2032 self.dcx().create_err(diagnostics::ExpectedBuiltinIdent { span: self.token.span });
2033 return Err(err);
2034 };
2035 self.psess.gated_spans.gate(sym::builtin_syntax, ident.span);
2036 self.bump();
2037
2038 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
2039 let ret = if let Some(res) = parse(self, lo, ident)? {
2040 Ok(res)
2041 } else {
2042 let err = self.dcx().create_err(diagnostics::UnknownBuiltinConstruct {
2043 span: lo.to(ident.span),
2044 name: ident,
2045 });
2046 return Err(err);
2047 };
2048 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
2049
2050 ret
2051 }
2052
2053 pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
2055 let container = self.parse_ty()?;
2056 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
2057
2058 let fields = self.parse_floating_field_access()?;
2059 let trailing_comma = self.eat_noexpect(&TokenKind::Comma);
2060
2061 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)]) {
2062 if trailing_comma {
2063 e.note("unexpected third argument to offset_of");
2064 } else {
2065 e.note("offset_of expects dot-separated field and variant names");
2066 }
2067 e.emit();
2068 }
2069
2070 if self.may_recover() {
2072 while !self.token.kind.is_close_delim_or_eof() {
2073 self.bump();
2074 }
2075 }
2076
2077 let span = lo.to(self.token.span);
2078 Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
2079 }
2080
2081 pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, Box<Expr>> {
2083 let expr = self.parse_expr()?;
2084 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))?;
2085 let ty = self.parse_ty()?;
2086 let span = lo.to(self.token.span);
2087 Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
2088 }
2089
2090 pub(crate) fn parse_expr_unsafe_binder_cast(
2091 &mut self,
2092 lo: Span,
2093 kind: UnsafeBinderCastKind,
2094 ) -> PResult<'a, Box<Expr>> {
2095 let expr = self.parse_expr()?;
2096 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 };
2097 let span = lo.to(self.token.span);
2098 Ok(self.mk_expr(span, ExprKind::UnsafeBinderCast(kind, expr, ty)))
2099 }
2100
2101 pub fn parse_str_lit(&mut self) -> Result<ast::StrLit, Option<MetaItemLit>> {
2105 match self.parse_opt_meta_item_lit() {
2106 Some(lit) => match lit.kind {
2107 ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit {
2108 style,
2109 symbol: lit.symbol,
2110 suffix: lit.suffix,
2111 span: lit.span,
2112 symbol_unescaped,
2113 }),
2114 _ => Err(Some(lit)),
2115 },
2116 None => Err(None),
2117 }
2118 }
2119
2120 pub(crate) fn mk_token_lit_char(name: Symbol, span: Span) -> (token::Lit, Span) {
2121 (token::Lit { symbol: name, suffix: None, kind: token::Char }, span)
2122 }
2123
2124 fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit {
2125 ast::MetaItemLit {
2126 symbol: name,
2127 suffix: None,
2128 kind: ast::LitKind::Char(name.as_str().chars().next().unwrap_or('_')),
2129 span,
2130 }
2131 }
2132
2133 fn handle_missing_lit<L>(
2134 &mut self,
2135 mk_lit_char: impl FnOnce(Symbol, Span) -> L,
2136 ) -> PResult<'a, L> {
2137 let token = self.token;
2138 let err = |self_: &Self| {
2139 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));
2140 self_.dcx().struct_span_err(token.span, msg)
2141 };
2142 if let Some((ident, IdentIsRaw::No)) = self.token.lifetime()
2145 && could_be_unclosed_char_literal(ident)
2146 {
2147 let lt = self.expect_lifetime();
2148 Ok(self.recover_unclosed_char(lt.ident, mk_lit_char, err))
2149 } else {
2150 Err(err(self))
2151 }
2152 }
2153
2154 pub(super) fn parse_token_lit(&mut self) -> PResult<'a, (token::Lit, Span)> {
2155 self.parse_opt_token_lit()
2156 .ok_or(())
2157 .or_else(|()| self.handle_missing_lit(Parser::mk_token_lit_char))
2158 }
2159
2160 pub(super) fn parse_meta_item_lit(&mut self) -> PResult<'a, MetaItemLit> {
2161 self.parse_opt_meta_item_lit()
2162 .ok_or(())
2163 .or_else(|()| self.handle_missing_lit(Parser::mk_meta_item_lit_char))
2164 }
2165
2166 fn recover_after_dot(&mut self) {
2167 if self.token == token::Dot {
2168 let recovered = self.look_ahead(1, |next_token| {
2171 if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) =
2178 next_token.kind
2179 && suffix.is_none_or(|s| s == sym::f32 || s == sym::f64)
2180 && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_')
2181 && self.token.span.hi() == next_token.span.lo()
2182 {
2183 let s = String::from("0.") + symbol.as_str();
2184 let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
2185 Some(Token::new(kind, self.token.span.to(next_token.span)))
2186 } else {
2187 None
2188 }
2189 });
2190 if let Some(recovered) = recovered {
2191 self.dcx().emit_err(diagnostics::FloatLiteralRequiresIntegerPart {
2192 span: recovered.span,
2193 suggestion: recovered.span.shrink_to_lo(),
2194 });
2195 self.bump();
2196 self.token = recovered;
2197 }
2198 }
2199 }
2200
2201 pub fn eat_token_lit(&mut self) -> Option<token::Lit> {
2204 let check_expr = |expr: Box<Expr>| {
2205 if let ast::ExprKind::Lit(token_lit) = expr.kind {
2206 Some(token_lit)
2207 } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind
2208 && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner
2209 {
2210 None
2211 } else {
2212 {
::core::panicking::panic_fmt(format_args!("unexpected reparsed expr/literal: {0:?}",
expr.kind));
};panic!("unexpected reparsed expr/literal: {:?}", expr.kind);
2213 }
2214 };
2215 match self.token.uninterpolate().kind {
2216 token::Ident(name, IdentIsRaw::No) if name.is_bool_lit() => {
2217 self.bump();
2218 Some(token::Lit::new(token::Bool, name, None))
2219 }
2220 token::Literal(token_lit) => {
2221 self.bump();
2222 Some(token_lit)
2223 }
2224 token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => {
2225 let lit = self
2226 .eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2227 .expect("metavar seq literal");
2228 check_expr(lit)
2229 }
2230 token::OpenInvisible(InvisibleOrigin::MetaVar(
2231 mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. },
2232 )) => {
2233 let expr = self
2234 .eat_metavar_seq(mv_kind, |this| this.parse_expr())
2235 .expect("metavar seq expr");
2236 check_expr(expr)
2237 }
2238 _ => None,
2239 }
2240 }
2241
2242 fn parse_opt_token_lit(&mut self) -> Option<(token::Lit, Span)> {
2245 self.recover_after_dot();
2246 let span = self.token.span;
2247 self.eat_token_lit().map(|token_lit| (token_lit, span))
2248 }
2249
2250 fn parse_opt_meta_item_lit(&mut self) -> Option<MetaItemLit> {
2253 self.recover_after_dot();
2254 let span = self.token.span;
2255 let uninterpolated_span = self.token_uninterpolated_span();
2256 self.eat_token_lit().map(|token_lit| {
2257 match MetaItemLit::from_token_lit(token_lit, span) {
2258 Ok(lit) => lit,
2259 Err(err) => {
2260 let guar = report_lit_error(&self.psess, err, token_lit, uninterpolated_span);
2261 let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
2264 let symbol = Symbol::intern(&suffixless_lit.to_string());
2265 let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
2266 MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
2267 }
2268 }
2269 })
2270 }
2271
2272 pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> {
2275 if let Some(expr) = self.eat_metavar_seq_with_matcher(
2276 |mv_kind| #[allow(non_exhaustive_omitted_patterns)] match mv_kind {
MetaVarKind::Expr { .. } => true,
_ => false,
}matches!(mv_kind, MetaVarKind::Expr { .. }),
2277 |this| {
2278 this.parse_expr()
2289 },
2290 ) {
2291 return Ok(expr);
2292 } else if let Some(lit) =
2293 self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
2294 {
2295 return Ok(lit);
2296 }
2297
2298 let lo = self.token.span;
2299 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));
2300 let (token_lit, span) = self.parse_token_lit()?;
2301 let expr = self.mk_expr(span, ExprKind::Lit(token_lit));
2302
2303 if minus_present {
2304 Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_unary(UnOp::Neg, expr)))
2305 } else {
2306 Ok(expr)
2307 }
2308 }
2309
2310 fn is_array_like_block(&mut self) -> bool {
2311 self.token.kind == TokenKind::OpenBrace
2312 && self
2313 .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(_)))
2314 && self.look_ahead(2, |t| t == &token::Comma)
2315 && self.look_ahead(3, |t| t.can_begin_expr())
2316 }
2317
2318 fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<Box<Expr>> {
2322 let mut snapshot = self.create_snapshot_for_diagnostic();
2323 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)) {
2324 Ok(arr) => {
2325 let guar = self.dcx().emit_err(diagnostics::ArrayBracketsInsteadOfBraces {
2326 span: arr.span,
2327 sub: diagnostics::ArrayBracketsInsteadOfBracesSugg {
2328 left: lo,
2329 right: snapshot.prev_token.span,
2330 },
2331 });
2332
2333 self.restore_snapshot(snapshot);
2334 Some(self.mk_expr_err(arr.span, guar))
2335 }
2336 Err(e) => {
2337 e.cancel();
2338 None
2339 }
2340 }
2341 }
2342
2343 fn suggest_missing_semicolon_before_array(
2344 &self,
2345 prev_span: Span,
2346 open_delim_span: Span,
2347 ) -> PResult<'a, ()> {
2348 if !self.may_recover() {
2349 return Ok(());
2350 }
2351
2352 if self.token == token::Comma {
2353 if !self.psess.source_map().is_multiline(prev_span.until(self.token.span)) {
2354 return Ok(());
2355 }
2356 let mut snapshot = self.create_snapshot_for_diagnostic();
2357 snapshot.bump();
2358 match snapshot.parse_seq_to_before_end(
2359 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBracket,
token_type: crate::parser::token_type::TokenType::CloseBracket,
}exp!(CloseBracket),
2360 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2361 |p| p.parse_expr(),
2362 ) {
2363 Ok(_)
2364 if snapshot
2370 .span_to_snippet(snapshot.token.span)
2371 .is_ok_and(|snippet| snippet == "]") =>
2372 {
2373 return Err(self.dcx().create_err(diagnostics::MissingSemicolonBeforeArray {
2374 open_delim: open_delim_span,
2375 semicolon: prev_span.shrink_to_hi(),
2376 }));
2377 }
2378 Ok(_) => (),
2379 Err(err) => err.cancel(),
2380 }
2381 }
2382 Ok(())
2383 }
2384
2385 pub(super) fn parse_expr_block(
2387 &mut self,
2388 opt_label: Option<Label>,
2389 lo: Span,
2390 blk_mode: BlockCheckMode,
2391 ) -> PResult<'a, Box<Expr>> {
2392 if self.may_recover() && self.is_array_like_block() {
2393 if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) {
2394 return Ok(arr);
2395 }
2396 }
2397
2398 if self.token.is_metavar_block() {
2399 self.dcx().emit_err(diagnostics::InvalidBlockMacroSegment {
2400 span: self.token.span,
2401 context: lo.to(self.token.span),
2402 wrap: diagnostics::WrapInExplicitBlock {
2403 lo: self.token.span.shrink_to_lo(),
2404 hi: self.token.span.shrink_to_hi(),
2405 },
2406 });
2407 }
2408
2409 let (attrs, blk) = self.parse_block_common(lo, blk_mode, None)?;
2410 Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
2411 }
2412
2413 fn parse_simple_block(&mut self) -> PResult<'a, Box<Expr>> {
2415 let blk = self.parse_block()?;
2416 Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None)))
2417 }
2418
2419 fn parse_expr_closure(&mut self) -> PResult<'a, Box<Expr>> {
2421 let lo = self.token.span;
2422
2423 let before = self.prev_token;
2424 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)) {
2425 let lo = self.token.span;
2426 let (bound_vars, _) = self.parse_higher_ranked_binder()?;
2427 let span = lo.to(self.prev_token.span);
2428
2429 self.psess.gated_spans.gate(sym::closure_lifetime_binder, span);
2430
2431 ClosureBinder::For { span, generic_params: bound_vars }
2432 } else {
2433 ClosureBinder::NotPresent
2434 };
2435
2436 let constness = self.parse_closure_constness();
2437
2438 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)) {
2439 self.psess.gated_spans.gate(sym::coroutines, self.prev_token.span);
2440 Movability::Static
2441 } else {
2442 Movability::Movable
2443 };
2444
2445 let coroutine_marker = if self.token_uninterpolated_span().at_least_rust_2018() {
2446 self.parse_coroutine_marker(Case::Sensitive)
2447 } else {
2448 None
2449 };
2450
2451 if let ClosureBinder::NotPresent = binder
2452 && coroutine_marker.is_some()
2453 {
2454 self.expected_token_types.insert(TokenType::OpenBrace);
2457 }
2458
2459 let capture_clause = self.parse_capture_clause()?;
2460 let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
2461 let decl_hi = self.prev_token.span;
2462 let mut body = match &fn_decl.output {
2463 FnRetTy::Default(_) => {
2465 let restrictions =
2466 self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2467 let prev = self.prev_token;
2468 let token = self.token;
2469 match self.parse_expr_res(restrictions) {
2470 Ok(expr) => expr,
2471 Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
2472 }
2473 }
2474 FnRetTy::Ty(ty) => self.parse_closure_block_body(ty.span)?,
2476 };
2477
2478 if let Some(coroutine_marker) = coroutine_marker
2479 && coroutine_marker.kind.is_gen()
2480 {
2481 self.psess.gated_spans.gate(sym::gen_blocks, coroutine_marker.span);
2484 }
2485
2486 if self.token == TokenKind::Semi
2487 && let Some((Delimiter::Parenthesis, _)) = self.token_cursor.parent_delim_and_span()
2488 && self.may_recover()
2489 {
2490 body = self.mk_expr_err(
2494 body.span,
2495 self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"),
2496 );
2497 }
2498
2499 let body_span = body.span;
2500
2501 let closure = self.mk_expr(
2502 lo.to(body.span),
2503 ExprKind::Closure(Box::new(ast::Closure {
2504 binder,
2505 capture_clause,
2506 constness,
2507 coroutine_marker,
2508 movability,
2509 fn_decl,
2510 body,
2511 fn_decl_span: lo.to(decl_hi),
2512 fn_arg_span,
2513 })),
2514 );
2515
2516 let spans =
2518 ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span };
2519 self.current_closure = Some(spans);
2520
2521 Ok(closure)
2522 }
2523
2524 fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, Box<Expr>> {
2526 if self.may_recover()
2527 && self.token.can_begin_expr()
2528 && self.token.kind != TokenKind::OpenBrace
2529 && !self.token.is_metavar_block()
2530 {
2531 let snapshot = self.create_snapshot_for_diagnostic();
2532 let restrictions =
2533 self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
2534 let tok = self.token.clone();
2535 match self.parse_expr_res(restrictions) {
2536 Ok(expr) => {
2537 let descr = super::token_descr(&tok);
2538 let mut diag = self
2539 .dcx()
2540 .struct_span_err(tok.span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected `{{`, found {0}", descr))
})format!("expected `{{`, found {descr}"));
2541 diag.span_label(
2542 ret_span,
2543 "explicit return type requires closure body to be enclosed in braces",
2544 );
2545 diag.multipart_suggestion(
2546 "wrap the expression in curly braces",
2547 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(expr.span.shrink_to_lo(), "{ ".to_string()),
(expr.span.shrink_to_hi(), " }".to_string())]))vec![
2548 (expr.span.shrink_to_lo(), "{ ".to_string()),
2549 (expr.span.shrink_to_hi(), " }".to_string()),
2550 ],
2551 Applicability::MachineApplicable,
2552 );
2553 diag.emit();
2554 return Ok(expr);
2555 }
2556 Err(diag) => {
2557 diag.cancel();
2558 self.restore_snapshot(snapshot);
2559 }
2560 }
2561 }
2562
2563 let body_lo = self.token.span;
2564 self.parse_expr_block(None, body_lo, BlockCheckMode::Default)
2565 }
2566
2567 fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
2569 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)) {
2570 let move_kw_span = self.prev_token.span;
2571 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)) {
2573 let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2574 Err(self
2575 .dcx()
2576 .create_err(diagnostics::AsyncMoveOrderIncorrect { span: move_async_span }))
2577 } else {
2578 Ok(CaptureBy::Value { move_kw: move_kw_span })
2579 }
2580 } 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)) {
2581 let use_kw_span = self.prev_token.span;
2582 self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span);
2583 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)) {
2585 let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
2586 Err(self
2587 .dcx()
2588 .create_err(diagnostics::AsyncUseOrderIncorrect { span: use_async_span }))
2589 } else {
2590 Ok(CaptureBy::Use { use_kw: use_kw_span })
2591 }
2592 } else {
2593 Ok(CaptureBy::Ref)
2594 }
2595 }
2596
2597 fn parse_fn_block_decl(&mut self) -> PResult<'a, (Box<FnDecl>, Span)> {
2599 let arg_start = self.token.span.lo();
2600
2601 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)) {
2602 ThinVec::new()
2603 } else {
2604 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Or,
token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or))?;
2605 let args = self
2606 .parse_seq_to_before_tokens(
2607 &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Or,
token_type: crate::parser::token_type::TokenType::Or,
}exp!(Or)],
2608 &[&token::OrOr],
2609 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
2610 |p| p.parse_fn_block_param(),
2611 )?
2612 .0;
2613 self.expect_or()?;
2614 args
2615 };
2616 let arg_span = self.prev_token.span.with_lo(arg_start);
2617 let output =
2618 self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes)?;
2619
2620 Ok((Box::new(FnDecl { inputs, output }), arg_span))
2621 }
2622
2623 fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
2625 let lo = self.token.span;
2626 let attrs = self.parse_outer_attributes()?;
2627 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
2628 let pat = Box::new(this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?);
2629 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)) {
2630 this.parse_ty()?
2631 } else {
2632 this.mk_ty(pat.span, TyKind::Infer)
2633 };
2634
2635 Ok((
2636 Param {
2637 attrs,
2638 ty,
2639 pat,
2640 span: lo.to(this.prev_token.span),
2641 id: DUMMY_NODE_ID,
2642 is_placeholder: false,
2643 },
2644 Trailing::from(this.token == token::Comma),
2645 UsePreAttrPos::No,
2646 ))
2647 })
2648 }
2649
2650 fn parse_expr_if(&mut self) -> PResult<'a, Box<Expr>> {
2652 let lo = self.prev_token.span;
2653 let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
2656 let cond = self.parse_expr_cond(let_chains_policy)?;
2657 self.parse_if_after_cond(lo, cond)
2658 }
2659
2660 fn parse_if_after_cond(&mut self, lo: Span, mut cond: Box<Expr>) -> PResult<'a, Box<Expr>> {
2661 let cond_span = cond.span;
2662 let mut recover_block_from_condition = |this: &mut Self| {
2666 let block = match &mut cond.kind {
2667 ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
2668 if let ExprKind::Block(_, None) = right.kind =>
2669 {
2670 let guar = this.dcx().emit_err(diagnostics::IfExpressionMissingThenBlock {
2671 if_span: lo,
2672 missing_then_block_sub:
2673 diagnostics::IfExpressionMissingThenBlockSub::UnfinishedCondition(
2674 cond_span.shrink_to_lo().to(*binop_span),
2675 ),
2676 let_else_sub: None,
2677 });
2678 std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar))
2679 }
2680 ExprKind::Block(_, None) => {
2681 let guar = this.dcx().emit_err(diagnostics::IfExpressionMissingCondition {
2682 if_span: lo.with_neighbor(cond.span).shrink_to_hi(),
2683 block_span: self.psess.source_map().start_point(cond_span),
2684 });
2685 std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar))
2686 }
2687 _ => {
2688 return None;
2689 }
2690 };
2691 if let ExprKind::Block(block, _) = &block.kind {
2692 Some(block.clone())
2693 } else {
2694 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
2695 }
2696 };
2697 let thn = if self.token.is_keyword(kw::Else) {
2699 if let Some(block) = recover_block_from_condition(self) {
2700 block
2701 } else {
2702 let let_else_sub = #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
ExprKind::Let(..) => true,
_ => false,
}matches!(cond.kind, ExprKind::Let(..))
2703 .then(|| diagnostics::IfExpressionLetSomeSub { if_span: lo.until(cond_span) });
2704
2705 let guar = self.dcx().emit_err(diagnostics::IfExpressionMissingThenBlock {
2706 if_span: lo,
2707 missing_then_block_sub:
2708 diagnostics::IfExpressionMissingThenBlockSub::AddThenBlock(
2709 cond_span.shrink_to_hi(),
2710 ),
2711 let_else_sub,
2712 });
2713 self.mk_block_err(cond_span.shrink_to_hi(), guar)
2714 }
2715 } else {
2716 let attrs = self.parse_outer_attributes()?; let maybe_fatarrow = self.token;
2718 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)) {
2719 self.parse_block()?
2720 } else if let Some(block) = recover_block_from_condition(self) {
2721 block
2722 } else {
2723 self.error_on_extra_if(&cond)?;
2724 self.parse_block().map_err(|mut err| {
2726 if self.prev_token == token::Semi
2727 && self.token == token::AndAnd
2728 && let maybe_let = self.look_ahead(1, |t| t.clone())
2729 && maybe_let.is_keyword(kw::Let)
2730 {
2731 err.span_suggestion_verbose(
2732 self.prev_token.span,
2733 "consider removing this semicolon to parse the `let` as part of the same chain",
2734 "",
2735 Applicability::MachineApplicable,
2736 ).span_note(
2737 self.token.span.to(maybe_let.span),
2738 "you likely meant to continue parsing the let-chain starting here",
2739 );
2740 } else {
2741 if self.prev_token == token::Semi
2742 && (self.token == token::OpenBrace || AssocOp::from_token(&self.token).is_some())
2743 {
2744 err.span_suggestion_verbose(
2745 self.prev_token.span,
2746 "remove this semicolon",
2747 "",
2748 Applicability::MaybeIncorrect,
2749 );
2750 }
2751
2752 if maybe_fatarrow == token::FatArrow {
2754 err.span_suggestion_verbose(
2755 maybe_fatarrow.span,
2756 "you might have meant to write a \"greater than or equal to\" comparison",
2757 ">=",
2758 Applicability::MaybeIncorrect,
2759 );
2760 }
2761 err.span_note(
2762 cond_span,
2763 "the `if` expression is missing a block after this condition",
2764 );
2765 }
2766 err
2767 })?
2768 };
2769 self.error_on_if_block_attrs(lo, false, block.span, attrs);
2770 block
2771 };
2772 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 };
2773 Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els)))
2774 }
2775
2776 pub fn parse_expr_cond(
2783 &mut self,
2784 let_chains_policy: LetChainsPolicy,
2785 ) -> PResult<'a, Box<Expr>> {
2786 let mut cond =
2787 self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET)?;
2788
2789 let mut checker = CondChecker::new(self, let_chains_policy);
2790 checker.visit_expr(&mut cond);
2791 Ok(if let Some(guar) = checker.found_incorrect_let_chain {
2792 self.mk_expr_err(cond.span, guar)
2793 } else {
2794 cond
2795 })
2796 }
2797
2798 fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
2800 let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
2801 let err = diagnostics::ExpectedExpressionFoundLet {
2802 span: self.token.span,
2803 reason: diagnostics::ForbiddenLetReason::OtherForbidden,
2804 missing_let: None,
2805 comparison: None,
2806 };
2807 if self.prev_token == token::Or {
2808 return Err(self.dcx().create_err(err));
2810 } else {
2811 Recovered::Yes(self.dcx().emit_err(err))
2812 }
2813 } else {
2814 Recovered::No
2815 };
2816 self.bump(); let lo = self.prev_token.span;
2818 let pat = self.parse_pat_no_top_guard(
2819 None,
2820 RecoverComma::Yes,
2821 RecoverColon::Yes,
2822 CommaRecoveryMode::LikelyTuple,
2823 )?;
2824 if self.token == token::EqEq {
2825 self.dcx().emit_err(diagnostics::ExpectedEqForLetExpr {
2826 span: self.token.span,
2827 sugg_span: self.token.span,
2828 });
2829 self.bump();
2830 } else {
2831 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq))?;
2832 }
2833 let expr = self.parse_expr_assoc(Bound::Excluded(prec_let_scrutinee_needs_par()))?;
2834 let span = lo.to(expr.span);
2835 Ok(self.mk_expr(span, ExprKind::Let(Box::new(pat), expr, span, recovered)))
2836 }
2837
2838 fn parse_expr_else(&mut self) -> PResult<'a, Box<Expr>> {
2840 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)) {
2843 self.parse_expr_if()?
2844 } else if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
2845 self.parse_simple_block()?
2846 } else {
2847 let snapshot = self.create_snapshot_for_diagnostic();
2848 let first_tok = super::token_descr(&self.token);
2849 let first_tok_span = self.token.span;
2850 match self.parse_expr() {
2851 Ok(cond)
2852 if self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace))
2887 && (classify::expr_requires_semi_to_be_stmt(&cond)
2888 || #[allow(non_exhaustive_omitted_patterns)] match cond.kind {
ExprKind::MacCall(..) => true,
_ => false,
}matches!(cond.kind, ExprKind::MacCall(..)))
2889 =>
2890 {
2891 self.dcx().emit_err(diagnostics::ExpectedElseBlock {
2892 first_tok_span,
2893 first_tok,
2894 else_span,
2895 condition_start: cond.span.shrink_to_lo(),
2896 });
2897 self.parse_if_after_cond(cond.span.shrink_to_lo(), cond)?
2898 }
2899 Err(e) => {
2900 e.cancel();
2901 self.restore_snapshot(snapshot);
2902 self.parse_simple_block()?
2903 },
2904 Ok(_) => {
2905 self.restore_snapshot(snapshot);
2906 self.parse_simple_block()?
2907 },
2908 }
2909 };
2910 self.error_on_if_block_attrs(else_span, true, expr.span, attrs);
2911 Ok(expr)
2912 }
2913
2914 fn error_on_if_block_attrs(
2915 &self,
2916 ctx_span: Span,
2917 is_ctx_else: bool,
2918 branch_span: Span,
2919 attrs: AttrWrapper,
2920 ) {
2921 if !attrs.is_empty()
2922 && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
2923 {
2924 let attributes = x0.span.until(branch_span);
2925 let last = xn.span;
2926 let ctx = if is_ctx_else { "else" } else { "if" };
2927 self.dcx().emit_err(diagnostics::OuterAttributeNotAllowedOnIfElse {
2928 last,
2929 branch_span,
2930 ctx_span,
2931 ctx: ctx.to_string(),
2932 attributes,
2933 });
2934 }
2935 }
2936
2937 fn error_on_extra_if(&mut self, cond: &Box<Expr>) -> PResult<'a, ()> {
2938 if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind
2939 && let BinOpKind::And = binop
2940 && let ExprKind::If(cond, ..) = &right.kind
2941 {
2942 Err(self.dcx().create_err(diagnostics::UnexpectedIfWithIf(
2943 binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()),
2944 )))
2945 } else {
2946 Ok(())
2947 }
2948 }
2949
2950 pub fn parse_for_head(&mut self) -> PResult<'a, (Pat, Box<Expr>)> {
2952 let begin_paren = if self.token == token::OpenParen {
2953 let start_span = self.token.span;
2957 let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2958 Some((start_span, left))
2959 } else {
2960 None
2961 };
2962 let pat = match (
2964 self.parse_pat_allow_top_guard(
2965 None,
2966 RecoverComma::Yes,
2967 RecoverColon::Yes,
2968 CommaRecoveryMode::LikelyTuple,
2969 ),
2970 begin_paren,
2971 ) {
2972 (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)) => {
2974 let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL) {
2977 Ok(expr) => expr,
2978 Err(expr_err) => {
2979 expr_err.cancel();
2982 return Err(err);
2983 }
2984 };
2985 return if self.token == token::CloseParen {
2986 let span = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[start_span, self.token.span]))vec![start_span, self.token.span];
2989 let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
2990 self.bump(); err.cancel();
2992 self.dcx().emit_err(diagnostics::ParenthesesInForHead {
2993 span,
2994 sugg: diagnostics::ParenthesesInForHeadSugg { left, right },
2998 });
2999 Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr))
3000 } else {
3001 Err(err) };
3003 }
3004 (Err(err), _) => return Err(err), };
3006 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)) {
3007 self.error_missing_in_for_loop();
3008 }
3009 self.check_for_for_in_in_typo(self.prev_token.span);
3010 let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
3011 Ok((pat, expr))
3012 }
3013
3014 fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3016 let is_await =
3017 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));
3018
3019 if is_await {
3020 self.psess.gated_spans.gate(sym::async_for_loop, self.prev_token.span);
3021 }
3022
3023 let kind = if is_await { ForLoopKind::ForAwait } else { ForLoopKind::For };
3024
3025 let (pat, expr) = self.parse_for_head()?;
3026 let pat = Box::new(pat);
3027 if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ExprKind::Block(..) => true,
_ => false,
}matches!(expr.kind, ExprKind::Block(..))
3029 && self.token.kind != token::OpenBrace
3030 && self.may_recover()
3031 {
3032 let guar = self.dcx().emit_err(diagnostics::MissingExpressionInForLoop {
3033 span: expr.span.shrink_to_lo(),
3034 });
3035 let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar));
3036 let block = self.mk_block(::thin_vec::ThinVec::new()thin_vec![], BlockCheckMode::Default, self.prev_token.span);
3037 return Ok(self.mk_expr(
3038 lo.to(self.prev_token.span),
3039 ExprKind::ForLoop(Box::new(ForLoop {
3040 pat,
3041 iter: err_expr,
3042 body: block,
3043 label: opt_label,
3044 kind,
3045 })),
3046 ));
3047 }
3048
3049 let (attrs, loop_block) = self.parse_inner_attrs_and_block(
3050 opt_label.is_none().then_some(lo),
3053 )?;
3054
3055 let kind = ExprKind::ForLoop(Box::new(ForLoop {
3056 pat,
3057 iter: expr,
3058 body: loop_block,
3059 label: opt_label,
3060 kind,
3061 }));
3062
3063 self.recover_loop_else("for", lo)?;
3064
3065 Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3066 }
3067
3068 fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> {
3070 if self.token.is_keyword(kw::Else) && self.may_recover() {
3071 let else_span = self.token.span;
3072 self.bump();
3073 let else_clause = self.parse_expr_else()?;
3074 self.dcx().emit_err(diagnostics::LoopElseNotSupported {
3075 span: else_span.to(else_clause.span),
3076 loop_kind,
3077 loop_kw,
3078 });
3079 }
3080 Ok(())
3081 }
3082
3083 fn error_missing_in_for_loop(&mut self) {
3084 let (span, sub) = if self.token.is_ident_named(sym::of) {
3085 let span = self.token.span;
3087 self.bump();
3088 (span, Some(diagnostics::MissingInInForLoopSub::InNotOf(span)))
3089 } else if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) {
3090 let span = self.prev_token.span;
3091 (span, Some(diagnostics::MissingInInForLoopSub::InNotEq(span)))
3092 } else {
3093 let span = self.prev_token.span.between(self.token.span);
3094 let sub = (!self.for_loop_head_has_in())
3095 .then_some(diagnostics::MissingInInForLoopSub::AddIn(span));
3096 (span, sub)
3097 };
3098
3099 self.dcx().emit_err(diagnostics::MissingInInForLoop { span, sub });
3100 }
3101
3102 fn for_loop_head_has_in(&self) -> bool {
3106 let mut dist = 0;
3107 loop {
3108 let (is_in, is_end) = self.look_ahead(dist, |t| {
3109 (t.is_keyword(kw::In), #[allow(non_exhaustive_omitted_patterns)] match t.kind {
token::OpenBrace | token::Eof => true,
_ => false,
}matches!(t.kind, token::OpenBrace | token::Eof))
3110 });
3111 if is_in {
3112 return true;
3113 }
3114 if is_end {
3115 return false;
3116 }
3117 dist += 1;
3118 }
3119 }
3120
3121 fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3123 let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
3124 let cond = self.parse_expr_cond(policy).map_err(|mut err| {
3125 err.span_label(lo, "while parsing the condition of this `while` expression");
3126 err
3127 })?;
3128 let (attrs, body) = self
3129 .parse_inner_attrs_and_block(
3130 opt_label.is_none().then_some(lo),
3133 )
3134 .map_err(|mut err| {
3135 err.span_label(lo, "while parsing the body of this `while` expression");
3136 err.span_label(cond.span, "this `while` condition successfully parsed");
3137 err
3138 })?;
3139
3140 self.recover_loop_else("while", lo)?;
3141
3142 Ok(self.mk_expr_with_attrs(
3143 lo.to(self.prev_token.span),
3144 ExprKind::While(cond, body, opt_label),
3145 attrs,
3146 ))
3147 }
3148
3149 fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, Box<Expr>> {
3151 let loop_span = self.prev_token.span;
3152 let (attrs, body) = self.parse_inner_attrs_and_block(
3153 opt_label.is_none().then_some(lo),
3156 )?;
3157 self.recover_loop_else("loop", lo)?;
3158 Ok(self.mk_expr_with_attrs(
3159 lo.to(self.prev_token.span),
3160 ExprKind::Loop(body, opt_label, loop_span),
3161 attrs,
3162 ))
3163 }
3164
3165 pub(crate) fn eat_label(&mut self) -> Option<Label> {
3166 if let Some((ident, is_raw)) = self.token.lifetime() {
3167 if is_raw == IdentIsRaw::No && ident.without_first_quote().is_reserved() {
3169 self.dcx().emit_err(diagnostics::KeywordLabel { span: ident.span });
3170 }
3171
3172 self.bump();
3173 Some(Label { ident })
3174 } else {
3175 None
3176 }
3177 }
3178
3179 fn parse_expr_match(&mut self) -> PResult<'a, Box<Expr>> {
3181 let match_span = self.prev_token.span;
3182 let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL)?;
3183
3184 self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
3185 }
3186
3187 fn parse_match_block(
3190 &mut self,
3191 lo: Span,
3192 match_span: Span,
3193 scrutinee: Box<Expr>,
3194 match_kind: MatchKind,
3195 ) -> PResult<'a, Box<Expr>> {
3196 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)) {
3197 if self.token == token::Semi {
3198 e.span_suggestion_short(
3199 match_span,
3200 "try removing this `match`",
3201 "",
3202 Applicability::MaybeIncorrect, );
3204 }
3205 if self.maybe_recover_unexpected_block_label(None) {
3206 e.cancel();
3207 self.bump();
3208 } else {
3209 return Err(e);
3210 }
3211 }
3212 let attrs = self.parse_inner_attributes()?;
3213
3214 let mut arms = ThinVec::new();
3215 while self.token != token::CloseBrace {
3216 match self.parse_arm() {
3217 Ok(arm) => arms.push(arm),
3218 Err(e) => {
3219 let guar = e.emit();
3221 self.recover_stmt();
3222 let span = lo.to(self.token.span);
3223 if self.token == token::CloseBrace {
3224 self.bump();
3225 }
3226 arms.push(Arm {
3228 attrs: Default::default(),
3229 pat: Box::new(self.mk_pat(span, ast::PatKind::Err(guar))),
3230 guard: None,
3231 body: Some(self.mk_expr_err(span, guar)),
3232 span,
3233 id: DUMMY_NODE_ID,
3234 is_placeholder: false,
3235 });
3236 return Ok(self.mk_expr_with_attrs(
3237 span,
3238 ExprKind::Match(scrutinee, arms, match_kind),
3239 attrs,
3240 ));
3241 }
3242 }
3243 }
3244 let hi = self.token.span;
3245 self.bump();
3246 Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
3247 }
3248
3249 fn parse_arm_body_missing_braces(
3251 &mut self,
3252 first_expr: &Box<Expr>,
3253 arrow_span: Span,
3254 ) -> Option<(Span, ErrorGuaranteed)> {
3255 if self.token != token::Semi {
3256 return None;
3257 }
3258 let start_snapshot = self.create_snapshot_for_diagnostic();
3259 let semi_sp = self.token.span;
3260 self.bump(); let mut stmts =
3262 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[self.mk_stmt(first_expr.span,
ast::StmtKind::Expr(first_expr.clone()))]))vec![self.mk_stmt(first_expr.span, ast::StmtKind::Expr(first_expr.clone()))];
3263 let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
3264 let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
3265
3266 let guar = this.dcx().emit_err(diagnostics::MatchArmBodyWithoutBraces {
3267 statements: span,
3268 arrow: arrow_span,
3269 num_statements: stmts.len(),
3270 sub: if stmts.len() > 1 {
3271 diagnostics::MatchArmBodyWithoutBracesSugg::AddBraces {
3272 left: span.shrink_to_lo(),
3273 right: span.shrink_to_hi(),
3274 num_statements: stmts.len(),
3275 }
3276 } else {
3277 diagnostics::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
3278 },
3279 });
3280 (span, guar)
3281 };
3282 loop {
3285 if self.token == token::CloseBrace {
3286 return Some(err(self, stmts));
3288 }
3289 if self.token == token::Comma {
3290 self.restore_snapshot(start_snapshot);
3291 return None;
3292 }
3293 let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
3294 match self.parse_pat_no_top_alt(None, None) {
3295 Ok(_pat) => {
3296 if self.token == token::FatArrow {
3297 self.restore_snapshot(pre_pat_snapshot);
3299 return Some(err(self, stmts));
3300 }
3301 }
3302 Err(err) => {
3303 err.cancel();
3304 }
3305 }
3306
3307 self.restore_snapshot(pre_pat_snapshot);
3308 match self.parse_stmt_without_recovery(true, ForceCollect::No, false) {
3309 Ok(stmt) => {
3311 stmts.push(stmt);
3312 }
3313 Err(stmt_err) => {
3316 stmt_err.cancel();
3317 self.restore_snapshot(start_snapshot);
3318 break;
3319 }
3320 }
3321 }
3322 None
3323 }
3324
3325 pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
3326 let attrs = self.parse_outer_attributes()?;
3327 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
3328 let lo = this.token.span;
3329 let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
3330 let pat = Box::new(pat);
3331
3332 let span_before_body = this.prev_token.span;
3333 let arm_body;
3334 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));
3335 let is_almost_fat_arrow =
3336 TokenKind::FatArrow.similar_tokens().contains(&this.token.kind);
3337
3338 let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
3341 || #[allow(non_exhaustive_omitted_patterns)] match this.token.kind {
token::Comma | token::CloseBrace => true,
_ => false,
}matches!(this.token.kind, token::Comma | token::CloseBrace);
3342
3343 let mut result = if armless {
3344 arm_body = None;
3346 let span = lo.to(this.prev_token.span);
3347 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| {
3348 if !pat.contains_never_pattern() {
3350 this.psess.gated_spans.gate(sym::never_patterns, span);
3351 }
3352 x
3353 })
3354 } else {
3355 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)) {
3356 if is_almost_fat_arrow {
3358 err.span_suggestion_verbose(
3359 this.token.span,
3360 "use a fat arrow to start a match arm",
3361 "=>",
3362 Applicability::MachineApplicable,
3363 );
3364 if #[allow(non_exhaustive_omitted_patterns)] match (&this.prev_token.kind,
&this.token.kind) {
(token::DotDotEq, token::Gt) => true,
_ => false,
}matches!(
3365 (&this.prev_token.kind, &this.token.kind),
3366 (token::DotDotEq, token::Gt)
3367 ) {
3368 err.delay_as_bug();
3371 } else {
3372 err.emit();
3373 }
3374 this.bump();
3375 } else {
3376 return Err(err);
3377 }
3378 }
3379 let arrow_span = this.prev_token.span;
3380 let arm_start_span = this.token.span;
3381
3382 let expr =
3383 this.parse_expr_res(Restrictions::STMT_EXPR).map_err(|mut err| {
3384 err.span_label(arrow_span, "while parsing the `match` arm starting here");
3385 err
3386 })?;
3387
3388 let require_comma =
3389 !classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
3390
3391 if !require_comma {
3392 arm_body = Some(expr);
3393 let _ = this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
3395 Ok(Recovered::No)
3396 } else if let Some((span, guar)) =
3397 this.parse_arm_body_missing_braces(&expr, arrow_span)
3398 {
3399 let body = this.mk_expr_err(span, guar);
3400 arm_body = Some(body);
3401 Ok(Recovered::Yes(guar))
3402 } else {
3403 let expr_span = expr.span;
3404 arm_body = Some(expr);
3405 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| {
3406 if this.token == token::FatArrow {
3407 let sm = this.psess.source_map();
3408 if let Ok(expr_lines) = sm.span_to_lines(expr_span)
3409 && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
3410 && expr_lines.lines.len() == 2
3411 {
3412 if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col {
3413 err.span_suggestion_short(
3425 arm_start_span.shrink_to_hi(),
3426 "missing a comma here to end this `match` arm",
3427 ",",
3428 Applicability::MachineApplicable,
3429 );
3430 } else if arm_start_lines.lines[0].end_col + rustc_span::CharPos(1)
3431 == expr_lines.lines[0].end_col
3432 {
3433 let comma_span = arm_start_span
3435 .shrink_to_hi()
3436 .with_hi(arm_start_span.hi() + rustc_span::BytePos(1));
3437 if let Ok(res) = sm.span_to_snippet(comma_span)
3438 && (res == "." || res == "/")
3439 {
3440 err.span_suggestion_short(
3441 comma_span,
3442 "you might have meant to write a `,` to end this `match` arm",
3443 ",",
3444 Applicability::MachineApplicable,
3445 );
3446 }
3447 }
3448 }
3449 } else {
3450 err.span_label(
3451 arrow_span,
3452 "while parsing the `match` arm starting here",
3453 );
3454 }
3455 err
3456 })
3457 }
3458 };
3459
3460 let hi_span = arm_body.as_ref().map_or(span_before_body, |body| body.span);
3461 let arm_span = lo.to(hi_span);
3462
3463 let recover_missing_comma = arm_body.is_some() || pat.could_be_never_pattern();
3477 if recover_missing_comma {
3478 result = result.or_else(|err| {
3479 let mut snapshot = this.create_snapshot_for_diagnostic();
3484 let pattern_follows = snapshot
3485 .parse_pat_no_top_guard(
3486 None,
3487 RecoverComma::Yes,
3488 RecoverColon::Yes,
3489 CommaRecoveryMode::EitherTupleOrPipe,
3490 )
3491 .map_err(|err| err.cancel())
3492 .is_ok();
3493 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)) {
3494 err.cancel();
3495 let guar = this.dcx().emit_err(diagnostics::MissingCommaAfterMatchArm {
3496 span: arm_span.shrink_to_hi(),
3497 });
3498 return Ok(Recovered::Yes(guar));
3499 }
3500 Err(err)
3501 });
3502 }
3503 result?;
3504
3505 Ok((
3506 ast::Arm {
3507 attrs,
3508 pat,
3509 guard,
3510 body: arm_body,
3511 span: arm_span,
3512 id: DUMMY_NODE_ID,
3513 is_placeholder: false,
3514 },
3515 Trailing::No,
3516 UsePreAttrPos::No,
3517 ))
3518 })
3519 }
3520
3521 pub(crate) fn eat_metavar_guard(&mut self) -> Option<Box<Guard>> {
3522 self.eat_metavar_seq(MetaVarKind::Guard, |this| {
3523 this.expect_match_arm_guard(ForceCollect::Yes)
3524 })
3525 }
3526
3527 fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Guard>>> {
3528 if let Some(guard) = self.eat_metavar_guard() {
3529 return Ok(Some(guard));
3530 }
3531
3532 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)) {
3533 return Ok(None);
3535 }
3536 self.expect_match_arm_guard_cond(ForceCollect::No).map(Some)
3537 }
3538
3539 pub(crate) fn expect_match_arm_guard(
3540 &mut self,
3541 force_collect: ForceCollect,
3542 ) -> PResult<'a, Box<Guard>> {
3543 if let Some(guard) = self.eat_metavar_guard() {
3544 return Ok(guard);
3545 }
3546
3547 self.expect_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::If,
token_type: crate::parser::token_type::TokenType::KwIf,
}exp!(If))?;
3548 self.expect_match_arm_guard_cond(force_collect)
3549 }
3550
3551 fn expect_match_arm_guard_cond(
3552 &mut self,
3553 force_collect: ForceCollect,
3554 ) -> PResult<'a, Box<Guard>> {
3555 let leading_if_span = self.prev_token.span;
3556
3557 let mut cond = self.parse_match_guard_condition(force_collect)?;
3558 let cond_span = cond.span;
3559
3560 CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
3561
3562 let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) };
3563 Ok(Box::new(guard))
3564 }
3565
3566 fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Guard>>)> {
3567 if self.token == token::OpenParen {
3568 let left = self.token.span;
3569 let pat = self.parse_pat_no_top_guard(
3570 None,
3571 RecoverComma::Yes,
3572 RecoverColon::Yes,
3573 CommaRecoveryMode::EitherTupleOrPipe,
3574 )?;
3575 if let ast::PatKind::Paren(subpat) = &pat.kind
3576 && let ast::PatKind::Guard(..) = &subpat.kind
3577 {
3578 let span = pat.span;
3581 let ast::PatKind::Paren(subpat) = pat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3582 let ast::PatKind::Guard(_, mut guard) = subpat.kind else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
3583 self.psess.gated_spans.ungate_last(sym::guard_patterns, guard.span());
3584 let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
3585 checker.visit_expr(&mut guard.cond);
3586
3587 let right = self.prev_token.span;
3588 self.dcx().emit_err(diagnostics::ParenthesesInMatchPat {
3589 span: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[left, right]))vec![left, right],
3590 sugg: diagnostics::ParenthesesInMatchPatSugg { left, right },
3591 });
3592
3593 if let Some(guar) = checker.found_incorrect_let_chain {
3594 guard.cond = *self.mk_expr_err(guard.span(), guar);
3595 }
3596 Ok((self.mk_pat(span, ast::PatKind::Wild), Some(guard)))
3597 } else {
3598 Ok((pat, self.parse_match_arm_guard()?))
3599 }
3600 } else {
3601 let pat = self.parse_pat_no_top_guard(
3603 None,
3604 RecoverComma::Yes,
3605 RecoverColon::Yes,
3606 CommaRecoveryMode::EitherTupleOrPipe,
3607 )?;
3608 Ok((pat, self.parse_match_arm_guard()?))
3609 }
3610 }
3611
3612 fn parse_match_guard_condition(
3613 &mut self,
3614 force_collect: ForceCollect,
3615 ) -> PResult<'a, Box<Expr>> {
3616 let attrs = self.parse_outer_attributes()?;
3617 let expr = self.collect_tokens(
3618 None,
3619 AttrWrapper::empty(),
3620 force_collect,
3621 |this, _empty_attrs| {
3622 match this.parse_expr_res_after_attrs(
3623 Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD,
3624 attrs,
3625 ) {
3626 Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)),
3627 Err(mut err) => {
3628 if this.prev_token == token::OpenBrace {
3629 let sugg_sp = this.prev_token.span.shrink_to_lo();
3630 this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
3633 let msg =
3634 "you might have meant to start a match arm after the match guard";
3635 if this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)) {
3636 let applicability = if this.token != token::FatArrow {
3637 Applicability::MachineApplicable
3642 } else {
3643 Applicability::MaybeIncorrect
3644 };
3645 err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
3646 }
3647 }
3648 Err(err)
3649 }
3650 }
3651 },
3652 )?;
3653 Ok(expr)
3654 }
3655
3656 pub(crate) fn is_builtin(&self) -> bool {
3657 self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
3658 }
3659
3660 fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, Box<Expr>> {
3662 let annotation =
3663 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 };
3664
3665 let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3666 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)) {
3667 Err(self.dcx().create_err(diagnostics::CatchAfterTry { span: self.prev_token.span }))
3668 } else {
3669 let span = span_lo.to(body.span);
3670 let gate_sym =
3671 if annotation.is_none() { sym::try_blocks } else { sym::try_blocks_heterogeneous };
3672 self.psess.gated_spans.gate(gate_sym, span);
3673 Ok(self.mk_expr_with_attrs(span, ExprKind::TryBlock(body, annotation), attrs))
3674 }
3675 }
3676
3677 fn is_do_catch_block(&self) -> bool {
3678 self.token.is_keyword(kw::Do)
3679 && self.is_keyword_ahead(1, &[kw::Catch])
3680 && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
3681 && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3682 }
3683
3684 fn is_do_yeet(&self) -> bool {
3685 self.token.is_keyword(kw::Do) && self.is_keyword_ahead(1, &[kw::Yeet])
3686 }
3687
3688 fn is_try_block(&self) -> bool {
3689 self.token.is_keyword(kw::Try)
3690 && self.look_ahead(1, |t| {
3691 *t == token::OpenBrace || t.is_metavar_block() || t.is_keyword(sym::bikeshed)
3692 })
3693 && self.token_uninterpolated_span().at_least_rust_2018()
3694 }
3695
3696 fn parse_gen_block(&mut self) -> PResult<'a, Box<Expr>> {
3698 let lo = self.token.span;
3699 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)) {
3700 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Gen,
token_type: crate::parser::token_type::TokenType::KwGen,
}exp!(Gen)) { CoroutineKind::AsyncGen } else { CoroutineKind::Async }
3701 } else {
3702 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)));
3703 CoroutineKind::Gen
3704 };
3705 if kind.is_gen() {
3706 self.psess.gated_spans.gate(sym::gen_blocks, lo.to(self.prev_token.span));
3707 }
3708 let capture_clause = self.parse_capture_clause()?;
3709 let decl_span = lo.to(self.prev_token.span);
3710 let (attrs, body) = self.parse_inner_attrs_and_block(None)?;
3711 let kind = ExprKind::Gen(capture_clause, body, kind, decl_span);
3712 Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs))
3713 }
3714
3715 fn is_gen_block(&self, kw: Symbol, lookahead: usize) -> bool {
3716 self.is_keyword_ahead(lookahead, &[kw])
3717 && ((
3718 self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
3720 && self.look_ahead(lookahead + 2, |t| {
3721 *t == token::OpenBrace || t.is_metavar_block()
3722 })
3723 ) || (
3724 self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
3726 ))
3727 }
3728
3729 pub(super) fn is_async_gen_block(&self) -> bool {
3730 self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1)
3731 }
3732
3733 fn is_likely_struct_lit(&self) -> bool {
3734 self.look_ahead(1, |t| t.is_ident())
3736 && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
3737 }
3738
3739 fn maybe_parse_struct_expr(
3740 &mut self,
3741 qself: &Option<Box<ast::QSelf>>,
3742 path: &ast::Path,
3743 ) -> Option<PResult<'a, Box<Expr>>> {
3744 let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
3745 match (struct_allowed, self.is_likely_struct_lit()) {
3746 (false, false) => None,
3751 (true, _) => {
3752 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)) {
3755 return Some(Err(err));
3756 }
3757 Some(self.parse_expr_struct(qself.clone(), path.clone(), true))
3758 }
3759 (false, true) => {
3760 let snapshot = self.create_snapshot_for_diagnostic();
3764 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)) {
3765 return Some(Err(err));
3766 }
3767 match self.parse_expr_struct(qself.clone(), path.clone(), false) {
3768 Ok(expr) => {
3769 self.dcx().emit_err(diagnostics::StructLiteralNotAllowedHere {
3771 span: expr.span,
3772 sub: diagnostics::StructLiteralNotAllowedHereSugg {
3773 left: path.span.shrink_to_lo(),
3774 right: expr.span.shrink_to_hi(),
3775 },
3776 });
3777 Some(Ok(expr))
3778 }
3779 Err(err) => {
3780 err.cancel();
3783 self.restore_snapshot(snapshot);
3784 None
3785 }
3786 }
3787 }
3788 }
3789 }
3790
3791 fn maybe_recover_bad_struct_literal_path(
3792 &mut self,
3793 is_underscore_entry_point: bool,
3794 ) -> PResult<'a, Option<Box<Expr>>> {
3795 if self.may_recover()
3796 && self.check_noexpect(&token::OpenBrace)
3797 && (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
3798 && self.is_likely_struct_lit())
3799 {
3800 let span = if is_underscore_entry_point {
3801 self.prev_token.span
3802 } else {
3803 self.token.span.shrink_to_lo()
3804 };
3805
3806 self.bump(); let expr = self.parse_expr_struct(
3808 None,
3809 Path::from_ident(Ident::new(kw::Underscore, span)),
3810 false,
3811 )?;
3812
3813 let guar = if is_underscore_entry_point {
3814 self.dcx().create_err(diagnostics::StructLiteralPlaceholderPath { span }).emit()
3815 } else {
3816 self.dcx()
3817 .create_err(diagnostics::StructLiteralWithoutPathLate {
3818 span: expr.span,
3819 suggestion_span: expr.span.shrink_to_lo(),
3820 })
3821 .emit()
3822 };
3823
3824 Ok(Some(self.mk_expr_err(expr.span, guar)))
3825 } else {
3826 Ok(None)
3827 }
3828 }
3829
3830 pub(super) fn parse_struct_fields(
3831 &mut self,
3832 pth: ast::Path,
3833 recover: bool,
3834 close: ExpTokenPair,
3835 ) -> PResult<
3836 'a,
3837 (
3838 ThinVec<ExprField>,
3839 ast::StructRest,
3840 Option<ErrorGuaranteed>, ),
3842 > {
3843 let mut fields = ThinVec::new();
3844 let mut base = ast::StructRest::None;
3845 let mut recovered_async = None;
3846 let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);
3847
3848 let async_block_err = |e: &mut Diag<'_>, span: Span| {
3849 diagnostics::AsyncBlockIn2015 { span }.add_to_diag(e);
3850 diagnostics::HelpUseLatestEdition::new().add_to_diag(e);
3851 };
3852
3853 while self.token != close.tok {
3854 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) {
3855 let exp_span = self.prev_token.span;
3856 if self.check(close) {
3858 base = ast::StructRest::Rest(self.prev_token.span);
3859 break;
3860 }
3861 match self.parse_expr() {
3862 Ok(e) => base = ast::StructRest::Base(e),
3863 Err(e) if recover => {
3864 e.emit();
3865 self.recover_stmt();
3866 }
3867 Err(e) => return Err(e),
3868 }
3869 self.recover_struct_comma_after_dotdot(exp_span);
3870 break;
3871 }
3872
3873 let peek = self
3875 .token
3876 .non_reserved_ident()
3877 .filter(|_| self.look_ahead(1, |&tok| tok == token::Colon));
3878
3879 let field_ident = |this: &Self, guar: ErrorGuaranteed| {
3881 peek.map(|ident| {
3882 let span = ident.span;
3883 ExprField {
3884 ident,
3885 span,
3886 expr: this.mk_expr_err(span, guar),
3887 is_shorthand: false,
3888 attrs: AttrVec::new(),
3889 id: DUMMY_NODE_ID,
3890 is_placeholder: false,
3891 }
3892 })
3893 };
3894
3895 let parsed_field = match self.parse_expr_field() {
3896 Ok(f) => Ok(f),
3897 Err(mut e) => {
3898 if pth == kw::Async {
3899 async_block_err(&mut e, pth.span);
3900 } else {
3901 e.span_label(pth.span, "while parsing this struct");
3902 }
3903
3904 if let Some((ident, _)) = self.token.ident()
3905 && !self.token.is_reserved_ident()
3906 && self.look_ahead(1, |t| {
3907 AssocOp::from_token(t).is_some()
3908 || #[allow(non_exhaustive_omitted_patterns)] match t.kind {
token::OpenParen | token::OpenBracket | token::OpenBrace => true,
_ => false,
}matches!(
3909 t.kind,
3910 token::OpenParen | token::OpenBracket | token::OpenBrace
3911 )
3912 || *t == token::Dot
3913 })
3914 {
3915 e.span_suggestion_verbose(
3918 self.token.span.shrink_to_lo(),
3919 "try naming a field",
3920 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: ", ident))
})format!("{ident}: ",),
3921 Applicability::MaybeIncorrect,
3922 );
3923 }
3924 if in_if_guard && close.token_type == TokenType::CloseBrace {
3925 return Err(e);
3926 }
3927
3928 if !recover {
3929 return Err(e);
3930 }
3931
3932 let guar = e.emit();
3933 if pth == kw::Async {
3934 recovered_async = Some(guar);
3935 }
3936
3937 base = ast::StructRest::NoneWithError(guar);
3945
3946 if self.token != token::Comma {
3950 self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
3951 if self.token != token::Comma {
3952 break;
3953 }
3954 }
3955
3956 Err(guar)
3957 }
3958 };
3959
3960 let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand);
3961 self.check_or_expected(!is_shorthand, TokenType::Colon);
3964
3965 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]) {
3966 Ok(_) => {
3967 if let Ok(f) = parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar))
3968 {
3969 fields.push(f);
3971 }
3972 }
3973 Err(mut e) => {
3974 if pth == kw::Async {
3975 async_block_err(&mut e, pth.span);
3976 } else {
3977 e.span_label(pth.span, "while parsing this struct");
3978 if peek.is_some() {
3979 e.span_suggestion(
3980 self.prev_token.span.shrink_to_hi(),
3981 "try adding a comma",
3982 ",",
3983 Applicability::MachineApplicable,
3984 );
3985 }
3986 }
3987 if !recover {
3988 return Err(e);
3989 }
3990 let guar = e.emit();
3991 if pth == kw::Async {
3992 recovered_async = Some(guar);
3993 } else if let Some(f) = field_ident(self, guar) {
3994 fields.push(f);
3995 }
3996
3997 base = ast::StructRest::NoneWithError(guar);
3999
4000 self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
4001 let _ = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
4002 }
4003 }
4004 }
4005 Ok((fields, base, recovered_async))
4006 }
4007
4008 pub(super) fn parse_expr_struct(
4010 &mut self,
4011 qself: Option<Box<ast::QSelf>>,
4012 pth: ast::Path,
4013 recover: bool,
4014 ) -> PResult<'a, Box<Expr>> {
4015 let lo = pth.span;
4016 let (fields, base, recovered_async) =
4017 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))?;
4018 let span = lo.to(self.token.span);
4019 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace))?;
4020 let expr = if let Some(guar) = recovered_async {
4021 ExprKind::Err(guar)
4022 } else {
4023 ExprKind::Struct(Box::new(ast::StructExpr { qself, path: pth, fields, rest: base }))
4024 };
4025 Ok(self.mk_expr(span, expr))
4026 }
4027
4028 fn recover_struct_comma_after_dotdot(&mut self, span: Span) {
4029 if self.token != token::Comma {
4030 return;
4031 }
4032 self.dcx().emit_err(diagnostics::CommaAfterBaseStruct {
4033 span: span.to(self.prev_token.span),
4034 comma: self.token.span,
4035 });
4036 self.recover_stmt();
4037 }
4038
4039 fn recover_struct_field_dots(&mut self, close: &TokenKind) -> bool {
4040 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)) {
4041 let span = self.prev_token.span;
4043 self.dcx().emit_err(diagnostics::MissingDotDot { token_span: span, sugg_span: span });
4044 return true;
4045 }
4046 false
4047 }
4048
4049 fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
4051 let label = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}", ident.name))
})format!("'{}", ident.name);
4054 let ident = Ident::new(Symbol::intern(&label), ident.span);
4055
4056 self.dcx().emit_err(diagnostics::ExpectedLabelFoundIdent {
4057 span: ident.span,
4058 start: ident.span.shrink_to_lo(),
4059 });
4060
4061 Label { ident }
4062 }
4063
4064 fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
4066 let attrs = self.parse_outer_attributes()?;
4067 self.recover_vcs_conflict_marker();
4068 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4069 let lo = this.token.span;
4070
4071 let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
4073 let is_wrong = this.token.is_non_reserved_ident()
4075 && !this.look_ahead(1, |t| {
4076 t == &token::Colon
4077 || t == &token::Eq
4078 || t == &token::Comma
4079 || t == &token::CloseBrace
4080 || t == &token::CloseParen
4081 });
4082 if is_wrong {
4083 return Err(this.dcx().create_err(diagnostics::ExpectedStructField {
4084 span: this.look_ahead(1, |t| t.span),
4085 ident_span: this.token.span,
4086 token: pprust::token_to_string(&this.look_ahead(1, |t| *t)),
4087 }));
4088 }
4089 let (ident, expr) = if is_shorthand {
4090 let ident = this.parse_ident_common(false)?;
4092 let path = ast::Path::from_ident(ident);
4093 (ident, this.mk_expr(ident.span, ExprKind::Path(None, path)))
4094 } else {
4095 let ident = this.parse_field_name()?;
4096 this.error_on_eq_field_init(ident);
4097 this.bump(); (ident, this.parse_expr()?)
4099 };
4100
4101 Ok((
4102 ast::ExprField {
4103 ident,
4104 span: lo.to(expr.span),
4105 expr,
4106 is_shorthand,
4107 attrs,
4108 id: DUMMY_NODE_ID,
4109 is_placeholder: false,
4110 },
4111 Trailing::from(this.token == token::Comma),
4112 UsePreAttrPos::No,
4113 ))
4114 })
4115 }
4116
4117 fn error_on_eq_field_init(&self, field_name: Ident) {
4120 if self.token != token::Eq {
4121 return;
4122 }
4123
4124 self.dcx().emit_err(diagnostics::EqFieldInit {
4125 span: self.token.span,
4126 eq: field_name.span.shrink_to_hi().to(self.token.span),
4127 });
4128 }
4129
4130 fn err_dotdotdot_syntax(&self, span: Span) {
4131 self.dcx().emit_err(diagnostics::DotDotDot { span });
4132 }
4133
4134 fn err_larrow_operator(&self, span: Span) {
4135 self.dcx().emit_err(diagnostics::LeftArrowOperator { span });
4136 }
4137
4138 fn mk_assign_op(&self, assign_op: AssignOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
4139 ExprKind::AssignOp(assign_op, lhs, rhs)
4140 }
4141
4142 fn mk_range(
4143 &mut self,
4144 start: Option<Box<Expr>>,
4145 end: Option<Box<Expr>>,
4146 limits: RangeLimits,
4147 ) -> ExprKind {
4148 if end.is_none() && limits == RangeLimits::Closed {
4149 let guar = self.inclusive_range_with_incorrect_end();
4150 ExprKind::Err(guar)
4151 } else {
4152 ExprKind::Range(start, end, limits)
4153 }
4154 }
4155
4156 fn mk_unary(&self, unop: UnOp, expr: Box<Expr>) -> ExprKind {
4157 ExprKind::Unary(unop, expr)
4158 }
4159
4160 fn mk_binary(&self, binop: BinOp, lhs: Box<Expr>, rhs: Box<Expr>) -> ExprKind {
4161 ExprKind::Binary(binop, lhs, rhs)
4162 }
4163
4164 fn mk_index(&self, expr: Box<Expr>, idx: Box<Expr>, brackets_span: Span) -> ExprKind {
4165 ExprKind::Index(expr, idx, brackets_span)
4166 }
4167
4168 fn mk_call(&self, f: Box<Expr>, args: ThinVec<Box<Expr>>) -> ExprKind {
4169 ExprKind::Call(f, args)
4170 }
4171
4172 fn mk_await_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4173 let span = lo.to(self.prev_token.span);
4174 let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
4175 self.recover_from_await_method_call();
4176 await_expr
4177 }
4178
4179 fn mk_use_expr(&mut self, self_arg: Box<Expr>, lo: Span) -> Box<Expr> {
4180 let span = lo.to(self.prev_token.span);
4181 let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span));
4182 self.recover_from_use();
4183 use_expr
4184 }
4185
4186 pub(crate) fn mk_expr_with_attrs(
4187 &self,
4188 span: Span,
4189 kind: ExprKind,
4190 attrs: AttrVec,
4191 ) -> Box<Expr> {
4192 Box::new(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None })
4193 }
4194
4195 pub(crate) fn mk_expr(&self, span: Span, kind: ExprKind) -> Box<Expr> {
4196 self.mk_expr_with_attrs(span, kind, AttrVec::new())
4197 }
4198
4199 pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Expr> {
4200 self.mk_expr(span, ExprKind::Err(guar))
4201 }
4202
4203 pub(crate) fn mk_unit_expr(&self, span: Span) -> Box<Expr> {
4204 self.mk_expr(span, ExprKind::Tup(Default::default()))
4205 }
4206
4207 pub(crate) fn mk_closure_expr(&self, span: Span, body: Box<Expr>) -> Box<Expr> {
4208 self.mk_expr(
4209 span,
4210 ast::ExprKind::Closure(Box::new(ast::Closure {
4211 binder: rustc_ast::ClosureBinder::NotPresent,
4212 constness: rustc_ast::Const::No,
4213 movability: rustc_ast::Movability::Movable,
4214 capture_clause: rustc_ast::CaptureBy::Ref,
4215 coroutine_marker: None,
4216 fn_decl: Box::new(rustc_ast::FnDecl {
4217 inputs: Default::default(),
4218 output: rustc_ast::FnRetTy::Default(span),
4219 }),
4220 fn_arg_span: span,
4221 fn_decl_span: span,
4222 body,
4223 })),
4224 )
4225 }
4226
4227 fn mk_expr_sp(&self, lhs: &Box<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span {
4230 lhs.attrs
4231 .iter()
4232 .find(|a| a.style == AttrStyle::Outer)
4233 .map_or(lhs_span, |a| a.span)
4234 .to(op_span)
4235 .to(rhs_span)
4236 }
4237
4238 fn collect_tokens_for_expr(
4239 &mut self,
4240 attrs: AttrWrapper,
4241 f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, Box<Expr>>,
4242 ) -> PResult<'a, Box<Expr>> {
4243 self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
4244 let res = f(this, attrs)?;
4245 let trailing = Trailing::from(
4246 this.restrictions.contains(Restrictions::STMT_EXPR)
4247 && this.token == token::Semi
4248 || this.token == token::Comma,
4252 );
4253 Ok((res, trailing, UsePreAttrPos::No))
4254 })
4255 }
4256}
4257
4258pub(crate) fn could_be_unclosed_char_literal(ident: Ident) -> bool {
4261 ident.name.as_str().starts_with('\'')
4262 && unescape_char(ident.without_first_quote().name.as_str()).is_ok()
4263}
4264
4265pub enum LetChainsPolicy {
4268 AlwaysAllowed,
4269 EditionDependent { current_edition: Edition },
4270}
4271
4272struct CondChecker<'a> {
4282 parser: &'a Parser<'a>,
4283 let_chains_policy: LetChainsPolicy,
4284 depth: u32,
4285 forbid_let_reason: Option<diagnostics::ForbiddenLetReason>,
4286 missing_let: Option<diagnostics::MaybeMissingLet>,
4287 comparison: Option<diagnostics::MaybeComparison>,
4288 found_incorrect_let_chain: Option<ErrorGuaranteed>,
4289}
4290
4291impl<'a> CondChecker<'a> {
4292 fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
4293 CondChecker {
4294 parser,
4295 forbid_let_reason: None,
4296 missing_let: None,
4297 comparison: None,
4298 let_chains_policy,
4299 found_incorrect_let_chain: None,
4300 depth: 0,
4301 }
4302 }
4303}
4304
4305impl MutVisitor for CondChecker<'_> {
4306 fn visit_expr(&mut self, e: &mut Expr) {
4307 self.depth += 1;
4308
4309 let span = e.span;
4310 match e.kind {
4311 ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
4312 if let Some(reason) = self.forbid_let_reason {
4313 let error = match reason {
4314 diagnostics::ForbiddenLetReason::NotSupportedOr(or_span) => {
4315 self.parser.dcx().emit_err(diagnostics::OrInLetChain { span: or_span })
4316 }
4317 _ => {
4318 let guar = self.parser.dcx().emit_err(
4319 diagnostics::ExpectedExpressionFoundLet {
4320 span,
4321 reason,
4322 missing_let: self.missing_let,
4323 comparison: self.comparison,
4324 },
4325 );
4326 if let Some(_) = self.missing_let {
4327 self.found_incorrect_let_chain = Some(guar);
4328 }
4329 guar
4330 }
4331 };
4332 *recovered = Recovered::Yes(error);
4333 } else if self.depth > 1 {
4334 match self.let_chains_policy {
4336 LetChainsPolicy::AlwaysAllowed => (),
4337 LetChainsPolicy::EditionDependent { current_edition } => {
4338 if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4339 self.parser.dcx().emit_err(diagnostics::LetChainPre2024 { span });
4340 }
4341 }
4342 }
4343 }
4344 }
4345 ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
4346 mut_visit::walk_expr(self, e);
4347 }
4348 ExprKind::Binary(Spanned { node: BinOpKind::Or, span: or_span }, _, _)
4349 if let None | Some(diagnostics::ForbiddenLetReason::NotSupportedOr(_)) =
4350 self.forbid_let_reason =>
4351 {
4352 let forbid_let_reason = self.forbid_let_reason;
4353 self.forbid_let_reason =
4354 Some(diagnostics::ForbiddenLetReason::NotSupportedOr(or_span));
4355 mut_visit::walk_expr(self, e);
4356 self.forbid_let_reason = forbid_let_reason;
4357 }
4358 ExprKind::Paren(ref inner)
4359 if let None | Some(diagnostics::ForbiddenLetReason::NotSupportedParentheses(_)) =
4360 self.forbid_let_reason =>
4361 {
4362 let forbid_let_reason = self.forbid_let_reason;
4363 self.forbid_let_reason =
4364 Some(diagnostics::ForbiddenLetReason::NotSupportedParentheses(inner.span));
4365 mut_visit::walk_expr(self, e);
4366 self.forbid_let_reason = forbid_let_reason;
4367 }
4368 ExprKind::Assign(ref lhs, ref rhs, span) => {
4369 if let ExprKind::Call(_, _) = &lhs.kind {
4370 fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
4371 fn inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
4372 match &e.kind {
4373 ExprKind::Binary(_, lhs, _) => inner(lhs, depth + 1),
4374 ExprKind::Path(_, path) => Some((depth, path)),
4375 _ => None,
4376 }
4377 }
4378
4379 inner(e, 0)
4380 }
4381
4382 if let Some((depth, path)) = get_path_from_rhs(rhs) {
4383 fn find_let_some(expr: &Expr) -> Option<&Expr> {
4386 match &expr.kind {
4387 ExprKind::Let(..) => Some(expr),
4388
4389 ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => {
4390 find_let_some(lhs).or_else(|| find_let_some(rhs))
4391 }
4392
4393 _ => None,
4394 }
4395 }
4396
4397 let expr_span = lhs.span.to(path.span);
4398
4399 if let Some(later_rhs) = find_let_some(rhs)
4400 && depth > 0
4401 {
4402 let guar =
4403 self.parser.dcx().emit_err(diagnostics::LetChainMissingLet {
4404 span: lhs.span,
4405 label_span: expr_span,
4406 rhs_span: later_rhs.span,
4407 sug_span: lhs.span.shrink_to_lo(),
4408 });
4409
4410 self.found_incorrect_let_chain = Some(guar);
4411 }
4412 }
4413 }
4414
4415 let forbid_let_reason = self.forbid_let_reason;
4416 self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4417 let missing_let = self.missing_let;
4418 if let ExprKind::Binary(_, _, rhs) = &lhs.kind
4419 && let ExprKind::Path(_, _)
4420 | ExprKind::Struct(_)
4421 | ExprKind::Call(_, _)
4422 | ExprKind::Array(_) = rhs.kind
4423 {
4424 self.missing_let =
4425 Some(diagnostics::MaybeMissingLet { span: rhs.span.shrink_to_lo() });
4426 }
4427 let comparison = self.comparison;
4428 self.comparison = Some(diagnostics::MaybeComparison { span: span.shrink_to_hi() });
4429 mut_visit::walk_expr(self, e);
4430 self.forbid_let_reason = forbid_let_reason;
4431 self.missing_let = missing_let;
4432 self.comparison = comparison;
4433 }
4434 ExprKind::Unary(_, _)
4435 | ExprKind::Await(_, _)
4436 | ExprKind::Move(_, _)
4437 | ExprKind::Use(_, _)
4438 | ExprKind::AssignOp(_, _, _)
4439 | ExprKind::Range(_, _, _)
4440 | ExprKind::Try(_)
4441 | ExprKind::AddrOf(_, _, _)
4442 | ExprKind::Binary(_, _, _)
4443 | ExprKind::Field(_, _)
4444 | ExprKind::Index(_, _, _)
4445 | ExprKind::Call(_, _)
4446 | ExprKind::MethodCall(_)
4447 | ExprKind::Tup(_)
4448 | ExprKind::Paren(_) => {
4449 let forbid_let_reason = self.forbid_let_reason;
4450 self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4451 mut_visit::walk_expr(self, e);
4452 self.forbid_let_reason = forbid_let_reason;
4453 }
4454 ExprKind::Cast(ref mut op, _)
4455 | ExprKind::Type(ref mut op, _)
4456 | ExprKind::UnsafeBinderCast(_, ref mut op, _) => {
4457 let forbid_let_reason = self.forbid_let_reason;
4458 self.forbid_let_reason = Some(diagnostics::ForbiddenLetReason::OtherForbidden);
4459 self.visit_expr(op);
4460 self.forbid_let_reason = forbid_let_reason;
4461 }
4462 ExprKind::Let(_, _, _, Recovered::Yes(_))
4463 | ExprKind::Array(_)
4464 | ExprKind::ConstBlock(_)
4465 | ExprKind::Lit(_)
4466 | ExprKind::If(_, _, _)
4467 | ExprKind::While(_, _, _)
4468 | ExprKind::ForLoop { .. }
4469 | ExprKind::Loop(_, _, _)
4470 | ExprKind::Match(_, _, _)
4471 | ExprKind::Closure(_)
4472 | ExprKind::Block(_, _)
4473 | ExprKind::Gen(_, _, _, _)
4474 | ExprKind::TryBlock(_, _)
4475 | ExprKind::Underscore
4476 | ExprKind::Path(_, _)
4477 | ExprKind::Break(_, _)
4478 | ExprKind::Continue(_)
4479 | ExprKind::Ret(_)
4480 | ExprKind::InlineAsm(_)
4481 | ExprKind::OffsetOf(_, _)
4482 | ExprKind::MacCall(_)
4483 | ExprKind::Struct(_)
4484 | ExprKind::Repeat(_, _)
4485 | ExprKind::Yield(_)
4486 | ExprKind::Yeet(_)
4487 | ExprKind::Become(_)
4488 | ExprKind::IncludedBytes(_)
4489 | ExprKind::FormatArgs(_)
4490 | ExprKind::Err(_)
4491 | ExprKind::DirectConstArg(_)
4492 | ExprKind::Dummy => {
4493 }
4495 }
4496 self.depth -= 1;
4497 }
4498}