1 use super::diagnostics
::SnapshotParser
;
2 use super::pat
::{CommaRecoveryMode, RecoverColon, RecoverComma, PARAM_EXPECTED}
;
3 use super::ty
::{AllowPlus, RecoverQPath, RecoverReturnSign}
;
5 AttrWrapper
, BlockMode
, ClosureSpans
, ForceCollect
, Parser
, PathStyle
, Restrictions
,
6 SemiColonMode
, SeqSep
, TokenExpectType
, TokenType
, TrailingToken
,
8 use crate::maybe_recover_from_interpolated_ty_qpath
;
11 use rustc_ast
::ptr
::P
;
12 use rustc_ast
::token
::{self, Delimiter, Token, TokenKind}
;
13 use rustc_ast
::tokenstream
::Spacing
;
14 use rustc_ast
::util
::classify
;
15 use rustc_ast
::util
::literal
::LitError
;
16 use rustc_ast
::util
::parser
::{prec_let_scrutinee_needs_par, AssocOp, Fixity}
;
17 use rustc_ast
::visit
::Visitor
;
18 use rustc_ast
::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp, DUMMY_NODE_ID}
;
19 use rustc_ast
::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}
;
20 use rustc_ast
::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}
;
21 use rustc_ast
::{ClosureBinder, StmtKind}
;
22 use rustc_ast_pretty
::pprust
;
23 use rustc_data_structures
::thin_vec
::ThinVec
;
24 use rustc_errors
::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult}
;
25 use rustc_session
::lint
::builtin
::BREAK_WITH_LABEL_AND_LOOP
;
26 use rustc_session
::lint
::BuiltinLintDiagnostics
;
27 use rustc_span
::source_map
::{self, Span, Spanned}
;
28 use rustc_span
::symbol
::{kw, sym, Ident, Symbol}
;
29 use rustc_span
::{BytePos, Pos}
;
31 /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression
32 /// dropped into the token stream, which happens while parsing the result of
33 /// macro expansion). Placement of these is not as complex as I feared it would
34 /// be. The important thing is to make sure that lookahead doesn't balk at
35 /// `token::Interpolated` tokens.
36 macro_rules
! maybe_whole_expr
{
38 if let token
::Interpolated(nt
) = &$p
.token
.kind
{
40 token
::NtExpr(e
) | token
::NtLiteral(e
) => {
45 token
::NtPath(path
) => {
46 let path
= (**path
).clone();
50 ExprKind
::Path(None
, path
),
54 token
::NtBlock(block
) => {
55 let block
= block
.clone();
59 ExprKind
::Block(block
, None
),
70 pub(super) enum LhsExpr
{
72 AttributesParsed(AttrWrapper
),
73 AlreadyParsed(P
<Expr
>),
76 impl From
<Option
<AttrWrapper
>> for LhsExpr
{
77 /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)`
78 /// and `None` into `LhsExpr::NotYetParsed`.
80 /// This conversion does not allocate.
81 fn from(o
: Option
<AttrWrapper
>) -> Self {
82 if let Some(attrs
) = o { LhsExpr::AttributesParsed(attrs) }
else { LhsExpr::NotYetParsed }
86 impl From
<P
<Expr
>> for LhsExpr
{
87 /// Converts the `expr: P<Expr>` into `LhsExpr::AlreadyParsed(expr)`.
89 /// This conversion does not allocate.
90 fn from(expr
: P
<Expr
>) -> Self {
91 LhsExpr
::AlreadyParsed(expr
)
96 /// Parses an expression.
98 pub fn parse_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
99 self.current_closure
.take();
101 self.parse_expr_res(Restrictions
::empty(), None
)
104 /// Parses an expression, forcing tokens to be collected
105 pub fn parse_expr_force_collect(&mut self) -> PResult
<'a
, P
<Expr
>> {
106 self.collect_tokens_no_attrs(|this
| this
.parse_expr())
109 pub fn parse_anon_const_expr(&mut self) -> PResult
<'a
, AnonConst
> {
110 self.parse_expr().map(|value
| AnonConst { id: DUMMY_NODE_ID, value }
)
113 fn parse_expr_catch_underscore(&mut self) -> PResult
<'a
, P
<Expr
>> {
114 match self.parse_expr() {
115 Ok(expr
) => Ok(expr
),
116 Err(mut err
) => match self.token
.ident() {
117 Some((Ident { name: kw::Underscore, .. }
, false))
118 if self.look_ahead(1, |t
| t
== &token
::Comma
) =>
120 // Special-case handling of `foo(_, _, _)`
123 Ok(self.mk_expr(self.prev_token
.span
, ExprKind
::Err
, AttrVec
::new()))
130 /// Parses a sequence of expressions delimited by parentheses.
131 fn parse_paren_expr_seq(&mut self) -> PResult
<'a
, Vec
<P
<Expr
>>> {
132 self.parse_paren_comma_seq(|p
| p
.parse_expr_catch_underscore()).map(|(r
, _
)| r
)
135 /// Parses an expression, subject to the given restrictions.
137 pub(super) fn parse_expr_res(
140 already_parsed_attrs
: Option
<AttrWrapper
>,
141 ) -> PResult
<'a
, P
<Expr
>> {
142 self.with_res(r
, |this
| this
.parse_assoc_expr(already_parsed_attrs
))
145 /// Parses an associative expression.
147 /// This parses an expression accounting for associativity and precedence of the operators in
152 already_parsed_attrs
: Option
<AttrWrapper
>,
153 ) -> PResult
<'a
, P
<Expr
>> {
154 self.parse_assoc_expr_with(0, already_parsed_attrs
.into())
157 /// Parses an associative expression with operators of at least `min_prec` precedence.
158 pub(super) fn parse_assoc_expr_with(
162 ) -> PResult
<'a
, P
<Expr
>> {
163 let mut lhs
= if let LhsExpr
::AlreadyParsed(expr
) = lhs
{
166 let attrs
= match lhs
{
167 LhsExpr
::AttributesParsed(attrs
) => Some(attrs
),
170 if [token
::DotDot
, token
::DotDotDot
, token
::DotDotEq
].contains(&self.token
.kind
) {
171 return self.parse_prefix_range_expr(attrs
);
173 self.parse_prefix_expr(attrs
)?
176 let last_type_ascription_set
= self.last_type_ascription
.is_some();
178 if !self.should_continue_as_assoc_expr(&lhs
) {
179 self.last_type_ascription
= None
;
183 self.expected_tokens
.push(TokenType
::Operator
);
184 while let Some(op
) = self.check_assoc_op() {
185 // Adjust the span for interpolated LHS to point to the `$lhs` token
186 // and not to what it refers to.
187 let lhs_span
= match self.prev_token
.kind
{
188 TokenKind
::Interpolated(..) => self.prev_token
.span
,
192 let cur_op_span
= self.token
.span
;
193 let restrictions
= if op
.node
.is_assign_like() {
194 self.restrictions
& Restrictions
::NO_STRUCT_LITERAL
198 let prec
= op
.node
.precedence();
202 // Check for deprecated `...` syntax
203 if self.token
== token
::DotDotDot
&& op
.node
== AssocOp
::DotDotEq
{
204 self.err_dotdotdot_syntax(self.token
.span
);
207 if self.token
== token
::LArrow
{
208 self.err_larrow_operator(self.token
.span
);
212 if op
.node
.is_comparison() {
213 if let Some(expr
) = self.check_no_chained_comparison(&lhs
, &op
)?
{
218 // Look for JS' `===` and `!==` and recover
219 if (op
.node
== AssocOp
::Equal
|| op
.node
== AssocOp
::NotEqual
)
220 && self.token
.kind
== token
::Eq
221 && self.prev_token
.span
.hi() == self.token
.span
.lo()
223 let sp
= op
.span
.to(self.token
.span
);
224 let sugg
= match op
.node
{
225 AssocOp
::Equal
=> "==",
226 AssocOp
::NotEqual
=> "!=",
229 self.struct_span_err(sp
, &format
!("invalid comparison operator `{sugg}=`"))
230 .span_suggestion_short(
232 &format
!("`{s}=` is not a valid comparison operator, use `{s}`", s
= sugg
),
234 Applicability
::MachineApplicable
,
240 // Look for PHP's `<>` and recover
241 if op
.node
== AssocOp
::Less
242 && self.token
.kind
== token
::Gt
243 && self.prev_token
.span
.hi() == self.token
.span
.lo()
245 let sp
= op
.span
.to(self.token
.span
);
246 self.struct_span_err(sp
, "invalid comparison operator `<>`")
247 .span_suggestion_short(
249 "`<>` is not a valid comparison operator, use `!=`",
251 Applicability
::MachineApplicable
,
257 // Look for C++'s `<=>` and recover
258 if op
.node
== AssocOp
::LessEqual
259 && self.token
.kind
== token
::Gt
260 && self.prev_token
.span
.hi() == self.token
.span
.lo()
262 let sp
= op
.span
.to(self.token
.span
);
263 self.struct_span_err(sp
, "invalid comparison operator `<=>`")
266 "`<=>` is not a valid comparison operator, use `std::cmp::Ordering`",
272 if self.prev_token
== token
::BinOp(token
::Plus
)
273 && self.token
== token
::BinOp(token
::Plus
)
274 && self.prev_token
.span
.between(self.token
.span
).is_empty()
276 let op_span
= self.prev_token
.span
.to(self.token
.span
);
277 // Eat the second `+`
279 lhs
= self.recover_from_postfix_increment(lhs
, op_span
)?
;
285 if op
== AssocOp
::As
{
286 lhs
= self.parse_assoc_op_cast(lhs
, lhs_span
, ExprKind
::Cast
)?
;
288 } else if op
== AssocOp
::Colon
{
289 lhs
= self.parse_assoc_op_ascribe(lhs
, lhs_span
)?
;
291 } else if op
== AssocOp
::DotDot
|| op
== AssocOp
::DotDotEq
{
292 // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
293 // generalise it to the Fixity::None code.
294 lhs
= self.parse_range_expr(prec
, lhs
, op
, cur_op_span
)?
;
298 let fixity
= op
.fixity();
299 let prec_adjustment
= match fixity
{
302 // We currently have no non-associative operators that are not handled above by
303 // the special cases. The code is here only for future convenience.
306 let rhs
= self.with_res(restrictions
- Restrictions
::STMT_EXPR
, |this
| {
307 this
.parse_assoc_expr_with(prec
+ prec_adjustment
, LhsExpr
::NotYetParsed
)
310 let span
= self.mk_expr_sp(&lhs
, lhs_span
, rhs
.span
);
323 | AssocOp
::ShiftRight
329 | AssocOp
::GreaterEqual
=> {
330 let ast_op
= op
.to_ast_binop().unwrap();
331 let binary
= self.mk_binary(source_map
::respan(cur_op_span
, ast_op
), lhs
, rhs
);
332 self.mk_expr(span
, binary
, AttrVec
::new())
335 self.mk_expr(span
, ExprKind
::Assign(lhs
, rhs
, cur_op_span
), AttrVec
::new())
337 AssocOp
::AssignOp(k
) => {
339 token
::Plus
=> BinOpKind
::Add
,
340 token
::Minus
=> BinOpKind
::Sub
,
341 token
::Star
=> BinOpKind
::Mul
,
342 token
::Slash
=> BinOpKind
::Div
,
343 token
::Percent
=> BinOpKind
::Rem
,
344 token
::Caret
=> BinOpKind
::BitXor
,
345 token
::And
=> BinOpKind
::BitAnd
,
346 token
::Or
=> BinOpKind
::BitOr
,
347 token
::Shl
=> BinOpKind
::Shl
,
348 token
::Shr
=> BinOpKind
::Shr
,
350 let aopexpr
= self.mk_assign_op(source_map
::respan(cur_op_span
, aop
), lhs
, rhs
);
351 self.mk_expr(span
, aopexpr
, AttrVec
::new())
353 AssocOp
::As
| AssocOp
::Colon
| AssocOp
::DotDot
| AssocOp
::DotDotEq
=> {
354 self.span_bug(span
, "AssocOp should have been handled by special case")
358 if let Fixity
::None
= fixity
{
362 if last_type_ascription_set
{
363 self.last_type_ascription
= None
;
368 fn should_continue_as_assoc_expr(&mut self, lhs
: &Expr
) -> bool
{
369 match (self.expr_is_complete(lhs
), AssocOp
::from_token(&self.token
)) {
370 // Semi-statement forms are odd:
371 // See https://github.com/rust-lang/rust/issues/29071
372 (true, None
) => false,
373 (false, _
) => true, // Continue parsing the expression.
374 // An exhaustive check is done in the following block, but these are checked first
375 // because they *are* ambiguous but also reasonable looking incorrect syntax, so we
376 // want to keep their span info to improve diagnostics in these cases in a later stage.
377 (true, Some(AssocOp
::Multiply
)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
378 (true, Some(AssocOp
::Subtract
)) | // `{ 42 } -5`
379 (true, Some(AssocOp
::Add
)) // `{ 42 } + 42
380 // If the next token is a keyword, then the tokens above *are* unambiguously incorrect:
381 // `if x { a } else { b } && if y { c } else { d }`
382 if !self.look_ahead(1, |t
| t
.is_used_keyword()) => {
383 // These cases are ambiguous and can't be identified in the parser alone.
384 let sp
= self.sess
.source_map().start_point(self.token
.span
);
385 self.sess
.ambiguous_block_expr_parse
.borrow_mut().insert(sp
, lhs
.span
);
388 (true, Some(AssocOp
::LAnd
)) |
389 (true, Some(AssocOp
::LOr
)) |
390 (true, Some(AssocOp
::BitOr
)) => {
391 // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
392 // above due to #74233.
393 // These cases are ambiguous and can't be identified in the parser alone.
395 // Bitwise AND is left out because guessing intent is hard. We can make
396 // suggestions based on the assumption that double-refs are rarely intentional,
397 // and closures are distinct enough that they don't get mixed up with their
399 let sp
= self.sess
.source_map().start_point(self.token
.span
);
400 self.sess
.ambiguous_block_expr_parse
.borrow_mut().insert(sp
, lhs
.span
);
403 (true, Some(ref op
)) if !op
.can_continue_expr_unambiguously() => false,
405 self.error_found_expr_would_be_stmt(lhs
);
411 /// We've found an expression that would be parsed as a statement,
412 /// but the next token implies this should be parsed as an expression.
413 /// For example: `if let Some(x) = x { x } else { 0 } / 2`.
414 fn error_found_expr_would_be_stmt(&self, lhs
: &Expr
) {
415 let mut err
= self.struct_span_err(
417 &format
!("expected expression, found `{}`", pprust
::token_to_string(&self.token
),),
419 err
.span_label(self.token
.span
, "expected expression");
420 self.sess
.expr_parentheses_needed(&mut err
, lhs
.span
);
424 /// Possibly translate the current token to an associative operator.
425 /// The method does not advance the current token.
427 /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
428 fn check_assoc_op(&self) -> Option
<Spanned
<AssocOp
>> {
429 let (op
, span
) = match (AssocOp
::from_token(&self.token
), self.token
.ident()) {
430 // When parsing const expressions, stop parsing when encountering `>`.
435 | AssocOp
::GreaterEqual
436 | AssocOp
::AssignOp(token
::BinOpToken
::Shr
),
439 ) if self.restrictions
.contains(Restrictions
::CONST_EXPR
) => {
442 (Some(op
), _
) => (op
, self.token
.span
),
443 (None
, Some((Ident { name: sym::and, span }
, false))) => {
444 self.error_bad_logical_op("and", "&&", "conjunction");
445 (AssocOp
::LAnd
, span
)
447 (None
, Some((Ident { name: sym::or, span }
, false))) => {
448 self.error_bad_logical_op("or", "||", "disjunction");
453 Some(source_map
::respan(span
, op
))
456 /// Error on `and` and `or` suggesting `&&` and `||` respectively.
457 fn error_bad_logical_op(&self, bad
: &str, good
: &str, english
: &str) {
458 self.struct_span_err(self.token
.span
, &format
!("`{bad}` is not a logical operator"))
459 .span_suggestion_short(
461 &format
!("use `{good}` to perform logical {english}"),
463 Applicability
::MachineApplicable
,
465 .note("unlike in e.g., python and PHP, `&&` and `||` are used for logical operators")
469 /// Checks if this expression is a successfully parsed statement.
470 fn expr_is_complete(&self, e
: &Expr
) -> bool
{
471 self.restrictions
.contains(Restrictions
::STMT_EXPR
)
472 && !classify
::expr_requires_semi_to_be_stmt(e
)
475 /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
476 /// The other two variants are handled in `parse_prefix_range_expr` below.
483 ) -> PResult
<'a
, P
<Expr
>> {
484 let rhs
= if self.is_at_start_of_range_notation_rhs() {
485 Some(self.parse_assoc_expr_with(prec
+ 1, LhsExpr
::NotYetParsed
)?
)
489 let rhs_span
= rhs
.as_ref().map_or(cur_op_span
, |x
| x
.span
);
490 let span
= self.mk_expr_sp(&lhs
, lhs
.span
, rhs_span
);
492 if op
== AssocOp
::DotDot { RangeLimits::HalfOpen }
else { RangeLimits::Closed }
;
493 let range
= self.mk_range(Some(lhs
), rhs
, limits
);
494 Ok(self.mk_expr(span
, range
, AttrVec
::new()))
497 fn is_at_start_of_range_notation_rhs(&self) -> bool
{
498 if self.token
.can_begin_expr() {
499 // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
500 if self.token
== token
::OpenDelim(Delimiter
::Brace
) {
501 return !self.restrictions
.contains(Restrictions
::NO_STRUCT_LITERAL
);
509 /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
510 fn parse_prefix_range_expr(&mut self, attrs
: Option
<AttrWrapper
>) -> PResult
<'a
, P
<Expr
>> {
511 // Check for deprecated `...` syntax.
512 if self.token
== token
::DotDotDot
{
513 self.err_dotdotdot_syntax(self.token
.span
);
517 [token
::DotDot
, token
::DotDotDot
, token
::DotDotEq
].contains(&self.token
.kind
),
518 "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq",
522 let limits
= match self.token
.kind
{
523 token
::DotDot
=> RangeLimits
::HalfOpen
,
524 _
=> RangeLimits
::Closed
,
526 let op
= AssocOp
::from_token(&self.token
);
527 // FIXME: `parse_prefix_range_expr` is called when the current
528 // token is `DotDot`, `DotDotDot`, or `DotDotEq`. If we haven't already
529 // parsed attributes, then trying to parse them here will always fail.
530 // We should figure out how we want attributes on range expressions to work.
531 let attrs
= self.parse_or_use_outer_attributes(attrs
)?
;
532 self.collect_tokens_for_expr(attrs
, |this
, attrs
| {
533 let lo
= this
.token
.span
;
535 let (span
, opt_end
) = if this
.is_at_start_of_range_notation_rhs() {
536 // RHS must be parsed with more associativity than the dots.
537 this
.parse_assoc_expr_with(op
.unwrap().precedence() + 1, LhsExpr
::NotYetParsed
)
538 .map(|x
| (lo
.to(x
.span
), Some(x
)))?
542 let range
= this
.mk_range(None
, opt_end
, limits
);
543 Ok(this
.mk_expr(span
, range
, attrs
.into()))
547 /// Parses a prefix-unary-operator expr.
548 fn parse_prefix_expr(&mut self, attrs
: Option
<AttrWrapper
>) -> PResult
<'a
, P
<Expr
>> {
549 let attrs
= self.parse_or_use_outer_attributes(attrs
)?
;
550 let lo
= self.token
.span
;
552 macro_rules
! make_it
{
553 ($this
:ident
, $attrs
:expr
, |this
, _
| $body
:expr
) => {
554 $this
.collect_tokens_for_expr($attrs
, |$this
, attrs
| {
555 let (hi
, ex
) = $body?
;
556 Ok($this
.mk_expr(lo
.to(hi
), ex
, attrs
.into()))
563 // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
564 match this
.token
.uninterpolate().kind
{
565 token
::Not
=> make_it
!(this
, attrs
, |this
, _
| this
.parse_unary_expr(lo
, UnOp
::Not
)), // `!expr`
566 token
::Tilde
=> make_it
!(this
, attrs
, |this
, _
| this
.recover_tilde_expr(lo
)), // `~expr`
567 token
::BinOp(token
::Minus
) => {
568 make_it
!(this
, attrs
, |this
, _
| this
.parse_unary_expr(lo
, UnOp
::Neg
))
570 token
::BinOp(token
::Star
) => {
571 make_it
!(this
, attrs
, |this
, _
| this
.parse_unary_expr(lo
, UnOp
::Deref
))
573 token
::BinOp(token
::And
) | token
::AndAnd
=> {
574 make_it
!(this
, attrs
, |this
, _
| this
.parse_borrow_expr(lo
))
576 token
::BinOp(token
::Plus
) if this
.look_ahead(1, |tok
| tok
.is_numeric_lit()) => {
577 let mut err
= this
.struct_span_err(lo
, "leading `+` is not supported");
578 err
.span_label(lo
, "unexpected `+`");
580 // a block on the LHS might have been intended to be an expression instead
581 if let Some(sp
) = this
.sess
.ambiguous_block_expr_parse
.borrow().get(&lo
) {
582 this
.sess
.expr_parentheses_needed(&mut err
, *sp
);
584 err
.span_suggestion_verbose(
586 "try removing the `+`",
588 Applicability
::MachineApplicable
,
594 this
.parse_prefix_expr(None
)
596 // Recover from `++x`:
597 token
::BinOp(token
::Plus
)
598 if this
.look_ahead(1, |t
| *t
== token
::BinOp(token
::Plus
)) =>
600 let prev_is_semi
= this
.prev_token
== token
::Semi
;
601 let pre_span
= this
.token
.span
.to(this
.look_ahead(1, |t
| t
.span
));
606 let operand_expr
= this
.parse_dot_or_call_expr(Default
::default())?
;
607 this
.recover_from_prefix_increment(operand_expr
, pre_span
, prev_is_semi
)
609 token
::Ident(..) if this
.token
.is_keyword(kw
::Box
) => {
610 make_it
!(this
, attrs
, |this
, _
| this
.parse_box_expr(lo
))
612 token
::Ident(..) if this
.is_mistaken_not_ident_negation() => {
613 make_it
!(this
, attrs
, |this
, _
| this
.recover_not_expr(lo
))
615 _
=> return this
.parse_dot_or_call_expr(Some(attrs
)),
619 fn parse_prefix_expr_common(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, P
<Expr
>)> {
621 let expr
= self.parse_prefix_expr(None
);
622 let (span
, expr
) = self.interpolated_or_expr_span(expr
)?
;
623 Ok((lo
.to(span
), expr
))
626 fn parse_unary_expr(&mut self, lo
: Span
, op
: UnOp
) -> PResult
<'a
, (Span
, ExprKind
)> {
627 let (span
, expr
) = self.parse_prefix_expr_common(lo
)?
;
628 Ok((span
, self.mk_unary(op
, expr
)))
631 // Recover on `!` suggesting for bitwise negation instead.
632 fn recover_tilde_expr(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, ExprKind
)> {
633 self.struct_span_err(lo
, "`~` cannot be used as a unary operator")
634 .span_suggestion_short(
636 "use `!` to perform bitwise not",
638 Applicability
::MachineApplicable
,
642 self.parse_unary_expr(lo
, UnOp
::Not
)
645 /// Parse `box expr`.
646 fn parse_box_expr(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, ExprKind
)> {
647 let (span
, expr
) = self.parse_prefix_expr_common(lo
)?
;
648 self.sess
.gated_spans
.gate(sym
::box_syntax
, span
);
649 Ok((span
, ExprKind
::Box(expr
)))
652 fn is_mistaken_not_ident_negation(&self) -> bool
{
653 let token_cannot_continue_expr
= |t
: &Token
| match t
.uninterpolate().kind
{
654 // These tokens can start an expression after `!`, but
655 // can't continue an expression after an ident
656 token
::Ident(name
, is_raw
) => token
::ident_can_begin_expr(name
, t
.span
, is_raw
),
657 token
::Literal(..) | token
::Pound
=> true,
658 _
=> t
.is_whole_expr(),
660 self.token
.is_ident_named(sym
::not
) && self.look_ahead(1, token_cannot_continue_expr
)
663 /// Recover on `not expr` in favor of `!expr`.
664 fn recover_not_expr(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, ExprKind
)> {
666 let not_token
= self.look_ahead(1, |t
| t
.clone());
667 self.struct_span_err(
669 &format
!("unexpected {} after identifier", super::token_descr(¬_token
)),
671 .span_suggestion_short(
672 // Span the `not` plus trailing whitespace to avoid
673 // trailing whitespace after the `!` in our suggestion
674 self.sess
.source_map().span_until_non_whitespace(lo
.to(not_token
.span
)),
675 "use `!` to perform logical negation",
677 Applicability
::MachineApplicable
,
682 self.parse_unary_expr(lo
, UnOp
::Not
)
685 /// Returns the span of expr, if it was not interpolated or the span of the interpolated token.
686 fn interpolated_or_expr_span(
688 expr
: PResult
<'a
, P
<Expr
>>,
689 ) -> PResult
<'a
, (Span
, P
<Expr
>)> {
692 match self.prev_token
.kind
{
693 TokenKind
::Interpolated(..) => self.prev_token
.span
,
701 fn parse_assoc_op_cast(
705 expr_kind
: fn(P
<Expr
>, P
<Ty
>) -> ExprKind
,
706 ) -> PResult
<'a
, P
<Expr
>> {
707 let mk_expr
= |this
: &mut Self, lhs
: P
<Expr
>, rhs
: P
<Ty
>| {
709 this
.mk_expr_sp(&lhs
, lhs_span
, rhs
.span
),
715 // Save the state of the parser before parsing type normally, in case there is a
716 // LessThan comparison after this cast.
717 let parser_snapshot_before_type
= self.clone();
718 let cast_expr
= match self.parse_as_cast_ty() {
719 Ok(rhs
) => mk_expr(self, lhs
, rhs
),
721 // Rewind to before attempting to parse the type with generics, to recover
722 // from situations like `x as usize < y` in which we first tried to parse
723 // `usize < y` as a type with generic arguments.
724 let parser_snapshot_after_type
= mem
::replace(self, parser_snapshot_before_type
);
726 // Check for typo of `'a: loop { break 'a }` with a missing `'`.
727 match (&lhs
.kind
, &self.token
.kind
) {
730 ExprKind
::Path(None
, ast
::Path { segments, .. }
),
731 TokenKind
::Ident(kw
::For
| kw
::Loop
| kw
::While
, false),
732 ) if segments
.len() == 1 => {
733 let snapshot
= self.create_snapshot_for_diagnostic();
735 ident
: Ident
::from_str_and_span(
736 &format
!("'{}", segments
[0].ident
),
737 segments
[0].ident
.span
,
740 match self.parse_labeled_expr(label
, AttrVec
::new(), false) {
743 self.struct_span_err(label
.ident
.span
, "malformed loop label")
746 "use the correct loop label format",
748 Applicability
::MachineApplicable
,
755 self.restore_snapshot(snapshot
);
762 match self.parse_path(PathStyle
::Expr
) {
764 let (op_noun
, op_verb
) = match self.token
.kind
{
765 token
::Lt
=> ("comparison", "comparing"),
766 token
::BinOp(token
::Shl
) => ("shift", "shifting"),
768 // We can end up here even without `<` being the next token, for
769 // example because `parse_ty_no_plus` returns `Err` on keywords,
770 // but `parse_path` returns `Ok` on them due to error recovery.
771 // Return original error and parser state.
772 *self = parser_snapshot_after_type
;
773 return Err(type_err
);
777 // Successfully parsed the type path leaving a `<` yet to parse.
780 // Report non-fatal diagnostics, keep `x as usize` as an expression
781 // in AST and continue parsing.
783 "`<` is interpreted as a start of generic arguments for `{}`, not a {}",
784 pprust
::path_to_string(&path
),
787 let span_after_type
= parser_snapshot_after_type
.token
.span
;
789 mk_expr(self, lhs
, self.mk_ty(path
.span
, TyKind
::Path(None
, path
)));
791 self.struct_span_err(self.token
.span
, &msg
)
793 self.look_ahead(1, |t
| t
.span
).to(span_after_type
),
794 "interpreted as generic arguments",
796 .span_label(self.token
.span
, format
!("not interpreted as {op_noun}"))
797 .multipart_suggestion(
798 &format
!("try {op_verb} the cast value"),
800 (expr
.span
.shrink_to_lo(), "(".to_string()),
801 (expr
.span
.shrink_to_hi(), ")".to_string()),
803 Applicability
::MachineApplicable
,
810 // Couldn't parse as a path, return original error and parser state.
812 *self = parser_snapshot_after_type
;
813 return Err(type_err
);
819 self.parse_and_disallow_postfix_after_cast(cast_expr
)
822 /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast,
823 /// then emits an error and returns the newly parsed tree.
824 /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
825 fn parse_and_disallow_postfix_after_cast(
828 ) -> PResult
<'a
, P
<Expr
>> {
829 let span
= cast_expr
.span
;
830 let (cast_kind
, maybe_ascription_span
) =
831 if let ExprKind
::Type(ascripted_expr
, _
) = &cast_expr
.kind
{
832 ("type ascription", Some(ascripted_expr
.span
.shrink_to_hi().with_hi(span
.hi())))
837 // Save the memory location of expr before parsing any following postfix operators.
838 // This will be compared with the memory location of the output expression.
839 // If they different we can assume we parsed another expression because the existing expression is not reallocated.
840 let addr_before
= &*cast_expr
as *const _
as usize;
841 let with_postfix
= self.parse_dot_or_call_expr_with_(cast_expr
, span
)?
;
842 let changed
= addr_before
!= &*with_postfix
as *const _
as usize;
844 // Check if an illegal postfix operator has been added after the cast.
845 // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator.
846 if !matches
!(with_postfix
.kind
, ExprKind
::Cast(_
, _
) | ExprKind
::Type(_
, _
)) || changed
{
848 "{cast_kind} cannot be followed by {}",
849 match with_postfix
.kind
{
850 ExprKind
::Index(_
, _
) => "indexing",
851 ExprKind
::Try(_
) => "`?`",
852 ExprKind
::Field(_
, _
) => "a field access",
853 ExprKind
::MethodCall(_
, _
, _
) => "a method call",
854 ExprKind
::Call(_
, _
) => "a function call",
855 ExprKind
::Await(_
) => "`.await`",
856 ExprKind
::Err
=> return Ok(with_postfix
),
857 _
=> unreachable
!("parse_dot_or_call_expr_with_ shouldn't produce this"),
860 let mut err
= self.struct_span_err(span
, &msg
);
862 let suggest_parens
= |err
: &mut DiagnosticBuilder
<'_
, _
>| {
863 let suggestions
= vec
![
864 (span
.shrink_to_lo(), "(".to_string()),
865 (span
.shrink_to_hi(), ")".to_string()),
867 err
.multipart_suggestion(
868 "try surrounding the expression in parentheses",
870 Applicability
::MachineApplicable
,
874 // If type ascription is "likely an error", the user will already be getting a useful
875 // help message, and doesn't need a second.
876 if self.last_type_ascription
.map_or(false, |last_ascription
| last_ascription
.1) {
877 self.maybe_annotate_with_ascription(&mut err
, false);
878 } else if let Some(ascription_span
) = maybe_ascription_span
{
879 let is_nightly
= self.sess
.unstable_features
.is_nightly_build();
881 suggest_parens(&mut err
);
886 "{}remove the type ascription",
887 if is_nightly { "alternatively, " }
else { "" }
891 Applicability
::MaybeIncorrect
893 Applicability
::MachineApplicable
897 suggest_parens(&mut err
);
904 fn parse_assoc_op_ascribe(&mut self, lhs
: P
<Expr
>, lhs_span
: Span
) -> PResult
<'a
, P
<Expr
>> {
905 let maybe_path
= self.could_ascription_be_path(&lhs
.kind
);
906 self.last_type_ascription
= Some((self.prev_token
.span
, maybe_path
));
907 let lhs
= self.parse_assoc_op_cast(lhs
, lhs_span
, ExprKind
::Type
)?
;
908 self.sess
.gated_spans
.gate(sym
::type_ascription
, lhs
.span
);
912 /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
913 fn parse_borrow_expr(&mut self, lo
: Span
) -> PResult
<'a
, (Span
, ExprKind
)> {
915 let has_lifetime
= self.token
.is_lifetime() && self.look_ahead(1, |t
| t
!= &token
::Colon
);
916 let lifetime
= has_lifetime
.then(|| self.expect_lifetime()); // For recovery, see below.
917 let (borrow_kind
, mutbl
) = self.parse_borrow_modifiers(lo
);
918 let expr
= self.parse_prefix_expr(None
);
919 let (hi
, expr
) = self.interpolated_or_expr_span(expr
)?
;
920 let span
= lo
.to(hi
);
921 if let Some(lt
) = lifetime
{
922 self.error_remove_borrow_lifetime(span
, lt
.ident
.span
);
924 Ok((span
, ExprKind
::AddrOf(borrow_kind
, mutbl
, expr
)))
927 fn error_remove_borrow_lifetime(&self, span
: Span
, lt_span
: Span
) {
928 self.struct_span_err(span
, "borrow expressions cannot be annotated with lifetimes")
929 .span_label(lt_span
, "annotated with lifetime here")
932 "remove the lifetime annotation",
934 Applicability
::MachineApplicable
,
939 /// Parse `mut?` or `raw [ const | mut ]`.
940 fn parse_borrow_modifiers(&mut self, lo
: Span
) -> (ast
::BorrowKind
, ast
::Mutability
) {
941 if self.check_keyword(kw
::Raw
) && self.look_ahead(1, Token
::is_mutability
) {
942 // `raw [ const | mut ]`.
943 let found_raw
= self.eat_keyword(kw
::Raw
);
945 let mutability
= self.parse_const_or_mut().unwrap();
946 self.sess
.gated_spans
.gate(sym
::raw_ref_op
, lo
.to(self.prev_token
.span
));
947 (ast
::BorrowKind
::Raw
, mutability
)
950 (ast
::BorrowKind
::Ref
, self.parse_mutability())
954 /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
955 fn parse_dot_or_call_expr(&mut self, attrs
: Option
<AttrWrapper
>) -> PResult
<'a
, P
<Expr
>> {
956 let attrs
= self.parse_or_use_outer_attributes(attrs
)?
;
957 self.collect_tokens_for_expr(attrs
, |this
, attrs
| {
958 let base
= this
.parse_bottom_expr();
959 let (span
, base
) = this
.interpolated_or_expr_span(base
)?
;
960 this
.parse_dot_or_call_expr_with(base
, span
, attrs
)
964 pub(super) fn parse_dot_or_call_expr_with(
968 mut attrs
: Vec
<ast
::Attribute
>,
969 ) -> PResult
<'a
, P
<Expr
>> {
970 // Stitch the list of outer attributes onto the return value.
971 // A little bit ugly, but the best way given the current code
973 self.parse_dot_or_call_expr_with_(e0
, lo
).map(|expr
| {
974 expr
.map(|mut expr
| {
975 attrs
.extend
::<Vec
<_
>>(expr
.attrs
.into());
976 expr
.attrs
= attrs
.into();
982 fn parse_dot_or_call_expr_with_(&mut self, mut e
: P
<Expr
>, lo
: Span
) -> PResult
<'a
, P
<Expr
>> {
984 let has_question
= if self.prev_token
.kind
== TokenKind
::Ident(kw
::Return
, false) {
985 // we are using noexpect here because we don't expect a `?` directly after a `return`
986 // which could be suggested otherwise
987 self.eat_noexpect(&token
::Question
)
989 self.eat(&token
::Question
)
993 e
= self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::Try(e
), AttrVec
::new());
996 let has_dot
= if self.prev_token
.kind
== TokenKind
::Ident(kw
::Return
, false) {
997 // we are using noexpect here because we don't expect a `.` directly after a `return`
998 // which could be suggested otherwise
999 self.eat_noexpect(&token
::Dot
)
1001 self.eat(&token
::Dot
)
1005 e
= self.parse_dot_suffix_expr(lo
, e
)?
;
1008 if self.expr_is_complete(&e
) {
1011 e
= match self.token
.kind
{
1012 token
::OpenDelim(Delimiter
::Parenthesis
) => self.parse_fn_call_expr(lo
, e
),
1013 token
::OpenDelim(Delimiter
::Bracket
) => self.parse_index_expr(lo
, e
)?
,
1019 fn look_ahead_type_ascription_as_field(&mut self) -> bool
{
1020 self.look_ahead(1, |t
| t
.is_ident())
1021 && self.look_ahead(2, |t
| t
== &token
::Colon
)
1022 && self.look_ahead(3, |t
| t
.can_begin_expr())
1025 fn parse_dot_suffix_expr(&mut self, lo
: Span
, base
: P
<Expr
>) -> PResult
<'a
, P
<Expr
>> {
1026 match self.token
.uninterpolate().kind
{
1027 token
::Ident(..) => self.parse_dot_suffix(base
, lo
),
1028 token
::Literal(token
::Lit { kind: token::Integer, symbol, suffix }
) => {
1029 Ok(self.parse_tuple_field_access_expr(lo
, base
, symbol
, suffix
, None
))
1031 token
::Literal(token
::Lit { kind: token::Float, symbol, suffix }
) => {
1032 Ok(self.parse_tuple_field_access_expr_float(lo
, base
, symbol
, suffix
))
1035 self.error_unexpected_after_dot();
1041 fn error_unexpected_after_dot(&self) {
1042 // FIXME Could factor this out into non_fatal_unexpected or something.
1043 let actual
= pprust
::token_to_string(&self.token
);
1044 self.struct_span_err(self.token
.span
, &format
!("unexpected token: `{actual}`")).emit();
1047 // We need an identifier or integer, but the next token is a float.
1048 // Break the float into components to extract the identifier or integer.
1049 // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
1050 // parts unless those parts are processed immediately. `TokenCursor` should either
1051 // support pushing "future tokens" (would be also helpful to `break_and_eat`), or
1052 // we should break everything including floats into more basic proc-macro style
1053 // tokens in the lexer (probably preferable).
1054 fn parse_tuple_field_access_expr_float(
1059 suffix
: Option
<Symbol
>,
1062 enum FloatComponent
{
1066 use FloatComponent
::*;
1068 let float_str
= float
.as_str();
1069 let mut components
= Vec
::new();
1070 let mut ident_like
= String
::new();
1071 for c
in float_str
.chars() {
1072 if c
== '_'
|| c
.is_ascii_alphanumeric() {
1074 } else if matches
!(c
, '
.'
| '
+'
| '
-'
) {
1075 if !ident_like
.is_empty() {
1076 components
.push(IdentLike(mem
::take(&mut ident_like
)));
1078 components
.push(Punct(c
));
1080 panic
!("unexpected character in a float token: {:?}", c
)
1083 if !ident_like
.is_empty() {
1084 components
.push(IdentLike(ident_like
));
1087 // With proc macros the span can refer to anything, the source may be too short,
1088 // or too long, or non-ASCII. It only makes sense to break our span into components
1089 // if its underlying text is identical to our float literal.
1090 let span
= self.token
.span
;
1091 let can_take_span_apart
=
1092 || self.span_to_snippet(span
).as_deref() == Ok(float_str
).as_deref();
1094 match &*components
{
1097 self.parse_tuple_field_access_expr(lo
, base
, Symbol
::intern(&i
), suffix
, None
)
1100 [IdentLike(i
), Punct('
.'
)] => {
1101 let (ident_span
, dot_span
) = if can_take_span_apart() {
1102 let (span
, ident_len
) = (span
.data(), BytePos
::from_usize(i
.len()));
1103 let ident_span
= span
.with_hi(span
.lo
+ ident_len
);
1104 let dot_span
= span
.with_lo(span
.lo
+ ident_len
);
1105 (ident_span
, dot_span
)
1109 assert
!(suffix
.is_none());
1110 let symbol
= Symbol
::intern(&i
);
1111 self.token
= Token
::new(token
::Ident(symbol
, false), ident_span
);
1112 let next_token
= (Token
::new(token
::Dot
, dot_span
), self.token_spacing
);
1113 self.parse_tuple_field_access_expr(lo
, base
, symbol
, None
, Some(next_token
))
1116 [IdentLike(i1
), Punct('
.'
), IdentLike(i2
)] => {
1117 let (ident1_span
, dot_span
, ident2_span
) = if can_take_span_apart() {
1118 let (span
, ident1_len
) = (span
.data(), BytePos
::from_usize(i1
.len()));
1119 let ident1_span
= span
.with_hi(span
.lo
+ ident1_len
);
1121 .with_lo(span
.lo
+ ident1_len
)
1122 .with_hi(span
.lo
+ ident1_len
+ BytePos(1));
1123 let ident2_span
= self.token
.span
.with_lo(span
.lo
+ ident1_len
+ BytePos(1));
1124 (ident1_span
, dot_span
, ident2_span
)
1128 let symbol1
= Symbol
::intern(&i1
);
1129 self.token
= Token
::new(token
::Ident(symbol1
, false), ident1_span
);
1130 // This needs to be `Spacing::Alone` to prevent regressions.
1131 // See issue #76399 and PR #76285 for more details
1132 let next_token1
= (Token
::new(token
::Dot
, dot_span
), Spacing
::Alone
);
1134 self.parse_tuple_field_access_expr(lo
, base
, symbol1
, None
, Some(next_token1
));
1135 let symbol2
= Symbol
::intern(&i2
);
1136 let next_token2
= Token
::new(token
::Ident(symbol2
, false), ident2_span
);
1137 self.bump_with((next_token2
, self.token_spacing
)); // `.`
1138 self.parse_tuple_field_access_expr(lo
, base1
, symbol2
, suffix
, None
)
1140 // 1e+ | 1e- (recovered)
1141 [IdentLike(_
), Punct('
+'
| '
-'
)] |
1143 [IdentLike(_
), Punct('
+'
| '
-'
), IdentLike(_
)] |
1145 [IdentLike(_
), Punct('
.'
), IdentLike(_
), Punct('
+'
| '
-'
)] |
1147 [IdentLike(_
), Punct('
.'
), IdentLike(_
), Punct('
+'
| '
-'
), IdentLike(_
)] => {
1148 // See the FIXME about `TokenCursor` above.
1149 self.error_unexpected_after_dot();
1152 _
=> panic
!("unexpected components in a float token: {:?}", components
),
1156 fn parse_tuple_field_access_expr(
1161 suffix
: Option
<Symbol
>,
1162 next_token
: Option
<(Token
, Spacing
)>,
1165 Some(next_token
) => self.bump_with(next_token
),
1166 None
=> self.bump(),
1168 let span
= self.prev_token
.span
;
1169 let field
= ExprKind
::Field(base
, Ident
::new(field
, span
));
1170 self.expect_no_suffix(span
, "a tuple index", suffix
);
1171 self.mk_expr(lo
.to(span
), field
, AttrVec
::new())
1174 /// Parse a function call expression, `expr(...)`.
1175 fn parse_fn_call_expr(&mut self, lo
: Span
, fun
: P
<Expr
>) -> P
<Expr
> {
1176 let snapshot
= if self.token
.kind
== token
::OpenDelim(Delimiter
::Parenthesis
)
1177 && self.look_ahead_type_ascription_as_field()
1179 Some((self.create_snapshot_for_diagnostic(), fun
.kind
.clone()))
1183 let open_paren
= self.token
.span
;
1185 let mut seq
= self.parse_paren_expr_seq().map(|args
| {
1186 self.mk_expr(lo
.to(self.prev_token
.span
), self.mk_call(fun
, args
), AttrVec
::new())
1189 self.maybe_recover_struct_lit_bad_delims(lo
, open_paren
, &mut seq
, snapshot
)
1193 self.recover_seq_parse_error(Delimiter
::Parenthesis
, lo
, seq
)
1196 /// If we encounter a parser state that looks like the user has written a `struct` literal with
1197 /// parentheses instead of braces, recover the parser state and provide suggestions.
1198 #[instrument(skip(self, seq, snapshot), level = "trace")]
1199 fn maybe_recover_struct_lit_bad_delims(
1203 seq
: &mut PResult
<'a
, P
<Expr
>>,
1204 snapshot
: Option
<(SnapshotParser
<'a
>, ExprKind
)>,
1205 ) -> Option
<P
<Expr
>> {
1206 match (seq
.as_mut(), snapshot
) {
1207 (Err(err
), Some((mut snapshot
, ExprKind
::Path(None
, path
)))) => {
1208 let name
= pprust
::path_to_string(&path
);
1209 snapshot
.bump(); // `(`
1210 match snapshot
.parse_struct_fields(path
, false, Delimiter
::Parenthesis
) {
1212 if snapshot
.eat(&token
::CloseDelim(Delimiter
::Parenthesis
)) =>
1214 // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
1215 // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
1216 self.restore_snapshot(snapshot
);
1217 let close_paren
= self.prev_token
.span
;
1218 let span
= lo
.to(self.prev_token
.span
);
1219 if !fields
.is_empty() {
1220 let replacement_err
= self.struct_span_err(
1222 "invalid `struct` delimiters or `fn` call arguments",
1224 mem
::replace(err
, replacement_err
).cancel();
1226 err
.multipart_suggestion(
1227 &format
!("if `{name}` is a struct, use braces as delimiters"),
1229 (open_paren
, " { ".to_string()),
1230 (close_paren
, " }".to_string()),
1232 Applicability
::MaybeIncorrect
,
1234 err
.multipart_suggestion(
1235 &format
!("if `{name}` is a function, use the arguments directly"),
1238 .map(|field
| (field
.span
.until(field
.expr
.span
), String
::new()))
1240 Applicability
::MaybeIncorrect
,
1246 return Some(self.mk_expr_err(span
));
1259 /// Parse an indexing expression `expr[...]`.
1260 fn parse_index_expr(&mut self, lo
: Span
, base
: P
<Expr
>) -> PResult
<'a
, P
<Expr
>> {
1262 let index
= self.parse_expr()?
;
1263 self.expect(&token
::CloseDelim(Delimiter
::Bracket
))?
;
1264 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), self.mk_index(base
, index
), AttrVec
::new()))
1267 /// Assuming we have just parsed `.`, continue parsing into an expression.
1268 fn parse_dot_suffix(&mut self, self_arg
: P
<Expr
>, lo
: Span
) -> PResult
<'a
, P
<Expr
>> {
1269 if self.token
.uninterpolated_span().rust_2018() && self.eat_keyword(kw
::Await
) {
1270 return Ok(self.mk_await_expr(self_arg
, lo
));
1273 let fn_span_lo
= self.token
.span
;
1274 let mut segment
= self.parse_path_segment(PathStyle
::Expr
, None
)?
;
1275 self.check_trailing_angle_brackets(&segment
, &[&token
::OpenDelim(Delimiter
::Parenthesis
)]);
1276 self.check_turbofish_missing_angle_brackets(&mut segment
);
1278 if self.check(&token
::OpenDelim(Delimiter
::Parenthesis
)) {
1279 // Method call `expr.f()`
1280 let mut args
= self.parse_paren_expr_seq()?
;
1281 args
.insert(0, self_arg
);
1283 let fn_span
= fn_span_lo
.to(self.prev_token
.span
);
1284 let span
= lo
.to(self.prev_token
.span
);
1285 Ok(self.mk_expr(span
, ExprKind
::MethodCall(segment
, args
, fn_span
), AttrVec
::new()))
1287 // Field access `expr.f`
1288 if let Some(args
) = segment
.args
{
1289 self.struct_span_err(
1291 "field expressions cannot have generic arguments",
1296 let span
= lo
.to(self.prev_token
.span
);
1297 Ok(self.mk_expr(span
, ExprKind
::Field(self_arg
, segment
.ident
), AttrVec
::new()))
1301 /// At the bottom (top?) of the precedence hierarchy,
1302 /// Parses things like parenthesized exprs, macros, `return`, etc.
1304 /// N.B., this does not parse outer attributes, and is private because it only works
1305 /// correctly if called from `parse_dot_or_call_expr()`.
1306 fn parse_bottom_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
1307 maybe_recover_from_interpolated_ty_qpath
!(self, true);
1308 maybe_whole_expr
!(self);
1310 // Outer attributes are already parsed and will be
1311 // added to the return value after the fact.
1313 // Therefore, prevent sub-parser from parsing
1314 // attributes by giving them an empty "already-parsed" list.
1315 let attrs
= AttrVec
::new();
1317 // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`.
1318 let lo
= self.token
.span
;
1319 if let token
::Literal(_
) = self.token
.kind
{
1320 // This match arm is a special-case of the `_` match arm below and
1321 // could be removed without changing functionality, but it's faster
1322 // to have it here, especially for programs with large constants.
1323 self.parse_lit_expr(attrs
)
1324 } else if self.check(&token
::OpenDelim(Delimiter
::Parenthesis
)) {
1325 self.parse_tuple_parens_expr(attrs
)
1326 } else if self.check(&token
::OpenDelim(Delimiter
::Brace
)) {
1327 self.parse_block_expr(None
, lo
, BlockCheckMode
::Default
, attrs
)
1328 } else if self.check(&token
::BinOp(token
::Or
)) || self.check(&token
::OrOr
) {
1329 self.parse_closure_expr(attrs
).map_err(|mut err
| {
1330 // If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
1331 // then suggest parens around the lhs.
1332 if let Some(sp
) = self.sess
.ambiguous_block_expr_parse
.borrow().get(&lo
) {
1333 self.sess
.expr_parentheses_needed(&mut err
, *sp
);
1337 } else if self.check(&token
::OpenDelim(Delimiter
::Bracket
)) {
1338 self.parse_array_or_repeat_expr(attrs
, Delimiter
::Bracket
)
1339 } else if self.check_path() {
1340 self.parse_path_start_expr(attrs
)
1341 } else if self.check_keyword(kw
::Move
) || self.check_keyword(kw
::Static
) {
1342 self.parse_closure_expr(attrs
)
1343 } else if self.eat_keyword(kw
::If
) {
1344 self.parse_if_expr(attrs
)
1345 } else if self.check_keyword(kw
::For
) {
1346 if self.choose_generics_over_qpath(1) {
1347 self.parse_closure_expr(attrs
)
1349 assert
!(self.eat_keyword(kw
::For
));
1350 self.parse_for_expr(None
, self.prev_token
.span
, attrs
)
1352 } else if self.eat_keyword(kw
::While
) {
1353 self.parse_while_expr(None
, self.prev_token
.span
, attrs
)
1354 } else if let Some(label
) = self.eat_label() {
1355 self.parse_labeled_expr(label
, attrs
, true)
1356 } else if self.eat_keyword(kw
::Loop
) {
1357 let sp
= self.prev_token
.span
;
1358 self.parse_loop_expr(None
, self.prev_token
.span
, attrs
).map_err(|mut err
| {
1359 err
.span_label(sp
, "while parsing this `loop` expression");
1362 } else if self.eat_keyword(kw
::Continue
) {
1363 let kind
= ExprKind
::Continue(self.eat_label());
1364 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), kind
, attrs
))
1365 } else if self.eat_keyword(kw
::Match
) {
1366 let match_sp
= self.prev_token
.span
;
1367 self.parse_match_expr(attrs
).map_err(|mut err
| {
1368 err
.span_label(match_sp
, "while parsing this `match` expression");
1371 } else if self.eat_keyword(kw
::Unsafe
) {
1372 let sp
= self.prev_token
.span
;
1373 self.parse_block_expr(None
, lo
, BlockCheckMode
::Unsafe(ast
::UserProvided
), attrs
)
1374 .map_err(|mut err
| {
1375 err
.span_label(sp
, "while parsing this `unsafe` expression");
1378 } else if self.check_inline_const(0) {
1379 self.parse_const_block(lo
.to(self.token
.span
), false)
1380 } else if self.is_do_catch_block() {
1381 self.recover_do_catch(attrs
)
1382 } else if self.is_try_block() {
1383 self.expect_keyword(kw
::Try
)?
;
1384 self.parse_try_block(lo
, attrs
)
1385 } else if self.eat_keyword(kw
::Return
) {
1386 self.parse_return_expr(attrs
)
1387 } else if self.eat_keyword(kw
::Break
) {
1388 self.parse_break_expr(attrs
)
1389 } else if self.eat_keyword(kw
::Yield
) {
1390 self.parse_yield_expr(attrs
)
1391 } else if self.is_do_yeet() {
1392 self.parse_yeet_expr(attrs
)
1393 } else if self.check_keyword(kw
::Let
) {
1394 self.parse_let_expr(attrs
)
1395 } else if self.eat_keyword(kw
::Underscore
) {
1396 Ok(self.mk_expr(self.prev_token
.span
, ExprKind
::Underscore
, attrs
))
1397 } else if !self.unclosed_delims
.is_empty() && self.check(&token
::Semi
) {
1398 // Don't complain about bare semicolons after unclosed braces
1399 // recovery in order to keep the error count down. Fixing the
1400 // delimiters will possibly also fix the bare semicolon found in
1401 // expression context. For example, silence the following error:
1403 // error: expected expression, found `;`
1407 // | ^ expected expression
1409 Ok(self.mk_expr_err(self.token
.span
))
1410 } else if self.token
.uninterpolated_span().rust_2018() {
1411 // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly.
1412 if self.check_keyword(kw
::Async
) {
1413 if self.is_async_block() {
1414 // Check for `async {` and `async move {`.
1415 self.parse_async_block(attrs
)
1417 self.parse_closure_expr(attrs
)
1419 } else if self.eat_keyword(kw
::Await
) {
1420 self.recover_incorrect_await_syntax(lo
, self.prev_token
.span
, attrs
)
1422 self.parse_lit_expr(attrs
)
1425 self.parse_lit_expr(attrs
)
1429 fn parse_lit_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
1430 let lo
= self.token
.span
;
1431 match self.parse_opt_lit() {
1433 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::Lit(literal
), attrs
);
1434 self.maybe_recover_from_bad_qpath(expr
)
1436 None
=> self.try_macro_suggestion(),
1440 fn parse_tuple_parens_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
1441 let lo
= self.token
.span
;
1442 self.expect(&token
::OpenDelim(Delimiter
::Parenthesis
))?
;
1443 let (es
, trailing_comma
) = match self.parse_seq_to_end(
1444 &token
::CloseDelim(Delimiter
::Parenthesis
),
1445 SeqSep
::trailing_allowed(token
::Comma
),
1446 |p
| p
.parse_expr_catch_underscore(),
1450 return Ok(self.recover_seq_parse_error(Delimiter
::Parenthesis
, lo
, Err(err
)));
1453 let kind
= if es
.len() == 1 && !trailing_comma
{
1454 // `(e)` is parenthesized `e`.
1455 ExprKind
::Paren(es
.into_iter().next().unwrap())
1457 // `(e,)` is a tuple with only one field, `e`.
1460 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), kind
, attrs
);
1461 self.maybe_recover_from_bad_qpath(expr
)
1464 fn parse_array_or_repeat_expr(
1467 close_delim
: Delimiter
,
1468 ) -> PResult
<'a
, P
<Expr
>> {
1469 let lo
= self.token
.span
;
1470 self.bump(); // `[` or other open delim
1472 let close
= &token
::CloseDelim(close_delim
);
1473 let kind
= if self.eat(close
) {
1475 ExprKind
::Array(Vec
::new())
1478 let first_expr
= self.parse_expr()?
;
1479 if self.eat(&token
::Semi
) {
1480 // Repeating array syntax: `[ 0; 512 ]`
1481 let count
= self.parse_anon_const_expr()?
;
1482 self.expect(close
)?
;
1483 ExprKind
::Repeat(first_expr
, count
)
1484 } else if self.eat(&token
::Comma
) {
1485 // Vector with two or more elements.
1486 let sep
= SeqSep
::trailing_allowed(token
::Comma
);
1487 let (remaining_exprs
, _
) = self.parse_seq_to_end(close
, sep
, |p
| p
.parse_expr())?
;
1488 let mut exprs
= vec
![first_expr
];
1489 exprs
.extend(remaining_exprs
);
1490 ExprKind
::Array(exprs
)
1492 // Vector with one element
1493 self.expect(close
)?
;
1494 ExprKind
::Array(vec
![first_expr
])
1497 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), kind
, attrs
);
1498 self.maybe_recover_from_bad_qpath(expr
)
1501 fn parse_path_start_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
1502 let (qself
, path
) = if self.eat_lt() {
1503 let (qself
, path
) = self.parse_qpath(PathStyle
::Expr
)?
;
1506 (None
, self.parse_path(PathStyle
::Expr
)?
)
1510 // `!`, as an operator, is prefix, so we know this isn't that.
1511 let (hi
, kind
) = if self.eat(&token
::Not
) {
1512 // MACRO INVOCATION expression
1513 if qself
.is_some() {
1514 self.struct_span_err(path
.span
, "macros cannot use qualified paths").emit();
1518 args
: self.parse_mac_args()?
,
1519 prior_type_ascription
: self.last_type_ascription
,
1521 (self.prev_token
.span
, ExprKind
::MacCall(mac
))
1522 } else if self.check(&token
::OpenDelim(Delimiter
::Brace
)) {
1523 if let Some(expr
) = self.maybe_parse_struct_expr(qself
.as_ref(), &path
, &attrs
) {
1524 if qself
.is_some() {
1525 self.sess
.gated_spans
.gate(sym
::more_qualified_paths
, path
.span
);
1529 (path
.span
, ExprKind
::Path(qself
, path
))
1532 (path
.span
, ExprKind
::Path(qself
, path
))
1535 let expr
= self.mk_expr(lo
.to(hi
), kind
, attrs
);
1536 self.maybe_recover_from_bad_qpath(expr
)
1539 /// Parse `'label: $expr`. The label is already parsed.
1540 fn parse_labeled_expr(
1544 mut consume_colon
: bool
,
1545 ) -> PResult
<'a
, P
<Expr
>> {
1546 let lo
= label
.ident
.span
;
1547 let label
= Some(label
);
1548 let ate_colon
= self.eat(&token
::Colon
);
1549 let expr
= if self.eat_keyword(kw
::While
) {
1550 self.parse_while_expr(label
, lo
, attrs
)
1551 } else if self.eat_keyword(kw
::For
) {
1552 self.parse_for_expr(label
, lo
, attrs
)
1553 } else if self.eat_keyword(kw
::Loop
) {
1554 self.parse_loop_expr(label
, lo
, attrs
)
1555 } else if self.check_noexpect(&token
::OpenDelim(Delimiter
::Brace
))
1556 || self.token
.is_whole_block()
1558 self.parse_block_expr(label
, lo
, BlockCheckMode
::Default
, attrs
)
1559 } else if !ate_colon
1560 && (self.check_noexpect(&TokenKind
::Comma
) || self.check_noexpect(&TokenKind
::Gt
))
1562 // We're probably inside of a `Path<'a>` that needs a turbofish
1563 let msg
= "expected `while`, `for`, `loop` or `{` after a label";
1564 self.struct_span_err(self.token
.span
, msg
).span_label(self.token
.span
, msg
).emit();
1565 consume_colon
= false;
1566 Ok(self.mk_expr_err(lo
))
1568 let msg
= "expected `while`, `for`, `loop` or `{` after a label";
1570 let mut err
= self.struct_span_err(self.token
.span
, msg
);
1571 err
.span_label(self.token
.span
, msg
);
1573 // Continue as an expression in an effort to recover on `'label: non_block_expr`.
1574 let expr
= self.parse_expr().map(|expr
| {
1575 let span
= expr
.span
;
1577 let found_labeled_breaks
= {
1578 struct FindLabeledBreaksVisitor(bool
);
1580 impl<'ast
> Visitor
<'ast
> for FindLabeledBreaksVisitor
{
1581 fn visit_expr_post(&mut self, ex
: &'ast Expr
) {
1582 if let ExprKind
::Break(Some(_label
), _
) = ex
.kind
{
1588 let mut vis
= FindLabeledBreaksVisitor(false);
1589 vis
.visit_expr(&expr
);
1593 // Suggestion involves adding a (as of time of writing this, unstable) labeled block.
1595 // If there are no breaks that may use this label, suggest removing the label and
1596 // recover to the unmodified expression.
1597 if !found_labeled_breaks
{
1598 let msg
= "consider removing the label";
1599 err
.span_suggestion_verbose(
1603 Applicability
::MachineApplicable
,
1609 let sugg_msg
= "consider enclosing expression in a block";
1610 let suggestions
= vec
![
1611 (span
.shrink_to_lo(), "{ ".to_owned()),
1612 (span
.shrink_to_hi(), " }".to_owned()),
1615 err
.multipart_suggestion_verbose(
1618 Applicability
::MachineApplicable
,
1621 // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to supress future errors about `break 'label`.
1622 let stmt
= self.mk_stmt(span
, StmtKind
::Expr(expr
));
1623 let blk
= self.mk_block(vec
![stmt
], BlockCheckMode
::Default
, span
);
1624 self.mk_expr(span
, ExprKind
::Block(blk
, label
), ThinVec
::new())
1631 if !ate_colon
&& consume_colon
{
1632 self.error_labeled_expr_must_be_followed_by_colon(lo
, expr
.span
);
1638 fn error_labeled_expr_must_be_followed_by_colon(&self, lo
: Span
, span
: Span
) {
1639 self.struct_span_err(span
, "labeled expression must be followed by `:`")
1640 .span_label(lo
, "the label")
1641 .span_suggestion_short(
1643 "add `:` after the label",
1645 Applicability
::MachineApplicable
,
1647 .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them")
1651 /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
1652 fn recover_do_catch(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
1653 let lo
= self.token
.span
;
1655 self.bump(); // `do`
1656 self.bump(); // `catch`
1658 let span_dc
= lo
.to(self.prev_token
.span
);
1659 self.struct_span_err(span_dc
, "found removed `do catch` syntax")
1662 "replace with the new syntax",
1664 Applicability
::MachineApplicable
,
1666 .note("following RFC #2388, the new non-placeholder syntax is `try`")
1669 self.parse_try_block(lo
, attrs
)
1672 /// Parse an expression if the token can begin one.
1673 fn parse_expr_opt(&mut self) -> PResult
<'a
, Option
<P
<Expr
>>> {
1674 Ok(if self.token
.can_begin_expr() { Some(self.parse_expr()?) }
else { None }
)
1677 /// Parse `"return" expr?`.
1678 fn parse_return_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
1679 let lo
= self.prev_token
.span
;
1680 let kind
= ExprKind
::Ret(self.parse_expr_opt()?
);
1681 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), kind
, attrs
);
1682 self.maybe_recover_from_bad_qpath(expr
)
1685 /// Parse `"do" "yeet" expr?`.
1686 fn parse_yeet_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
1687 let lo
= self.token
.span
;
1689 self.bump(); // `do`
1690 self.bump(); // `yeet`
1692 let kind
= ExprKind
::Yeet(self.parse_expr_opt()?
);
1694 let span
= lo
.to(self.prev_token
.span
);
1695 self.sess
.gated_spans
.gate(sym
::yeet_expr
, span
);
1696 let expr
= self.mk_expr(span
, kind
, attrs
);
1697 self.maybe_recover_from_bad_qpath(expr
)
1700 /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
1701 /// If the label is followed immediately by a `:` token, the label and `:` are
1702 /// parsed as part of the expression (i.e. a labeled loop). The language team has
1703 /// decided in #87026 to require parentheses as a visual aid to avoid confusion if
1704 /// the break expression of an unlabeled break is a labeled loop (as in
1705 /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
1706 /// expression only gets a warning for compatibility reasons; and a labeled break
1707 /// with a labeled loop does not even get a warning because there is no ambiguity.
1708 fn parse_break_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
1709 let lo
= self.prev_token
.span
;
1710 let mut label
= self.eat_label();
1711 let kind
= if label
.is_some() && self.token
== token
::Colon
{
1712 // The value expression can be a labeled loop, see issue #86948, e.g.:
1713 // `loop { break 'label: loop { break 'label 42; }; }`
1714 let lexpr
= self.parse_labeled_expr(label
.take().unwrap(), AttrVec
::new(), true)?
;
1715 self.struct_span_err(
1717 "parentheses are required around this expression to avoid confusion with a labeled break expression",
1719 .multipart_suggestion(
1720 "wrap the expression in parentheses",
1722 (lexpr
.span
.shrink_to_lo(), "(".to_string()),
1723 (lexpr
.span
.shrink_to_hi(), ")".to_string()),
1725 Applicability
::MachineApplicable
,
1729 } else if self.token
!= token
::OpenDelim(Delimiter
::Brace
)
1730 || !self.restrictions
.contains(Restrictions
::NO_STRUCT_LITERAL
)
1732 let expr
= self.parse_expr_opt()?
;
1733 if let Some(ref expr
) = expr
{
1737 ExprKind
::While(_
, _
, None
)
1738 | ExprKind
::ForLoop(_
, _
, _
, None
)
1739 | ExprKind
::Loop(_
, None
)
1740 | ExprKind
::Block(_
, None
)
1743 self.sess
.buffer_lint_with_diagnostic(
1744 BREAK_WITH_LABEL_AND_LOOP
,
1747 "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression",
1748 BuiltinLintDiagnostics
::BreakWithLabelAndLoop(expr
.span
),
1756 let expr
= self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::Break(label
, kind
), attrs
);
1757 self.maybe_recover_from_bad_qpath(expr
)
1760 /// Parse `"yield" expr?`.
1761 fn parse_yield_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
1762 let lo
= self.prev_token
.span
;
1763 let kind
= ExprKind
::Yield(self.parse_expr_opt()?
);
1764 let span
= lo
.to(self.prev_token
.span
);
1765 self.sess
.gated_spans
.gate(sym
::generators
, span
);
1766 let expr
= self.mk_expr(span
, kind
, attrs
);
1767 self.maybe_recover_from_bad_qpath(expr
)
1770 /// Returns a string literal if the next token is a string literal.
1771 /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
1772 /// and returns `None` if the next token is not literal at all.
1773 pub fn parse_str_lit(&mut self) -> Result
<ast
::StrLit
, Option
<Lit
>> {
1774 match self.parse_opt_lit() {
1775 Some(lit
) => match lit
.kind
{
1776 ast
::LitKind
::Str(symbol_unescaped
, style
) => Ok(ast
::StrLit
{
1778 symbol
: lit
.token
.symbol
,
1779 suffix
: lit
.token
.suffix
,
1783 _
=> Err(Some(lit
)),
1789 pub(super) fn parse_lit(&mut self) -> PResult
<'a
, Lit
> {
1790 self.parse_opt_lit().ok_or_else(|| {
1791 if let token
::Interpolated(inner
) = &self.token
.kind
{
1792 let expr
= match inner
.as_ref() {
1793 token
::NtExpr(expr
) => Some(expr
),
1794 token
::NtLiteral(expr
) => Some(expr
),
1797 if let Some(expr
) = expr
{
1798 if matches
!(expr
.kind
, ExprKind
::Err
) {
1801 .struct_span_err(self.token
.span
, "invalid interpolated expression");
1802 err
.downgrade_to_delayed_bug();
1807 let msg
= format
!("unexpected token: {}", super::token_descr(&self.token
));
1808 self.struct_span_err(self.token
.span
, &msg
)
1812 /// Matches `lit = true | false | token_lit`.
1813 /// Returns `None` if the next token is not a literal.
1814 pub(super) fn parse_opt_lit(&mut self) -> Option
<Lit
> {
1815 let mut recovered
= None
;
1816 if self.token
== token
::Dot
{
1817 // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where
1818 // dot would follow an optional literal, so we do this unconditionally.
1819 recovered
= self.look_ahead(1, |next_token
| {
1820 if let token
::Literal(token
::Lit { kind: token::Integer, symbol, suffix }
) =
1823 if self.token
.span
.hi() == next_token
.span
.lo() {
1824 let s
= String
::from("0.") + symbol
.as_str();
1825 let kind
= TokenKind
::lit(token
::Float
, Symbol
::intern(&s
), suffix
);
1826 return Some(Token
::new(kind
, self.token
.span
.to(next_token
.span
)));
1831 if let Some(token
) = &recovered
{
1833 self.error_float_lits_must_have_int_part(&token
);
1837 let token
= recovered
.as_ref().unwrap_or(&self.token
);
1838 match Lit
::from_token(token
) {
1843 Err(LitError
::NotLiteral
) => None
,
1845 let span
= token
.span
;
1846 let token
::Literal(lit
) = token
.kind
else {
1850 self.report_lit_error(err
, lit
, span
);
1851 // Pack possible quotes and prefixes from the original literal into
1852 // the error literal's symbol so they can be pretty-printed faithfully.
1853 let suffixless_lit
= token
::Lit
::new(lit
.kind
, lit
.symbol
, None
);
1854 let symbol
= Symbol
::intern(&suffixless_lit
.to_string());
1855 let lit
= token
::Lit
::new(token
::Err
, symbol
, lit
.suffix
);
1856 Some(Lit
::from_lit_token(lit
, span
).unwrap_or_else(|_
| unreachable
!()))
1861 fn error_float_lits_must_have_int_part(&self, token
: &Token
) {
1862 self.struct_span_err(token
.span
, "float literals must have an integer part")
1865 "must have an integer part",
1866 pprust
::token_to_string(token
),
1867 Applicability
::MachineApplicable
,
1872 fn report_lit_error(&self, err
: LitError
, lit
: token
::Lit
, span
: Span
) {
1873 // Checks if `s` looks like i32 or u1234 etc.
1874 fn looks_like_width_suffix(first_chars
: &[char], s
: &str) -> bool
{
1875 s
.len() > 1 && s
.starts_with(first_chars
) && s
[1..].chars().all(|c
| c
.is_ascii_digit())
1878 // Try to lowercase the prefix if it's a valid base prefix.
1879 fn fix_base_capitalisation(s
: &str) -> Option
<String
> {
1880 if let Some(stripped
) = s
.strip_prefix('B'
) {
1881 Some(format
!("0b{stripped}"))
1882 } else if let Some(stripped
) = s
.strip_prefix('O'
) {
1883 Some(format
!("0o{stripped}"))
1884 } else if let Some(stripped
) = s
.strip_prefix('X'
) {
1885 Some(format
!("0x{stripped}"))
1891 let token
::Lit { kind, suffix, .. }
= lit
;
1893 // `NotLiteral` is not an error by itself, so we don't report
1894 // it and give the parser opportunity to try something else.
1895 LitError
::NotLiteral
=> {}
1896 // `LexerError` *is* an error, but it was already reported
1897 // by lexer, so here we don't report it the second time.
1898 LitError
::LexerError
=> {}
1899 LitError
::InvalidSuffix
=> {
1900 self.expect_no_suffix(
1902 &format
!("{} {} literal", kind
.article(), kind
.descr()),
1906 LitError
::InvalidIntSuffix
=> {
1907 let suf
= suffix
.expect("suffix error with no suffix");
1908 let suf
= suf
.as_str();
1909 if looks_like_width_suffix(&['i'
, 'u'
], &suf
) {
1910 // If it looks like a width, try to be helpful.
1911 let msg
= format
!("invalid width `{}` for integer literal", &suf
[1..]);
1912 self.struct_span_err(span
, &msg
)
1913 .help("valid widths are 8, 16, 32, 64 and 128")
1915 } else if let Some(fixed
) = fix_base_capitalisation(suf
) {
1916 let msg
= "invalid base prefix for number literal";
1918 self.struct_span_err(span
, msg
)
1919 .note("base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase")
1922 "try making the prefix lowercase",
1924 Applicability
::MaybeIncorrect
,
1928 let msg
= format
!("invalid suffix `{suf}` for number literal");
1929 self.struct_span_err(span
, &msg
)
1930 .span_label(span
, format
!("invalid suffix `{suf}`"))
1931 .help("the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)")
1935 LitError
::InvalidFloatSuffix
=> {
1936 let suf
= suffix
.expect("suffix error with no suffix");
1937 let suf
= suf
.as_str();
1938 if looks_like_width_suffix(&['f'
], suf
) {
1939 // If it looks like a width, try to be helpful.
1940 let msg
= format
!("invalid width `{}` for float literal", &suf
[1..]);
1941 self.struct_span_err(span
, &msg
).help("valid widths are 32 and 64").emit();
1943 let msg
= format
!("invalid suffix `{suf}` for float literal");
1944 self.struct_span_err(span
, &msg
)
1945 .span_label(span
, format
!("invalid suffix `{suf}`"))
1946 .help("valid suffixes are `f32` and `f64`")
1950 LitError
::NonDecimalFloat(base
) => {
1951 let descr
= match base
{
1952 16 => "hexadecimal",
1955 _
=> unreachable
!(),
1957 self.struct_span_err(span
, &format
!("{descr} float literal is not supported"))
1958 .span_label(span
, "not supported")
1961 LitError
::IntTooLarge
=> {
1962 self.struct_span_err(span
, "integer literal is too large").emit();
1967 pub(super) fn expect_no_suffix(&self, sp
: Span
, kind
: &str, suffix
: Option
<Symbol
>) {
1968 if let Some(suf
) = suffix
{
1969 let mut err
= if kind
== "a tuple index"
1970 && [sym
::i32, sym
::u32, sym
::isize, sym
::usize].contains(&suf
)
1972 // #59553: warn instead of reject out of hand to allow the fix to percolate
1973 // through the ecosystem when people fix their macros
1977 .struct_span_warn(sp
, &format
!("suffixes on {kind} are invalid"));
1979 "`{}` is *temporarily* accepted on tuple index fields as it was \
1980 incorrectly accepted on stable for a few releases",
1984 "on proc macros, you'll want to use `syn::Index::from` or \
1985 `proc_macro::Literal::*_unsuffixed` for code that will desugar \
1986 to tuple field access",
1989 "see issue #60210 <https://github.com/rust-lang/rust/issues/60210> \
1990 for more information",
1994 self.struct_span_err(sp
, &format
!("suffixes on {kind} are invalid"))
1997 err
.span_label(sp
, format
!("invalid suffix `{suf}`"));
2002 /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
2003 /// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
2004 pub fn parse_literal_maybe_minus(&mut self) -> PResult
<'a
, P
<Expr
>> {
2005 maybe_whole_expr
!(self);
2007 let lo
= self.token
.span
;
2008 let minus_present
= self.eat(&token
::BinOp(token
::Minus
));
2009 let lit
= self.parse_lit()?
;
2010 let expr
= self.mk_expr(lit
.span
, ExprKind
::Lit(lit
), AttrVec
::new());
2014 lo
.to(self.prev_token
.span
),
2015 self.mk_unary(UnOp
::Neg
, expr
),
2023 fn is_array_like_block(&mut self) -> bool
{
2024 self.look_ahead(1, |t
| matches
!(t
.kind
, TokenKind
::Ident(..) | TokenKind
::Literal(_
)))
2025 && self.look_ahead(2, |t
| t
== &token
::Comma
)
2026 && self.look_ahead(3, |t
| t
.can_begin_expr())
2029 /// Emits a suggestion if it looks like the user meant an array but
2030 /// accidentally used braces, causing the code to be interpreted as a block
2032 fn maybe_suggest_brackets_instead_of_braces(
2036 ) -> Option
<P
<Expr
>> {
2037 let mut snapshot
= self.create_snapshot_for_diagnostic();
2038 match snapshot
.parse_array_or_repeat_expr(attrs
, Delimiter
::Brace
) {
2040 let hi
= snapshot
.prev_token
.span
;
2041 self.struct_span_err(arr
.span
, "this is a block expression, not an array")
2042 .multipart_suggestion(
2043 "to make an array, use square brackets instead of curly braces",
2044 vec
![(lo
, "[".to_owned()), (hi
, "]".to_owned())],
2045 Applicability
::MaybeIncorrect
,
2049 self.restore_snapshot(snapshot
);
2050 Some(self.mk_expr_err(arr
.span
))
2059 /// Parses a block or unsafe block.
2060 pub(super) fn parse_block_expr(
2062 opt_label
: Option
<Label
>,
2064 blk_mode
: BlockCheckMode
,
2066 ) -> PResult
<'a
, P
<Expr
>> {
2067 if self.is_array_like_block() {
2068 if let Some(arr
) = self.maybe_suggest_brackets_instead_of_braces(lo
, attrs
.clone()) {
2073 if let Some(label
) = opt_label
{
2074 self.sess
.gated_spans
.gate(sym
::label_break_value
, label
.ident
.span
);
2077 if self.token
.is_whole_block() {
2078 self.struct_span_err(self.token
.span
, "cannot use a `block` macro fragment here")
2079 .span_label(lo
.to(self.token
.span
), "the `block` fragment is within this context")
2083 let (inner_attrs
, blk
) = self.parse_block_common(lo
, blk_mode
)?
;
2084 attrs
.extend(inner_attrs
);
2085 Ok(self.mk_expr(blk
.span
, ExprKind
::Block(blk
, opt_label
), attrs
))
2088 /// Parse a block which takes no attributes and has no label
2089 fn parse_simple_block(&mut self) -> PResult
<'a
, P
<Expr
>> {
2090 let blk
= self.parse_block()?
;
2091 Ok(self.mk_expr(blk
.span
, ExprKind
::Block(blk
, None
), AttrVec
::new()))
2094 /// Parses a closure expression (e.g., `move |args| expr`).
2095 fn parse_closure_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
2096 let lo
= self.token
.span
;
2098 let binder
= if self.check_keyword(kw
::For
) {
2099 let lo
= self.token
.span
;
2100 let lifetime_defs
= self.parse_late_bound_lifetime_defs()?
;
2101 let span
= lo
.to(self.prev_token
.span
);
2103 self.sess
.gated_spans
.gate(sym
::closure_lifetime_binder
, span
);
2105 ClosureBinder
::For { span, generic_params: P::from_vec(lifetime_defs) }
2107 ClosureBinder
::NotPresent
2111 if self.eat_keyword(kw
::Static
) { Movability::Static }
else { Movability::Movable }
;
2113 let asyncness
= if self.token
.uninterpolated_span().rust_2018() {
2114 self.parse_asyncness()
2119 let capture_clause
= self.parse_capture_clause()?
;
2120 let decl
= self.parse_fn_block_decl()?
;
2121 let decl_hi
= self.prev_token
.span
;
2122 let mut body
= match decl
.output
{
2123 FnRetTy
::Default(_
) => {
2124 let restrictions
= self.restrictions
- Restrictions
::STMT_EXPR
;
2125 self.parse_expr_res(restrictions
, None
)?
2128 // If an explicit return type is given, require a block to appear (RFC 968).
2129 let body_lo
= self.token
.span
;
2130 self.parse_block_expr(None
, body_lo
, BlockCheckMode
::Default
, AttrVec
::new())?
2134 if let Async
::Yes { span, .. }
= asyncness
{
2135 // Feature-gate `async ||` closures.
2136 self.sess
.gated_spans
.gate(sym
::async_closure
, span
);
2139 if self.token
.kind
== TokenKind
::Semi
2140 && matches
!(self.token_cursor
.frame
.delim_sp
, Some((Delimiter
::Parenthesis
, _
)))
2142 // It is likely that the closure body is a block but where the
2143 // braces have been removed. We will recover and eat the next
2144 // statements later in the parsing process.
2145 body
= self.mk_expr_err(body
.span
);
2148 let body_span
= body
.span
;
2150 let closure
= self.mk_expr(
2164 // Disable recovery for closure body
2166 ClosureSpans { whole_closure: closure.span, closing_pipe: decl_hi, body: body_span }
;
2167 self.current_closure
= Some(spans
);
2172 /// Parses an optional `move` prefix to a closure-like construct.
2173 fn parse_capture_clause(&mut self) -> PResult
<'a
, CaptureBy
> {
2174 if self.eat_keyword(kw
::Move
) {
2175 // Check for `move async` and recover
2176 if self.check_keyword(kw
::Async
) {
2177 let move_async_span
= self.token
.span
.with_lo(self.prev_token
.span
.data().lo
);
2178 Err(self.incorrect_move_async_order_found(move_async_span
))
2180 Ok(CaptureBy
::Value
)
2187 /// Parses the `|arg, arg|` header of a closure.
2188 fn parse_fn_block_decl(&mut self) -> PResult
<'a
, P
<FnDecl
>> {
2189 let inputs
= if self.eat(&token
::OrOr
) {
2192 self.expect(&token
::BinOp(token
::Or
))?
;
2194 .parse_seq_to_before_tokens(
2195 &[&token
::BinOp(token
::Or
), &token
::OrOr
],
2196 SeqSep
::trailing_allowed(token
::Comma
),
2197 TokenExpectType
::NoExpect
,
2198 |p
| p
.parse_fn_block_param(),
2205 self.parse_ret_ty(AllowPlus
::Yes
, RecoverQPath
::Yes
, RecoverReturnSign
::Yes
)?
;
2207 Ok(P(FnDecl { inputs, output }
))
2210 /// Parses a parameter in a closure header (e.g., `|arg, arg|`).
2211 fn parse_fn_block_param(&mut self) -> PResult
<'a
, Param
> {
2212 let lo
= self.token
.span
;
2213 let attrs
= self.parse_outer_attributes()?
;
2214 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
2215 let pat
= this
.parse_pat_no_top_alt(PARAM_EXPECTED
)?
;
2216 let ty
= if this
.eat(&token
::Colon
) {
2219 this
.mk_ty(this
.prev_token
.span
, TyKind
::Infer
)
2224 attrs
: attrs
.into(),
2227 span
: lo
.to(this
.token
.span
),
2229 is_placeholder
: false,
2231 TrailingToken
::MaybeComma
,
2236 /// Parses an `if` expression (`if` token already eaten).
2237 fn parse_if_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
2238 let lo
= self.prev_token
.span
;
2239 let cond
= self.parse_cond_expr()?
;
2241 self.parse_if_after_cond(attrs
, lo
, cond
)
2244 fn parse_if_after_cond(
2249 ) -> PResult
<'a
, P
<Expr
>> {
2250 let cond_span
= cond
.span
;
2251 // Tries to interpret `cond` as either a missing expression if it's a block,
2252 // or as an unfinished expression if it's a binop and the RHS is a block.
2253 // We could probably add more recoveries here too...
2254 let mut recover_block_from_condition
= |this
: &mut Self| {
2255 let block
= match &mut cond
.kind
{
2256 ExprKind
::Binary(Spanned { span: binop_span, .. }
, _
, right
)
2257 if let ExprKind
::Block(_
, None
) = right
.kind
=> {
2258 this
.error_missing_if_then_block(lo
, cond_span
.shrink_to_lo().to(*binop_span
), true).emit();
2259 std
::mem
::replace(right
, this
.mk_expr_err(binop_span
.shrink_to_hi()))
2261 ExprKind
::Block(_
, None
) => {
2262 this
.error_missing_if_cond(lo
, cond_span
).emit();
2263 std
::mem
::replace(&mut cond
, this
.mk_expr_err(cond_span
.shrink_to_hi()))
2269 if let ExprKind
::Block(block
, _
) = &block
.kind
{
2276 let thn
= if self.token
.is_keyword(kw
::Else
) {
2277 if let Some(block
) = recover_block_from_condition(self) {
2280 self.error_missing_if_then_block(lo
, cond_span
, false).emit();
2281 self.mk_block_err(cond_span
.shrink_to_hi())
2284 let attrs
= self.parse_outer_attributes()?
.take_for_recovery(); // For recovery.
2285 let block
= if self.check(&token
::OpenDelim(Delimiter
::Brace
)) {
2288 if let Some(block
) = recover_block_from_condition(self) {
2291 // Parse block, which will always fail, but we can add a nice note to the error
2292 self.parse_block().map_err(|mut err
| {
2295 "the `if` expression is missing a block after this condition",
2301 self.error_on_if_block_attrs(lo
, false, block
.span
, &attrs
);
2304 let els
= if self.eat_keyword(kw
::Else
) { Some(self.parse_else_expr()?) }
else { None }
;
2305 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::If(cond
, thn
, els
), attrs
))
2308 fn error_missing_if_then_block(
2312 is_unfinished
: bool
,
2313 ) -> DiagnosticBuilder
<'a
, ErrorGuaranteed
> {
2314 let mut err
= self.struct_span_err(
2316 "this `if` expression is missing a block after the condition",
2319 err
.span_help(cond_span
, "this binary operation is possibly unfinished");
2321 err
.span_help(cond_span
.shrink_to_hi(), "add a block here");
2326 fn error_missing_if_cond(
2330 ) -> DiagnosticBuilder
<'a
, ErrorGuaranteed
> {
2331 let next_span
= self.sess
.source_map().next_point(lo
);
2332 let mut err
= self.struct_span_err(next_span
, "missing condition for `if` expression");
2333 err
.span_label(next_span
, "expected condition here");
2335 self.sess
.source_map().start_point(span
),
2336 "if this block is the condition of the `if` expression, then it must be followed by another block"
2341 /// Parses the condition of a `if` or `while` expression.
2342 fn parse_cond_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
2343 let cond
= self.parse_expr_res(Restrictions
::NO_STRUCT_LITERAL
| Restrictions
::ALLOW_LET
, None
)?
;
2345 if let ExprKind
::Let(..) = cond
.kind
{
2346 // Remove the last feature gating of a `let` expression since it's stable.
2347 self.sess
.gated_spans
.ungate_last(sym
::let_chains
, cond
.span
);
2353 /// Parses a `let $pat = $expr` pseudo-expression.
2354 fn parse_let_expr(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
2355 // This is a *approximate* heuristic that detects if `let` chains are
2356 // being parsed in the right position. It's approximate because it
2357 // doesn't deny all invalid `let` expressions, just completely wrong usages.
2358 let not_in_chain
= !matches
!(
2359 self.prev_token
.kind
,
2360 TokenKind
::AndAnd
| TokenKind
::Ident(kw
::If
, _
) | TokenKind
::Ident(kw
::While
, _
)
2362 if !self.restrictions
.contains(Restrictions
::ALLOW_LET
) || not_in_chain
{
2363 self.struct_span_err(self.token
.span
, "expected expression, found `let` statement")
2367 self.bump(); // Eat `let` token
2368 let lo
= self.prev_token
.span
;
2369 let pat
= self.parse_pat_allow_top_alt(
2373 CommaRecoveryMode
::LikelyTuple
,
2375 self.expect(&token
::Eq
)?
;
2376 let expr
= self.with_res(self.restrictions
| Restrictions
::NO_STRUCT_LITERAL
, |this
| {
2377 this
.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None
.into())
2379 let span
= lo
.to(expr
.span
);
2380 self.sess
.gated_spans
.gate(sym
::let_chains
, span
);
2381 Ok(self.mk_expr(span
, ExprKind
::Let(pat
, expr
, span
), attrs
))
2384 /// Parses an `else { ... }` expression (`else` token already eaten).
2385 fn parse_else_expr(&mut self) -> PResult
<'a
, P
<Expr
>> {
2386 let else_span
= self.prev_token
.span
; // `else`
2387 let attrs
= self.parse_outer_attributes()?
.take_for_recovery(); // For recovery.
2388 let expr
= if self.eat_keyword(kw
::If
) {
2389 self.parse_if_expr(AttrVec
::new())?
2390 } else if self.check(&TokenKind
::OpenDelim(Delimiter
::Brace
)) {
2391 self.parse_simple_block()?
2393 let snapshot
= self.create_snapshot_for_diagnostic();
2394 let first_tok
= super::token_descr(&self.token
);
2395 let first_tok_span
= self.token
.span
;
2396 match self.parse_expr() {
2398 // If it's not a free-standing expression, and is followed by a block,
2399 // then it's very likely the condition to an `else if`.
2400 if self.check(&TokenKind
::OpenDelim(Delimiter
::Brace
))
2401 && classify
::expr_requires_semi_to_be_stmt(&cond
) =>
2403 self.struct_span_err(first_tok_span
, format
!("expected `{{`, found {first_tok}"))
2404 .span_label(else_span
, "expected an `if` or a block after this `else`")
2406 cond
.span
.shrink_to_lo(),
2407 "add an `if` if this is the condition of a chained `else if` statement",
2409 Applicability
::MaybeIncorrect
,
2412 self.parse_if_after_cond(AttrVec
::new(), cond
.span
.shrink_to_lo(), cond
)?
2416 self.restore_snapshot(snapshot
);
2417 self.parse_simple_block()?
2420 self.restore_snapshot(snapshot
);
2421 self.parse_simple_block()?
2425 self.error_on_if_block_attrs(else_span
, true, expr
.span
, &attrs
);
2429 fn error_on_if_block_attrs(
2434 attrs
: &[ast
::Attribute
],
2436 let (span
, last
) = match attrs
{
2438 [x0 @ xn
] | [x0
, .., xn
] => (x0
.span
.to(xn
.span
), xn
.span
),
2440 let ctx
= if is_ctx_else { "else" }
else { "if" }
;
2441 self.struct_span_err(last
, "outer attributes are not allowed on `if` and `else` branches")
2442 .span_label(branch_span
, "the attributes are attached to this branch")
2443 .span_label(ctx_span
, format
!("the branch belongs to this `{ctx}`"))
2444 .span_suggestion(span
, "remove the attributes", "", Applicability
::MachineApplicable
)
2448 /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
2451 opt_label
: Option
<Label
>,
2454 ) -> PResult
<'a
, P
<Expr
>> {
2455 // Record whether we are about to parse `for (`.
2456 // This is used below for recovery in case of `for ( $stuff ) $block`
2457 // in which case we will suggest `for $stuff $block`.
2458 let begin_paren
= match self.token
.kind
{
2459 token
::OpenDelim(Delimiter
::Parenthesis
) => Some(self.token
.span
),
2463 let pat
= self.parse_pat_allow_top_alt(
2467 CommaRecoveryMode
::LikelyTuple
,
2469 if !self.eat_keyword(kw
::In
) {
2470 self.error_missing_in_for_loop();
2472 self.check_for_for_in_in_typo(self.prev_token
.span
);
2473 let expr
= self.parse_expr_res(Restrictions
::NO_STRUCT_LITERAL
, None
)?
;
2475 let pat
= self.recover_parens_around_for_head(pat
, begin_paren
);
2477 let (iattrs
, loop_block
) = self.parse_inner_attrs_and_block()?
;
2478 attrs
.extend(iattrs
);
2480 let kind
= ExprKind
::ForLoop(pat
, expr
, loop_block
, opt_label
);
2481 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), kind
, attrs
))
2484 fn error_missing_in_for_loop(&mut self) {
2485 let (span
, msg
, sugg
) = if self.token
.is_ident_named(sym
::of
) {
2486 // Possibly using JS syntax (#75311).
2487 let span
= self.token
.span
;
2489 (span
, "try using `in` here instead", "in")
2491 (self.prev_token
.span
.between(self.token
.span
), "try adding `in` here", " in ")
2493 self.struct_span_err(span
, "missing `in` in `for` loop")
2494 .span_suggestion_short(
2498 // Has been misleading, at least in the past (closed Issue #48492).
2499 Applicability
::MaybeIncorrect
,
2504 /// Parses a `while` or `while let` expression (`while` token already eaten).
2505 fn parse_while_expr(
2507 opt_label
: Option
<Label
>,
2510 ) -> PResult
<'a
, P
<Expr
>> {
2511 let cond
= self.parse_cond_expr().map_err(|mut err
| {
2512 err
.span_label(lo
, "while parsing the condition of this `while` expression");
2515 let (iattrs
, body
) = self.parse_inner_attrs_and_block().map_err(|mut err
| {
2516 err
.span_label(lo
, "while parsing the body of this `while` expression");
2517 err
.span_label(cond
.span
, "this `while` condition successfully parsed");
2520 attrs
.extend(iattrs
);
2521 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::While(cond
, body
, opt_label
), attrs
))
2524 /// Parses `loop { ... }` (`loop` token already eaten).
2527 opt_label
: Option
<Label
>,
2530 ) -> PResult
<'a
, P
<Expr
>> {
2531 let (iattrs
, body
) = self.parse_inner_attrs_and_block()?
;
2532 attrs
.extend(iattrs
);
2533 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), ExprKind
::Loop(body
, opt_label
), attrs
))
2536 pub(crate) fn eat_label(&mut self) -> Option
<Label
> {
2537 self.token
.lifetime().map(|ident
| {
2543 /// Parses a `match ... { ... }` expression (`match` token already eaten).
2544 fn parse_match_expr(&mut self, mut attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
2545 let match_span
= self.prev_token
.span
;
2546 let lo
= self.prev_token
.span
;
2547 let scrutinee
= self.parse_expr_res(Restrictions
::NO_STRUCT_LITERAL
, None
)?
;
2548 if let Err(mut e
) = self.expect(&token
::OpenDelim(Delimiter
::Brace
)) {
2549 if self.token
== token
::Semi
{
2550 e
.span_suggestion_short(
2552 "try removing this `match`",
2554 Applicability
::MaybeIncorrect
, // speculative
2557 if self.maybe_recover_unexpected_block_label() {
2564 attrs
.extend(self.parse_inner_attributes()?
);
2566 let mut arms
: Vec
<Arm
> = Vec
::new();
2567 while self.token
!= token
::CloseDelim(Delimiter
::Brace
) {
2568 match self.parse_arm() {
2569 Ok(arm
) => arms
.push(arm
),
2571 // Recover by skipping to the end of the block.
2573 self.recover_stmt();
2574 let span
= lo
.to(self.token
.span
);
2575 if self.token
== token
::CloseDelim(Delimiter
::Brace
) {
2578 return Ok(self.mk_expr(span
, ExprKind
::Match(scrutinee
, arms
), attrs
));
2582 let hi
= self.token
.span
;
2584 Ok(self.mk_expr(lo
.to(hi
), ExprKind
::Match(scrutinee
, arms
), attrs
))
2587 /// Attempt to recover from match arm body with statements and no surrounding braces.
2588 fn parse_arm_body_missing_braces(
2590 first_expr
: &P
<Expr
>,
2592 ) -> Option
<P
<Expr
>> {
2593 if self.token
.kind
!= token
::Semi
{
2596 let start_snapshot
= self.create_snapshot_for_diagnostic();
2597 let semi_sp
= self.token
.span
;
2600 vec
![self.mk_stmt(first_expr
.span
, ast
::StmtKind
::Expr(first_expr
.clone()))];
2601 let err
= |this
: &mut Parser
<'_
>, stmts
: Vec
<ast
::Stmt
>| {
2602 let span
= stmts
[0].span
.to(stmts
[stmts
.len() - 1].span
);
2603 let mut err
= this
.struct_span_err(span
, "`match` arm body without braces");
2604 let (these
, s
, are
) =
2605 if stmts
.len() > 1 { ("these", "s", "are") }
else { ("this", "", "is") }
;
2609 "{these} statement{s} {are} not surrounded by a body",
2615 err
.span_label(arrow_span
, "while parsing the `match` arm starting here");
2616 if stmts
.len() > 1 {
2617 err
.multipart_suggestion(
2618 &format
!("surround the statement{s} with a body"),
2620 (span
.shrink_to_lo(), "{ ".to_string()),
2621 (span
.shrink_to_hi(), " }".to_string()),
2623 Applicability
::MachineApplicable
,
2626 err
.span_suggestion(
2628 "use a comma to end a `match` arm expression",
2630 Applicability
::MachineApplicable
,
2634 this
.mk_expr_err(span
)
2636 // We might have either a `,` -> `;` typo, or a block without braces. We need
2637 // a more subtle parsing strategy.
2639 if self.token
.kind
== token
::CloseDelim(Delimiter
::Brace
) {
2640 // We have reached the closing brace of the `match` expression.
2641 return Some(err(self, stmts
));
2643 if self.token
.kind
== token
::Comma
{
2644 self.restore_snapshot(start_snapshot
);
2647 let pre_pat_snapshot
= self.create_snapshot_for_diagnostic();
2648 match self.parse_pat_no_top_alt(None
) {
2650 if self.token
.kind
== token
::FatArrow
{
2652 self.restore_snapshot(pre_pat_snapshot
);
2653 return Some(err(self, stmts
));
2661 self.restore_snapshot(pre_pat_snapshot
);
2662 match self.parse_stmt_without_recovery(true, ForceCollect
::No
) {
2663 // Consume statements for as long as possible.
2668 self.restore_snapshot(start_snapshot
);
2671 // We couldn't parse either yet another statement missing it's
2672 // enclosing block nor the next arm's pattern or closing brace.
2675 self.restore_snapshot(start_snapshot
);
2683 pub(super) fn parse_arm(&mut self) -> PResult
<'a
, Arm
> {
2684 // Used to check the `let_chains` and `if_let_guard` features mostly by scaning
2686 fn check_let_expr(expr
: &Expr
) -> (bool
, bool
) {
2688 ExprKind
::Binary(BinOp { node: BinOpKind::And, .. }
, ref lhs
, ref rhs
) => {
2689 let lhs_rslt
= check_let_expr(lhs
);
2690 let rhs_rslt
= check_let_expr(rhs
);
2691 (lhs_rslt
.0 || rhs_rslt
.0, false)
2693 ExprKind
::Let(..) => (true, true),
2697 let attrs
= self.parse_outer_attributes()?
;
2698 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
2699 let lo
= this
.token
.span
;
2700 let pat
= this
.parse_pat_allow_top_alt(
2704 CommaRecoveryMode
::EitherTupleOrPipe
,
2706 let guard
= if this
.eat_keyword(kw
::If
) {
2707 let if_span
= this
.prev_token
.span
;
2708 let cond
= this
.parse_expr_res(Restrictions
::ALLOW_LET
, None
)?
;
2709 let (has_let_expr
, does_not_have_bin_op
) = check_let_expr(&cond
);
2711 if does_not_have_bin_op
{
2712 // Remove the last feature gating of a `let` expression since it's stable.
2713 this
.sess
.gated_spans
.ungate_last(sym
::let_chains
, cond
.span
);
2715 let span
= if_span
.to(cond
.span
);
2716 this
.sess
.gated_spans
.gate(sym
::if_let_guard
, span
);
2722 let arrow_span
= this
.token
.span
;
2723 if let Err(mut err
) = this
.expect(&token
::FatArrow
) {
2724 // We might have a `=>` -> `=` or `->` typo (issue #89396).
2725 if TokenKind
::FatArrow
2727 .map_or(false, |similar_tokens
| similar_tokens
.contains(&this
.token
.kind
))
2729 err
.span_suggestion(
2731 "try using a fat arrow here",
2733 Applicability
::MaybeIncorrect
,
2741 let arm_start_span
= this
.token
.span
;
2743 let expr
= this
.parse_expr_res(Restrictions
::STMT_EXPR
, None
).map_err(|mut err
| {
2744 err
.span_label(arrow_span
, "while parsing the `match` arm starting here");
2748 let require_comma
= classify
::expr_requires_semi_to_be_stmt(&expr
)
2749 && this
.token
!= token
::CloseDelim(Delimiter
::Brace
);
2751 let hi
= this
.prev_token
.span
;
2754 let sm
= this
.sess
.source_map();
2755 if let Some(body
) = this
.parse_arm_body_missing_braces(&expr
, arrow_span
) {
2756 let span
= body
.span
;
2759 attrs
: attrs
.into(),
2765 is_placeholder
: false,
2767 TrailingToken
::None
,
2770 this
.expect_one_of(&[token
::Comma
], &[token
::CloseDelim(Delimiter
::Brace
)])
2771 .or_else(|mut err
| {
2772 if this
.token
== token
::FatArrow
{
2773 if let Ok(expr_lines
) = sm
.span_to_lines(expr
.span
)
2774 && let Ok(arm_start_lines
) = sm
.span_to_lines(arm_start_span
)
2775 && arm_start_lines
.lines
[0].end_col
== expr_lines
.lines
[0].end_col
2776 && expr_lines
.lines
.len() == 2
2778 // We check whether there's any trailing code in the parse span,
2779 // if there isn't, we very likely have the following:
2782 // | -- - missing comma
2786 // | - ^^ self.token.span
2788 // | parsed until here as `"y" & X`
2789 err
.span_suggestion_short(
2790 arm_start_span
.shrink_to_hi(),
2791 "missing a comma here to end this `match` arm",
2793 Applicability
::MachineApplicable
,
2798 // FIXME(compiler-errors): We could also recover `; PAT =>` here
2800 // Try to parse a following `PAT =>`, if successful
2801 // then we should recover.
2802 let mut snapshot
= this
.create_snapshot_for_diagnostic();
2803 let pattern_follows
= snapshot
2804 .parse_pat_allow_top_alt(
2808 CommaRecoveryMode
::EitherTupleOrPipe
,
2810 .map_err(|err
| err
.cancel())
2812 if pattern_follows
&& snapshot
.check(&TokenKind
::FatArrow
) {
2814 this
.struct_span_err(
2816 "expected `,` following `match` arm",
2820 "missing a comma here to end this `match` arm",
2822 Applicability
::MachineApplicable
,
2828 err
.span_label(arrow_span
, "while parsing the `match` arm starting here");
2832 this
.eat(&token
::Comma
);
2837 attrs
: attrs
.into(),
2843 is_placeholder
: false,
2845 TrailingToken
::None
,
2850 /// Parses a `try {...}` expression (`try` token already eaten).
2851 fn parse_try_block(&mut self, span_lo
: Span
, mut attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
2852 let (iattrs
, body
) = self.parse_inner_attrs_and_block()?
;
2853 attrs
.extend(iattrs
);
2854 if self.eat_keyword(kw
::Catch
) {
2855 let mut error
= self.struct_span_err(
2856 self.prev_token
.span
,
2857 "keyword `catch` cannot follow a `try` block",
2859 error
.help("try using `match` on the result of the `try` block instead");
2863 let span
= span_lo
.to(body
.span
);
2864 self.sess
.gated_spans
.gate(sym
::try_blocks
, span
);
2865 Ok(self.mk_expr(span
, ExprKind
::TryBlock(body
), attrs
))
2869 fn is_do_catch_block(&self) -> bool
{
2870 self.token
.is_keyword(kw
::Do
)
2871 && self.is_keyword_ahead(1, &[kw
::Catch
])
2872 && self.look_ahead(2, |t
| *t
== token
::OpenDelim(Delimiter
::Brace
))
2873 && !self.restrictions
.contains(Restrictions
::NO_STRUCT_LITERAL
)
2876 fn is_do_yeet(&self) -> bool
{
2877 self.token
.is_keyword(kw
::Do
) && self.is_keyword_ahead(1, &[kw
::Yeet
])
2880 fn is_try_block(&self) -> bool
{
2881 self.token
.is_keyword(kw
::Try
)
2882 && self.look_ahead(1, |t
| *t
== token
::OpenDelim(Delimiter
::Brace
))
2883 && self.token
.uninterpolated_span().rust_2018()
2886 /// Parses an `async move? {...}` expression.
2887 fn parse_async_block(&mut self, mut attrs
: AttrVec
) -> PResult
<'a
, P
<Expr
>> {
2888 let lo
= self.token
.span
;
2889 self.expect_keyword(kw
::Async
)?
;
2890 let capture_clause
= self.parse_capture_clause()?
;
2891 let (iattrs
, body
) = self.parse_inner_attrs_and_block()?
;
2892 attrs
.extend(iattrs
);
2893 let kind
= ExprKind
::Async(capture_clause
, DUMMY_NODE_ID
, body
);
2894 Ok(self.mk_expr(lo
.to(self.prev_token
.span
), kind
, attrs
))
2897 fn is_async_block(&self) -> bool
{
2898 self.token
.is_keyword(kw
::Async
)
2901 self.is_keyword_ahead(1, &[kw
::Move
])
2902 && self.look_ahead(2, |t
| *t
== token
::OpenDelim(Delimiter
::Brace
))
2905 self.look_ahead(1, |t
| *t
== token
::OpenDelim(Delimiter
::Brace
))
2909 fn is_certainly_not_a_block(&self) -> bool
{
2910 self.look_ahead(1, |t
| t
.is_ident())
2912 // `{ ident, ` cannot start a block.
2913 self.look_ahead(2, |t
| t
== &token
::Comma
)
2914 || self.look_ahead(2, |t
| t
== &token
::Colon
)
2916 // `{ ident: token, ` cannot start a block.
2917 self.look_ahead(4, |t
| t
== &token
::Comma
) ||
2918 // `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`.
2919 self.look_ahead(3, |t
| !t
.can_begin_type())
2924 fn maybe_parse_struct_expr(
2926 qself
: Option
<&ast
::QSelf
>,
2929 ) -> Option
<PResult
<'a
, P
<Expr
>>> {
2930 let struct_allowed
= !self.restrictions
.contains(Restrictions
::NO_STRUCT_LITERAL
);
2931 if struct_allowed
|| self.is_certainly_not_a_block() {
2932 if let Err(err
) = self.expect(&token
::OpenDelim(Delimiter
::Brace
)) {
2933 return Some(Err(err
));
2935 let expr
= self.parse_struct_expr(qself
.cloned(), path
.clone(), attrs
.clone(), true);
2936 if let (Ok(expr
), false) = (&expr
, struct_allowed
) {
2937 // This is a struct literal, but we don't can't accept them here.
2938 self.error_struct_lit_not_allowed_here(path
.span
, expr
.span
);
2945 fn error_struct_lit_not_allowed_here(&self, lo
: Span
, sp
: Span
) {
2946 self.struct_span_err(sp
, "struct literals are not allowed here")
2947 .multipart_suggestion(
2948 "surround the struct literal with parentheses",
2949 vec
![(lo
.shrink_to_lo(), "(".to_string()), (sp
.shrink_to_hi(), ")".to_string())],
2950 Applicability
::MachineApplicable
,
2955 pub(super) fn parse_struct_fields(
2959 close_delim
: Delimiter
,
2960 ) -> PResult
<'a
, (Vec
<ExprField
>, ast
::StructRest
, bool
)> {
2961 let mut fields
= Vec
::new();
2962 let mut base
= ast
::StructRest
::None
;
2963 let mut recover_async
= false;
2965 let mut async_block_err
= |e
: &mut Diagnostic
, span
: Span
| {
2966 recover_async
= true;
2967 e
.span_label(span
, "`async` blocks are only allowed in Rust 2018 or later");
2968 e
.help_use_latest_edition();
2971 while self.token
!= token
::CloseDelim(close_delim
) {
2972 if self.eat(&token
::DotDot
) {
2973 let exp_span
= self.prev_token
.span
;
2974 // We permit `.. }` on the left-hand side of a destructuring assignment.
2975 if self.check(&token
::CloseDelim(close_delim
)) {
2976 base
= ast
::StructRest
::Rest(self.prev_token
.span
.shrink_to_hi());
2979 match self.parse_expr() {
2980 Ok(e
) => base
= ast
::StructRest
::Base(e
),
2981 Err(mut e
) if recover
=> {
2983 self.recover_stmt();
2985 Err(e
) => return Err(e
),
2987 self.recover_struct_comma_after_dotdot(exp_span
);
2991 let recovery_field
= self.find_struct_error_after_field_looking_code();
2992 let parsed_field
= match self.parse_expr_field() {
2995 if pth
== kw
::Async
{
2996 async_block_err(&mut e
, pth
.span
);
2998 e
.span_label(pth
.span
, "while parsing this struct");
3002 // If the next token is a comma, then try to parse
3003 // what comes next as additional fields, rather than
3004 // bailing out until next `}`.
3005 if self.token
!= token
::Comma
{
3006 self.recover_stmt_(SemiColonMode
::Comma
, BlockMode
::Ignore
);
3007 if self.token
!= token
::Comma
{
3015 let is_shorthand
= parsed_field
.as_ref().map_or(false, |f
| f
.is_shorthand
);
3016 // A shorthand field can be turned into a full field with `:`.
3017 // We should point this out.
3018 self.check_or_expected(!is_shorthand
, TokenType
::Token(token
::Colon
));
3020 match self.expect_one_of(&[token
::Comma
], &[token
::CloseDelim(close_delim
)]) {
3022 if let Some(f
) = parsed_field
.or(recovery_field
) {
3023 // Only include the field if there's no parse error for the field name.
3028 if pth
== kw
::Async
{
3029 async_block_err(&mut e
, pth
.span
);
3031 e
.span_label(pth
.span
, "while parsing this struct");
3032 if let Some(f
) = recovery_field
{
3035 self.prev_token
.span
.shrink_to_hi(),
3036 "try adding a comma",
3038 Applicability
::MachineApplicable
,
3040 } else if is_shorthand
3041 && (AssocOp
::from_token(&self.token
).is_some()
3042 || matches
!(&self.token
.kind
, token
::OpenDelim(_
))
3043 || self.token
.kind
== token
::Dot
)
3045 // Looks like they tried to write a shorthand, complex expression.
3046 let ident
= parsed_field
.expect("is_shorthand implies Some").ident
;
3048 ident
.span
.shrink_to_lo(),
3049 "try naming a field",
3050 &format
!("{ident}: "),
3051 Applicability
::HasPlaceholders
,
3059 self.recover_stmt_(SemiColonMode
::Comma
, BlockMode
::Ignore
);
3060 self.eat(&token
::Comma
);
3064 Ok((fields
, base
, recover_async
))
3067 /// Precondition: already parsed the '{'.
3068 pub(super) fn parse_struct_expr(
3070 qself
: Option
<ast
::QSelf
>,
3074 ) -> PResult
<'a
, P
<Expr
>> {
3076 let (fields
, base
, recover_async
) =
3077 self.parse_struct_fields(pth
.clone(), recover
, Delimiter
::Brace
)?
;
3078 let span
= lo
.to(self.token
.span
);
3079 self.expect(&token
::CloseDelim(Delimiter
::Brace
))?
;
3080 let expr
= if recover_async
{
3083 ExprKind
::Struct(P(ast
::StructExpr { qself, path: pth, fields, rest: base }
))
3085 Ok(self.mk_expr(span
, expr
, attrs
))
3088 /// Use in case of error after field-looking code: `S { foo: () with a }`.
3089 fn find_struct_error_after_field_looking_code(&self) -> Option
<ExprField
> {
3090 match self.token
.ident() {
3091 Some((ident
, is_raw
))
3092 if (is_raw
|| !ident
.is_reserved())
3093 && self.look_ahead(1, |t
| *t
== token
::Colon
) =>
3095 Some(ast
::ExprField
{
3097 span
: self.token
.span
,
3098 expr
: self.mk_expr_err(self.token
.span
),
3099 is_shorthand
: false,
3100 attrs
: AttrVec
::new(),
3102 is_placeholder
: false,
3109 fn recover_struct_comma_after_dotdot(&mut self, span
: Span
) {
3110 if self.token
!= token
::Comma
{
3113 self.struct_span_err(
3114 span
.to(self.prev_token
.span
),
3115 "cannot use a comma after the base struct",
3117 .span_suggestion_short(
3119 "remove this comma",
3121 Applicability
::MachineApplicable
,
3123 .note("the base struct must always be the last field")
3125 self.recover_stmt();
3128 /// Parses `ident (COLON expr)?`.
3129 fn parse_expr_field(&mut self) -> PResult
<'a
, ExprField
> {
3130 let attrs
= self.parse_outer_attributes()?
;
3131 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
3132 let lo
= this
.token
.span
;
3134 // Check if a colon exists one ahead. This means we're parsing a fieldname.
3135 let is_shorthand
= !this
.look_ahead(1, |t
| t
== &token
::Colon
|| t
== &token
::Eq
);
3136 let (ident
, expr
) = if is_shorthand
{
3137 // Mimic `x: x` for the `x` field shorthand.
3138 let ident
= this
.parse_ident_common(false)?
;
3139 let path
= ast
::Path
::from_ident(ident
);
3140 (ident
, this
.mk_expr(ident
.span
, ExprKind
::Path(None
, path
), AttrVec
::new()))
3142 let ident
= this
.parse_field_name()?
;
3143 this
.error_on_eq_field_init(ident
);
3145 (ident
, this
.parse_expr()?
)
3151 span
: lo
.to(expr
.span
),
3154 attrs
: attrs
.into(),
3156 is_placeholder
: false,
3158 TrailingToken
::MaybeComma
,
3163 /// Check for `=`. This means the source incorrectly attempts to
3164 /// initialize a field with an eq rather than a colon.
3165 fn error_on_eq_field_init(&self, field_name
: Ident
) {
3166 if self.token
!= token
::Eq
{
3170 self.struct_span_err(self.token
.span
, "expected `:`, found `=`")
3172 field_name
.span
.shrink_to_hi().to(self.token
.span
),
3173 "replace equals symbol with a colon",
3175 Applicability
::MachineApplicable
,
3180 fn err_dotdotdot_syntax(&self, span
: Span
) {
3181 self.struct_span_err(span
, "unexpected token: `...`")
3184 "use `..` for an exclusive range",
3186 Applicability
::MaybeIncorrect
,
3190 "or `..=` for an inclusive range",
3192 Applicability
::MaybeIncorrect
,
3197 fn err_larrow_operator(&self, span
: Span
) {
3198 self.struct_span_err(span
, "unexpected token: `<-`")
3201 "if you meant to write a comparison against a negative value, add a \
3202 space in between `<` and `-`",
3204 Applicability
::MaybeIncorrect
,
3209 fn mk_assign_op(&self, binop
: BinOp
, lhs
: P
<Expr
>, rhs
: P
<Expr
>) -> ExprKind
{
3210 ExprKind
::AssignOp(binop
, lhs
, rhs
)
3215 start
: Option
<P
<Expr
>>,
3216 end
: Option
<P
<Expr
>>,
3217 limits
: RangeLimits
,
3219 if end
.is_none() && limits
== RangeLimits
::Closed
{
3220 self.inclusive_range_with_incorrect_end(self.prev_token
.span
);
3223 ExprKind
::Range(start
, end
, limits
)
3227 fn mk_unary(&self, unop
: UnOp
, expr
: P
<Expr
>) -> ExprKind
{
3228 ExprKind
::Unary(unop
, expr
)
3231 fn mk_binary(&self, binop
: BinOp
, lhs
: P
<Expr
>, rhs
: P
<Expr
>) -> ExprKind
{
3232 ExprKind
::Binary(binop
, lhs
, rhs
)
3235 fn mk_index(&self, expr
: P
<Expr
>, idx
: P
<Expr
>) -> ExprKind
{
3236 ExprKind
::Index(expr
, idx
)
3239 fn mk_call(&self, f
: P
<Expr
>, args
: Vec
<P
<Expr
>>) -> ExprKind
{
3240 ExprKind
::Call(f
, args
)
3243 fn mk_await_expr(&mut self, self_arg
: P
<Expr
>, lo
: Span
) -> P
<Expr
> {
3244 let span
= lo
.to(self.prev_token
.span
);
3245 let await_expr
= self.mk_expr(span
, ExprKind
::Await(self_arg
), AttrVec
::new());
3246 self.recover_from_await_method_call();
3250 pub(crate) fn mk_expr(&self, span
: Span
, kind
: ExprKind
, attrs
: AttrVec
) -> P
<Expr
> {
3251 P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }
)
3254 pub(super) fn mk_expr_err(&self, span
: Span
) -> P
<Expr
> {
3255 self.mk_expr(span
, ExprKind
::Err
, AttrVec
::new())
3258 /// Create expression span ensuring the span of the parent node
3259 /// is larger than the span of lhs and rhs, including the attributes.
3260 fn mk_expr_sp(&self, lhs
: &P
<Expr
>, lhs_span
: Span
, rhs_span
: Span
) -> Span
{
3263 .find(|a
| a
.style
== AttrStyle
::Outer
)
3264 .map_or(lhs_span
, |a
| a
.span
)
3268 fn collect_tokens_for_expr(
3271 f
: impl FnOnce(&mut Self, Vec
<ast
::Attribute
>) -> PResult
<'a
, P
<Expr
>>,
3272 ) -> PResult
<'a
, P
<Expr
>> {
3273 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
3274 let res
= f(this
, attrs
)?
;
3275 let trailing
= if this
.restrictions
.contains(Restrictions
::STMT_EXPR
)
3276 && this
.token
.kind
== token
::Semi
3280 // FIXME - pass this through from the place where we know
3281 // we need a comma, rather than assuming that `#[attr] expr,`
3282 // always captures a trailing comma
3283 TrailingToken
::MaybeComma