2023-11-22 23:27:15 +00:00
// ignore-tidy-filelength
2024-06-20 06:06:53 +10:00
2022-08-30 13:19:17 +02:00
use core ::mem ;
2024-11-28 14:03:16 -08:00
use core ::ops ::{ Bound , ControlFlow } ;
2023-01-29 13:37:05 +00:00
2024-07-10 08:17:13 +00:00
use ast ::mut_visit ::{ self , MutVisitor } ;
2024-04-18 21:31:17 +10:00
use ast ::token ::IdentIsRaw ;
2024-05-09 18:44:40 +10:00
use ast ::{ CoroutineKind , ForLoopKind , GenBlockKind , MatchKind , Pat , Path , PathSegment , Recovered } ;
2020-02-29 20:37:32 +03:00
use rustc_ast ::ptr ::P ;
2024-04-18 21:31:17 +10:00
use rustc_ast ::token ::{ self , Delimiter , InvisibleOrigin , MetaVarKind , Token , TokenKind } ;
2024-12-10 19:18:44 +11:00
use rustc_ast ::tokenstream ::TokenTree ;
2022-09-15 20:27:23 +04:00
use rustc_ast ::util ::case ::Case ;
2020-02-29 20:37:32 +03:00
use rustc_ast ::util ::classify ;
2024-11-28 12:47:18 -08:00
use rustc_ast ::util ::parser ::{ AssocOp , ExprPrecedence , Fixity , prec_let_scrutinee_needs_par } ;
2024-02-24 02:52:59 -05:00
use rustc_ast ::visit ::{ Visitor , walk_expr } ;
2022-11-23 15:39:42 +11:00
use rustc_ast ::{
2024-12-20 10:15:05 +11:00
self as ast , AnonConst , Arm , AssignOp , AssignOpKind , AttrStyle , AttrVec , BinOp , BinOpKind ,
BlockCheckMode , CaptureBy , ClosureBinder , DUMMY_NODE_ID , Expr , ExprField , ExprKind , FnDecl ,
FnRetTy , Label , MacCall , MetaItemLit , Movability , Param , RangeLimits , StmtKind , Ty , TyKind ,
UnOp , UnsafeBinderCastKind , YieldKind ,
2022-11-23 15:39:42 +11:00
} ;
2023-08-19 12:55:01 +02:00
use rustc_data_structures ::stack ::ensure_sufficient_stack ;
2024-03-06 14:00:16 +11:00
use rustc_errors ::{ Applicability , Diag , PResult , StashKey , Subdiagnostic } ;
2025-04-04 14:44:45 +02:00
use rustc_literal_escaper ::unescape_char ;
2023-09-08 10:14:36 +00:00
use rustc_macros ::Subdiagnostic ;
2022-10-10 13:40:56 +11:00
use rustc_session ::errors ::{ ExprParenthesesNeeded , report_lit_error } ;
2024-02-29 16:40:44 +11:00
use rustc_session ::lint ::BuiltinLintDiag ;
2021-07-10 16:38:55 +02:00
use rustc_session ::lint ::builtin ::BREAK_WITH_LABEL_AND_LOOP ;
2023-11-02 14:10:12 +11:00
use rustc_span ::source_map ::{ self , Spanned } ;
2024-12-13 10:29:23 +11:00
use rustc_span ::{ BytePos , ErrorGuaranteed , Ident , Pos , Span , Symbol , kw , sym } ;
2022-11-23 11:55:16 +11:00
use thin_vec ::{ ThinVec , thin_vec } ;
2024-05-22 14:42:14 +10:00
use tracing ::instrument ;
2019-08-11 13:14:30 +02:00
2022-08-30 13:19:17 +02:00
use super ::diagnostics ::SnapshotParser ;
2022-11-08 22:03:17 +01:00
use super ::pat ::{ CommaRecoveryMode , Expected , RecoverColon , RecoverComma } ;
2020-10-15 21:21:45 +02:00
use super ::ty ::{ AllowPlus , RecoverQPath , RecoverReturnSign } ;
2021-08-16 15:22:36 +02:00
use super ::{
2024-12-04 15:55:06 +11:00
AttrWrapper , BlockMode , ClosureSpans , ExpTokenPair , ForceCollect , Parser , PathStyle ,
Restrictions , SemiColonMode , SeqSep , TokenType , Trailing , UsePreAttrPos ,
2024-07-29 08:13:50 +10:00
} ;
2024-12-04 15:55:06 +11:00
use crate ::{ errors , exp , maybe_recover_from_interpolated_ty_qpath } ;
2024-07-29 08:13:50 +10:00
2023-06-02 18:51:27 +02:00
#[ derive(Debug) ]
2024-07-04 14:10:17 +02:00
pub ( super ) enum DestructuredFloat {
2023-06-02 18:51:27 +02:00
/// 1e2
Single ( Symbol , Span ) ,
/// 1.
TrailingDot ( Symbol , Span , Span ) ,
/// 1.2 | 1.2e3
MiddleDot ( Symbol , Span , Span , Symbol , Span ) ,
/// Invalid
2024-09-20 13:02:14 +10:00
Error ,
2023-06-02 18:51:27 +02:00
}
2019-08-11 13:14:30 +02:00
impl < ' a > Parser < ' a > {
/// Parses an expression.
#[ inline ]
pub fn parse_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
2021-08-16 15:22:36 +02:00
self . current_closure . take ( ) ;
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
self . parse_expr_res ( Restrictions ::empty ( ) , attrs ) . map ( | res | res . 0 )
2019-08-11 13:14:30 +02:00
}
2024-06-19 17:33:46 +10:00
/// Parses an expression, forcing tokens to be collected.
2021-03-25 18:05:49 -04:00
pub fn parse_expr_force_collect ( & mut self ) -> PResult < ' a , P < Expr > > {
2024-06-19 17:33:46 +10:00
self . current_closure . take ( ) ;
2024-08-06 17:16:40 +10:00
// If the expression is associative (e.g. `1 + 2`), then any preceding
// outer attribute actually belongs to the first inner sub-expression.
// In which case we must use the pre-attr pos to include the attribute
// in the collected tokens for the outer expression.
let pre_attr_pos = self . collect_pos ( ) ;
2024-06-19 17:33:46 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
self . collect_tokens (
Some ( pre_attr_pos ) ,
AttrWrapper ::empty ( ) ,
ForceCollect ::Yes ,
| this , _empty_attrs | {
let ( expr , is_assoc ) = this . parse_expr_res ( Restrictions ::empty ( ) , attrs ) ? ;
let use_pre_attr_pos =
if is_assoc { UsePreAttrPos ::Yes } else { UsePreAttrPos ::No } ;
Ok ( ( expr , Trailing ::No , use_pre_attr_pos ) )
} ,
)
2021-03-25 18:05:49 -04:00
}
2023-02-24 04:38:45 +01:00
pub fn parse_expr_anon_const ( & mut self ) -> PResult < ' a , AnonConst > {
2019-12-08 08:19:53 +01:00
self . parse_expr ( ) . map ( | value | AnonConst { id : DUMMY_NODE_ID , value } )
}
2023-09-08 10:14:36 +00:00
fn parse_expr_catch_underscore ( & mut self , restrictions : Restrictions ) -> PResult < ' a , P < Expr > > {
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
match self . parse_expr_res ( restrictions , attrs ) {
2024-08-06 17:16:40 +10:00
Ok ( ( expr , _ ) ) = > Ok ( expr ) ,
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
Err ( err ) = > match self . token . ident ( ) {
2024-02-13 23:28:27 +00:00
Some ( ( Ident { name : kw ::Underscore , .. } , IdentIsRaw ::No ) )
2022-10-28 20:44:26 +02:00
if self . may_recover ( ) & & self . look_ahead ( 1 , | t | t = = & token ::Comma ) = >
2019-09-16 21:45:43 +01:00
{
// Special-case handling of `foo(_, _, _)`
2024-02-25 22:22:11 +01:00
let guar = err . emit ( ) ;
2019-09-16 21:45:43 +01:00
self . bump ( ) ;
2024-02-25 22:22:11 +01:00
Ok ( self . mk_expr ( self . prev_token . span , ExprKind ::Err ( guar ) ) )
2019-09-16 21:45:43 +01:00
}
_ = > Err ( err ) ,
} ,
}
}
2019-12-08 08:19:53 +01:00
/// Parses a sequence of expressions delimited by parentheses.
2023-02-24 04:38:45 +01:00
fn parse_expr_paren_seq ( & mut self ) -> PResult < ' a , ThinVec < P < Expr > > > {
2023-09-08 10:14:36 +00:00
self . parse_paren_comma_seq ( | p | p . parse_expr_catch_underscore ( Restrictions ::empty ( ) ) )
. map ( | ( r , _ ) | r )
2019-08-11 13:14:30 +02:00
}
/// Parses an expression, subject to the given restrictions.
#[ inline ]
pub ( super ) fn parse_expr_res (
& mut self ,
r : Restrictions ,
2024-06-19 16:24:21 +10:00
attrs : AttrWrapper ,
2024-08-06 17:16:40 +10:00
) -> PResult < ' a , ( P < Expr > , bool ) > {
2024-11-28 14:03:16 -08:00
self . with_res ( r , | this | this . parse_expr_assoc_with ( Bound ::Unbounded , attrs ) )
2019-08-11 13:14:30 +02:00
}
/// Parses an associative expression with operators of at least `min_prec` precedence.
2024-08-06 17:16:40 +10:00
/// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator
/// followed by a subexpression (e.g. `1 + 2`).
2023-02-24 04:38:45 +01:00
pub ( super ) fn parse_expr_assoc_with (
2019-08-11 13:14:30 +02:00
& mut self ,
2024-11-28 12:47:18 -08:00
min_prec : Bound < ExprPrecedence > ,
2024-07-31 12:56:25 +10:00
attrs : AttrWrapper ,
2024-08-06 17:16:40 +10:00
) -> PResult < ' a , ( P < Expr > , bool ) > {
2024-07-31 12:56:25 +10:00
let lhs = if self . token . is_range_separator ( ) {
2024-08-06 17:16:40 +10:00
return self . parse_expr_prefix_range ( attrs ) . map ( | res | ( res , false ) ) ;
2024-07-31 12:56:25 +10:00
} else {
self . parse_expr_prefix ( attrs ) ?
2019-08-11 13:14:30 +02:00
} ;
2024-07-31 12:56:25 +10:00
self . parse_expr_assoc_rest_with ( min_prec , false , lhs )
}
2019-08-11 13:14:30 +02:00
2024-07-31 12:56:25 +10:00
/// Parses the rest of an associative expression (i.e. the part after the lhs) with operators
2024-08-06 17:16:40 +10:00
/// of at least `min_prec` precedence. The `bool` in the return value indicates if something
/// was actually parsed.
2024-07-31 12:56:25 +10:00
pub ( super ) fn parse_expr_assoc_rest_with (
& mut self ,
2024-11-28 12:47:18 -08:00
min_prec : Bound < ExprPrecedence > ,
2024-07-31 12:56:25 +10:00
starts_stmt : bool ,
mut lhs : P < Expr > ,
2024-08-06 17:16:40 +10:00
) -> PResult < ' a , ( P < Expr > , bool ) > {
let mut parsed_something = false ;
2023-12-29 16:41:25 -08:00
if ! self . should_continue_as_assoc_expr ( & lhs ) {
2024-08-06 17:16:40 +10:00
return Ok ( ( lhs , parsed_something ) ) ;
2019-08-11 13:14:30 +02:00
}
2024-12-04 15:55:06 +11:00
self . expected_token_types . insert ( TokenType ::Operator ) ;
2019-12-03 09:04:36 +01:00
while let Some ( op ) = self . check_assoc_op ( ) {
2023-08-15 10:35:42 +10:00
let lhs_span = self . interpolated_or_expr_span ( & lhs ) ;
2019-08-11 13:14:30 +02:00
let cur_op_span = self . token . span ;
2020-01-11 00:19:09 +00:00
let restrictions = if op . node . is_assign_like ( ) {
2019-08-11 13:14:30 +02:00
self . restrictions & Restrictions ::NO_STRUCT_LITERAL
} else {
self . restrictions
} ;
2020-01-11 00:19:09 +00:00
let prec = op . node . precedence ( ) ;
2024-11-28 14:03:16 -08:00
if match min_prec {
Bound ::Included ( min_prec ) = > prec < min_prec ,
Bound ::Excluded ( min_prec ) = > prec < = min_prec ,
Bound ::Unbounded = > false ,
} {
2019-08-11 13:14:30 +02:00
break ;
}
// Check for deprecated `...` syntax
2024-12-19 21:42:46 +11:00
if self . token = = token ::DotDotDot & & op . node = = AssocOp ::Range ( RangeLimits ::Closed ) {
2019-08-11 13:14:30 +02:00
self . err_dotdotdot_syntax ( self . token . span ) ;
}
2019-08-11 23:37:05 +02:00
if self . token = = token ::LArrow {
self . err_larrow_operator ( self . token . span ) ;
}
2024-08-06 17:16:40 +10:00
parsed_something = true ;
2019-08-11 13:14:30 +02:00
self . bump ( ) ;
2020-01-11 00:19:09 +00:00
if op . node . is_comparison ( ) {
2019-09-29 19:07:26 -07:00
if let Some ( expr ) = self . check_no_chained_comparison ( & lhs , & op ) ? {
2024-08-06 17:16:40 +10:00
return Ok ( ( expr , parsed_something ) ) ;
2019-09-29 19:07:26 -07:00
}
2019-08-11 13:14:30 +02:00
}
2020-08-08 21:17:15 -07:00
2021-12-06 18:55:58 +01:00
// Look for JS' `===` and `!==` and recover
2024-12-19 18:24:07 +11:00
if let AssocOp ::Binary ( bop @ BinOpKind ::Eq | bop @ BinOpKind ::Ne ) = op . node
2024-08-09 17:44:47 +10:00
& & self . token = = token ::Eq
2020-08-08 21:17:15 -07:00
& & self . prev_token . span . hi ( ) = = self . token . span . lo ( )
{
let sp = op . span . to ( self . token . span ) ;
2024-12-19 18:24:07 +11:00
let sugg = bop . as_str ( ) . into ( ) ;
2023-07-24 00:18:52 -04:00
let invalid = format! ( " {sugg} = " ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::InvalidComparisonOperator {
2022-08-17 19:05:49 +02:00
span : sp ,
invalid : invalid . clone ( ) ,
2023-02-05 03:26:33 +01:00
sub : errors ::InvalidComparisonOperatorSub ::Correctable {
2022-08-17 19:05:49 +02:00
span : sp ,
invalid ,
correct : sugg ,
} ,
} ) ;
2020-08-08 21:17:15 -07:00
self . bump ( ) ;
}
2021-12-06 18:55:58 +01:00
// Look for PHP's `<>` and recover
2024-12-19 18:24:07 +11:00
if op . node = = AssocOp ::Binary ( BinOpKind ::Lt )
2024-08-09 17:44:47 +10:00
& & self . token = = token ::Gt
2021-12-06 18:55:58 +01:00
& & self . prev_token . span . hi ( ) = = self . token . span . lo ( )
{
let sp = op . span . to ( self . token . span ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::InvalidComparisonOperator {
2022-08-17 19:05:49 +02:00
span : sp ,
invalid : " <> " . into ( ) ,
2023-02-05 03:26:33 +01:00
sub : errors ::InvalidComparisonOperatorSub ::Correctable {
2022-08-17 19:05:49 +02:00
span : sp ,
invalid : " <> " . into ( ) ,
correct : " != " . into ( ) ,
} ,
} ) ;
2021-12-06 18:55:58 +01:00
self . bump ( ) ;
}
// Look for C++'s `<=>` and recover
2024-12-19 18:24:07 +11:00
if op . node = = AssocOp ::Binary ( BinOpKind ::Le )
2024-08-09 17:44:47 +10:00
& & self . token = = token ::Gt
2021-12-06 18:55:58 +01:00
& & self . prev_token . span . hi ( ) = = self . token . span . lo ( )
{
let sp = op . span . to ( self . token . span ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::InvalidComparisonOperator {
2022-08-17 19:05:49 +02:00
span : sp ,
invalid : " <=> " . into ( ) ,
2023-02-05 03:26:33 +01:00
sub : errors ::InvalidComparisonOperatorSub ::Spaceship ( sp ) ,
2022-08-17 19:05:49 +02:00
} ) ;
2021-12-06 18:55:58 +01:00
self . bump ( ) ;
}
2024-12-20 07:28:16 +11:00
if self . prev_token = = token ::Plus
& & self . token = = token ::Plus
2022-02-17 16:30:48 -08:00
& & self . prev_token . span . between ( self . token . span ) . is_empty ( )
2021-09-06 16:16:52 -07:00
{
let op_span = self . prev_token . span . to ( self . token . span ) ;
// Eat the second `+`
self . bump ( ) ;
2022-11-26 05:33:13 +08:00
lhs = self . recover_from_postfix_increment ( lhs , op_span , starts_stmt ) ? ;
2021-09-06 16:16:52 -07:00
continue ;
}
2024-12-20 07:28:16 +11:00
if self . prev_token = = token ::Minus
& & self . token = = token ::Minus
2023-02-26 16:17:23 +00:00
& & self . prev_token . span . between ( self . token . span ) . is_empty ( )
2023-02-27 13:25:03 +00:00
& & ! self . look_ahead ( 1 , | tok | tok . can_begin_expr ( ) )
2023-02-26 16:17:23 +00:00
{
let op_span = self . prev_token . span . to ( self . token . span ) ;
2023-02-26 16:24:08 +00:00
// Eat the second `-`
2023-02-26 16:17:23 +00:00
self . bump ( ) ;
lhs = self . recover_from_postfix_decrement ( lhs , op_span , starts_stmt ) ? ;
continue ;
}
2021-09-06 16:16:52 -07:00
2020-01-11 00:19:09 +00:00
let op = op . node ;
2019-08-11 13:14:30 +02:00
// Special cases:
2024-12-19 21:46:44 +11:00
if op = = AssocOp ::Cast {
2019-08-11 13:14:30 +02:00
lhs = self . parse_assoc_op_cast ( lhs , lhs_span , ExprKind ::Cast ) ? ;
continue ;
2024-12-19 21:42:46 +11:00
} else if let AssocOp ::Range ( limits ) = op {
2022-03-30 17:04:46 -04:00
// If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
2019-08-11 13:14:30 +02:00
// generalise it to the Fixity::None code.
2024-12-19 21:42:46 +11:00
lhs = self . parse_expr_range ( prec , lhs , limits , cur_op_span ) ? ;
2019-08-11 13:14:30 +02:00
break ;
}
2024-12-20 19:50:42 -08:00
let min_prec = match op . fixity ( ) {
2024-11-28 14:03:16 -08:00
Fixity ::Right = > Bound ::Included ( prec ) ,
2024-12-20 19:50:42 -08:00
Fixity ::Left | Fixity ::None = > Bound ::Excluded ( prec ) ,
2019-08-11 13:14:30 +02:00
} ;
2024-08-06 17:16:40 +10:00
let ( rhs , _ ) = self . with_res ( restrictions - Restrictions ::STMT_EXPR , | this | {
2024-06-19 16:06:16 +10:00
let attrs = this . parse_outer_attributes ( ) ? ;
2024-11-28 14:03:16 -08:00
this . parse_expr_assoc_with ( min_prec , attrs )
2019-08-11 13:14:30 +02:00
} ) ? ;
2024-06-06 20:39:54 +00:00
let span = self . mk_expr_sp ( & lhs , lhs_span , rhs . span ) ;
2019-08-11 13:14:30 +02:00
lhs = match op {
2024-12-19 18:24:07 +11:00
AssocOp ::Binary ( ast_op ) = > {
2019-08-11 13:14:30 +02:00
let binary = self . mk_binary ( source_map ::respan ( cur_op_span , ast_op ) , lhs , rhs ) ;
2022-08-15 09:58:38 +10:00
self . mk_expr ( span , binary )
2019-12-22 21:08:53 +00:00
}
2022-08-15 09:58:38 +10:00
AssocOp ::Assign = > self . mk_expr ( span , ExprKind ::Assign ( lhs , rhs , cur_op_span ) ) ,
2024-12-19 16:24:06 +11:00
AssocOp ::AssignOp ( aop ) = > {
2019-08-11 13:14:30 +02:00
let aopexpr = self . mk_assign_op ( source_map ::respan ( cur_op_span , aop ) , lhs , rhs ) ;
2022-08-15 09:58:38 +10:00
self . mk_expr ( span , aopexpr )
2019-08-11 13:14:30 +02:00
}
2024-12-19 21:46:44 +11:00
AssocOp ::Cast | AssocOp ::Range ( _ ) = > {
2023-12-18 21:09:22 +11:00
self . dcx ( ) . span_bug ( span , " AssocOp should have been handled by special case " )
2019-08-11 13:14:30 +02:00
}
} ;
}
2022-11-16 21:46:06 +01:00
2024-08-06 17:16:40 +10:00
Ok ( ( lhs , parsed_something ) )
2019-08-11 13:14:30 +02:00
}
2023-12-29 16:41:25 -08:00
fn should_continue_as_assoc_expr ( & mut self , lhs : & Expr ) -> bool {
match ( self . expr_is_complete ( lhs ) , AssocOp ::from_token ( & self . token ) ) {
2019-12-03 09:04:36 +01:00
// Semi-statement forms are odd:
// See https://github.com/rust-lang/rust/issues/29071
( true , None ) = > false ,
( false , _ ) = > true , // Continue parsing the expression.
// An exhaustive check is done in the following block, but these are checked first
// because they *are* ambiguous but also reasonable looking incorrect syntax, so we
// want to keep their span info to improve diagnostics in these cases in a later stage.
2024-12-19 18:24:07 +11:00
( true , Some ( AssocOp ::Binary (
BinOpKind ::Mul | // `{ 42 } *foo = bar;` or `{ 42 } * 3`
BinOpKind ::Sub | // `{ 42 } -5`
BinOpKind ::Add | // `{ 42 } + 42` (unary plus)
BinOpKind ::And | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
BinOpKind ::Or | // `{ 42 } || 42` ("logical or" or closure)
BinOpKind ::BitOr // `{ 42 } | 42` or `{ 42 } |x| 42`
) ) ) = > {
2019-12-03 09:04:36 +01:00
// These cases are ambiguous and can't be identified in the parser alone.
2022-02-24 17:02:38 -07:00
//
// Bitwise AND is left out because guessing intent is hard. We can make
// suggestions based on the assumption that double-refs are rarely intentional,
// and closures are distinct enough that they don't get mixed up with their
// return value.
2024-03-04 16:31:49 +11:00
let sp = self . psess . source_map ( ) . start_point ( self . token . span ) ;
self . psess . ambiguous_block_expr_parse . borrow_mut ( ) . insert ( sp , lhs . span ) ;
2019-12-03 09:04:36 +01:00
false
}
2022-11-22 09:42:01 +00:00
( true , Some ( op ) ) if ! op . can_continue_expr_unambiguously ( ) = > false ,
2019-12-03 09:04:36 +01:00
( true , Some ( _ ) ) = > {
self . error_found_expr_would_be_stmt ( lhs ) ;
true
}
}
}
/// We've found an expression that would be parsed as a statement,
/// but the next token implies this should be parsed as an expression.
/// For example: `if let Some(x) = x { x } else { 0 } / 2`.
fn error_found_expr_would_be_stmt ( & self , lhs : & Expr ) {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::FoundExprWouldBeStmt {
2022-08-24 22:41:51 +02:00
span : self . token . span ,
2022-09-22 18:39:17 +02:00
token : self . token . clone ( ) ,
2022-08-24 22:41:51 +02:00
suggestion : ExprParenthesesNeeded ::surrounding ( lhs . span ) ,
} ) ;
2019-12-03 09:04:36 +01:00
}
/// Possibly translate the current token to an associative operator.
/// The method does not advance the current token.
///
/// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
2024-06-03 15:47:46 +10:00
pub ( super ) fn check_assoc_op ( & self ) -> Option < Spanned < AssocOp > > {
2020-03-04 23:37:52 +03:00
let ( op , span ) = match ( AssocOp ::from_token ( & self . token ) , self . token . ident ( ) ) {
2020-10-03 19:30:32 +01:00
// When parsing const expressions, stop parsing when encountering `>`.
(
Some (
2024-12-19 18:24:07 +11:00
AssocOp ::Binary ( BinOpKind ::Shr | BinOpKind ::Gt | BinOpKind ::Ge )
2024-12-20 10:15:05 +11:00
| AssocOp ::AssignOp ( AssignOpKind ::ShrAssign ) ,
2020-10-03 19:30:32 +01:00
) ,
_ ,
) if self . restrictions . contains ( Restrictions ::CONST_EXPR ) = > {
return None ;
}
2024-12-19 18:24:07 +11:00
// When recovering patterns as expressions, stop parsing when encountering an
// assignment `=`, an alternative `|`, or a range `..`.
2024-01-28 16:12:21 +01:00
(
Some (
AssocOp ::Assign
| AssocOp ::AssignOp ( _ )
2024-12-19 18:24:07 +11:00
| AssocOp ::Binary ( BinOpKind ::BitOr )
2024-12-19 21:42:46 +11:00
| AssocOp ::Range ( _ ) ,
2024-01-28 16:12:21 +01:00
) ,
_ ,
) if self . restrictions . contains ( Restrictions ::IS_PAT ) = > {
return None ;
}
2020-03-04 23:37:52 +03:00
( Some ( op ) , _ ) = > ( op , self . token . span ) ,
2024-02-13 23:28:27 +00:00
( None , Some ( ( Ident { name : sym ::and , span } , IdentIsRaw ::No ) ) )
if self . may_recover ( ) = >
{
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::InvalidLogicalOperator {
2022-08-17 19:05:49 +02:00
span : self . token . span ,
incorrect : " and " . into ( ) ,
2023-02-05 03:26:33 +01:00
sub : errors ::InvalidLogicalOperatorSub ::Conjunction ( self . token . span ) ,
2022-08-17 19:05:49 +02:00
} ) ;
2024-12-19 18:24:07 +11:00
( AssocOp ::Binary ( BinOpKind ::And ) , span )
2020-03-04 23:37:52 +03:00
}
2024-02-13 23:28:27 +00:00
( None , Some ( ( Ident { name : sym ::or , span } , IdentIsRaw ::No ) ) ) if self . may_recover ( ) = > {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::InvalidLogicalOperator {
2022-08-17 19:05:49 +02:00
span : self . token . span ,
incorrect : " or " . into ( ) ,
2023-02-05 03:26:33 +01:00
sub : errors ::InvalidLogicalOperatorSub ::Disjunction ( self . token . span ) ,
2022-08-17 19:05:49 +02:00
} ) ;
2024-12-19 18:24:07 +11:00
( AssocOp ::Binary ( BinOpKind ::Or ) , span )
2020-03-04 23:37:52 +03:00
}
_ = > return None ,
} ;
Some ( source_map ::respan ( span , op ) )
2019-12-03 10:19:58 +01:00
}
2019-08-11 13:14:30 +02:00
/// Checks if this expression is a successfully parsed statement.
2023-12-29 16:41:25 -08:00
fn expr_is_complete ( & self , e : & Expr ) -> bool {
2024-04-19 18:46:16 -07:00
self . restrictions . contains ( Restrictions ::STMT_EXPR ) & & classify ::expr_is_complete ( e )
2019-08-11 13:14:30 +02:00
}
2019-12-07 04:59:08 +01:00
/// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
/// The other two variants are handled in `parse_prefix_range_expr` below.
2023-02-24 04:38:45 +01:00
fn parse_expr_range (
2019-12-07 04:59:08 +01:00
& mut self ,
2024-11-28 12:47:18 -08:00
prec : ExprPrecedence ,
2019-12-07 04:59:08 +01:00
lhs : P < Expr > ,
2024-12-19 21:42:46 +11:00
limits : RangeLimits ,
2019-12-07 04:59:08 +01:00
cur_op_span : Span ,
) -> PResult < ' a , P < Expr > > {
let rhs = if self . is_at_start_of_range_notation_rhs ( ) {
2023-12-22 21:56:58 -08:00
let maybe_lt = self . token . clone ( ) ;
2024-06-19 16:06:16 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2023-12-22 21:56:58 -08:00
Some (
2024-11-28 14:03:16 -08:00
self . parse_expr_assoc_with ( Bound ::Excluded ( prec ) , attrs )
2024-08-06 17:16:40 +10:00
. map_err ( | err | self . maybe_err_dotdotlt_syntax ( maybe_lt , err ) ) ?
. 0 ,
2023-12-22 21:56:58 -08:00
)
2019-12-07 04:59:08 +01:00
} else {
None
} ;
let rhs_span = rhs . as_ref ( ) . map_or ( cur_op_span , | x | x . span ) ;
2024-06-06 20:39:54 +00:00
let span = self . mk_expr_sp ( & lhs , lhs . span , rhs_span ) ;
2021-06-25 19:46:41 -07:00
let range = self . mk_range ( Some ( lhs ) , rhs , limits ) ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr ( span , range ) )
2019-12-07 04:59:08 +01:00
}
2019-08-11 13:14:30 +02:00
fn is_at_start_of_range_notation_rhs ( & self ) -> bool {
if self . token . can_begin_expr ( ) {
2019-09-06 03:56:45 +01:00
// Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
2022-04-26 15:40:14 +03:00
if self . token = = token ::OpenDelim ( Delimiter ::Brace ) {
2019-08-11 13:14:30 +02:00
return ! self . restrictions . contains ( Restrictions ::NO_STRUCT_LITERAL ) ;
}
true
} else {
false
}
}
2019-09-06 03:56:45 +01:00
/// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
2024-06-19 15:37:31 +10:00
fn parse_expr_prefix_range ( & mut self , attrs : AttrWrapper ) -> PResult < ' a , P < Expr > > {
if ! attrs . is_empty ( ) {
let err = errors ::DotDotRangeAttribute { span : self . token . span } ;
self . dcx ( ) . emit_err ( err ) ;
}
2019-09-06 03:56:45 +01:00
// Check for deprecated `...` syntax.
2019-08-11 13:14:30 +02:00
if self . token = = token ::DotDotDot {
self . err_dotdotdot_syntax ( self . token . span ) ;
}
debug_assert! (
2022-12-16 18:41:08 +05:30
self . token . is_range_separator ( ) ,
2019-08-11 13:14:30 +02:00
" parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq " ,
self . token
) ;
2019-12-07 04:37:05 +01:00
let limits = match self . token . kind {
token ::DotDot = > RangeLimits ::HalfOpen ,
_ = > RangeLimits ::Closed ,
} ;
let op = AssocOp ::from_token ( & self . token ) ;
2024-06-19 15:37:31 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2021-01-22 13:28:08 -05:00
self . collect_tokens_for_expr ( attrs , | this , attrs | {
let lo = this . token . span ;
2023-12-22 21:56:58 -08:00
let maybe_lt = this . look_ahead ( 1 , | t | t . clone ( ) ) ;
2021-01-22 13:28:08 -05:00
this . bump ( ) ;
let ( span , opt_end ) = if this . is_at_start_of_range_notation_rhs ( ) {
// RHS must be parsed with more associativity than the dots.
2024-06-19 16:06:16 +10:00
let attrs = this . parse_outer_attributes ( ) ? ;
2024-11-28 14:03:16 -08:00
this . parse_expr_assoc_with ( Bound ::Excluded ( op . unwrap ( ) . precedence ( ) ) , attrs )
2024-08-06 17:16:40 +10:00
. map ( | ( x , _ ) | ( lo . to ( x . span ) , Some ( x ) ) )
2024-07-31 12:56:25 +10:00
. map_err ( | err | this . maybe_err_dotdotlt_syntax ( maybe_lt , err ) ) ?
2021-01-22 13:28:08 -05:00
} else {
( lo , None )
} ;
2021-06-25 19:46:41 -07:00
let range = this . mk_range ( None , opt_end , limits ) ;
2022-08-15 09:58:38 +10:00
Ok ( this . mk_expr_with_attrs ( span , range , attrs ) )
2021-01-22 13:28:08 -05:00
} )
2019-08-11 13:14:30 +02:00
}
2019-09-06 03:56:45 +01:00
/// Parses a prefix-unary-operator expr.
2024-06-19 14:41:01 +10:00
fn parse_expr_prefix ( & mut self , attrs : AttrWrapper ) -> PResult < ' a , P < Expr > > {
2021-01-22 13:28:08 -05:00
let lo = self . token . span ;
macro_rules ! make_it {
( $this :ident , $attrs :expr , | this , _ | $body :expr ) = > {
$this . collect_tokens_for_expr ( $attrs , | $this , attrs | {
let ( hi , ex ) = $body ? ;
2022-08-15 09:58:38 +10:00
Ok ( $this . mk_expr_with_attrs ( lo . to ( hi ) , ex , attrs ) )
2021-01-22 13:28:08 -05:00
} )
} ;
}
let this = self ;
// Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
match this . token . uninterpolate ( ) . kind {
2023-01-14 11:29:22 +00:00
// `!expr`
2024-12-20 14:04:25 +11:00
token ::Bang = > make_it! ( this , attrs , | this , _ | this . parse_expr_unary ( lo , UnOp ::Not ) ) ,
2023-01-14 11:29:22 +00:00
// `~expr`
token ::Tilde = > make_it! ( this , attrs , | this , _ | this . recover_tilde_expr ( lo ) ) ,
// `-expr`
2024-12-20 07:28:16 +11:00
token ::Minus = > {
2023-02-24 04:38:45 +01:00
make_it! ( this , attrs , | this , _ | this . parse_expr_unary ( lo , UnOp ::Neg ) )
2023-01-14 11:29:22 +00:00
}
// `*expr`
2024-12-20 07:28:16 +11:00
token ::Star = > {
2023-02-24 04:38:45 +01:00
make_it! ( this , attrs , | this , _ | this . parse_expr_unary ( lo , UnOp ::Deref ) )
2023-01-14 11:29:22 +00:00
}
// `&expr` and `&&expr`
2024-12-20 07:28:16 +11:00
token ::And | token ::AndAnd = > {
2023-02-24 04:38:45 +01:00
make_it! ( this , attrs , | this , _ | this . parse_expr_borrow ( lo ) )
2021-01-22 13:28:08 -05:00
}
2023-01-14 11:29:22 +00:00
// `+lit`
2024-12-20 07:28:16 +11:00
token ::Plus if this . look_ahead ( 1 , | tok | tok . is_numeric_lit ( ) ) = > {
2023-02-05 03:26:33 +01:00
let mut err = errors ::LeadingPlusNotSupported {
span : lo ,
remove_plus : None ,
add_parentheses : None ,
} ;
2021-09-01 11:54:06 -04:00
// a block on the LHS might have been intended to be an expression instead
2024-03-04 16:31:49 +11:00
if let Some ( sp ) = this . psess . ambiguous_block_expr_parse . borrow ( ) . get ( & lo ) {
2022-08-24 22:41:51 +02:00
err . add_parentheses = Some ( ExprParenthesesNeeded ::surrounding ( * sp ) ) ;
2021-09-01 11:54:06 -04:00
} else {
2022-08-24 22:41:51 +02:00
err . remove_plus = Some ( lo ) ;
2021-09-01 11:54:06 -04:00
}
2023-12-18 21:14:02 +11:00
this . dcx ( ) . emit_err ( err ) ;
2021-08-31 23:07:58 -04:00
2021-09-01 11:54:06 -04:00
this . bump ( ) ;
2024-06-19 14:41:01 +10:00
let attrs = this . parse_outer_attributes ( ) ? ;
this . parse_expr_prefix ( attrs )
2023-01-14 11:29:22 +00:00
}
2022-02-17 12:28:07 -08:00
// Recover from `++x`:
2024-12-20 07:28:16 +11:00
token ::Plus if this . look_ahead ( 1 , | t | * t = = token ::Plus ) = > {
2022-11-26 05:33:13 +08:00
let starts_stmt = this . prev_token = = token ::Semi
| | this . prev_token = = token ::CloseDelim ( Delimiter ::Brace ) ;
2021-09-06 16:16:52 -07:00
let pre_span = this . token . span . to ( this . look_ahead ( 1 , | t | t . span ) ) ;
// Eat both `+`s.
this . bump ( ) ;
this . bump ( ) ;
2024-06-18 20:00:45 +10:00
let operand_expr = this . parse_expr_dot_or_call ( attrs ) ? ;
2022-11-26 05:33:13 +08:00
this . recover_from_prefix_increment ( operand_expr , pre_span , starts_stmt )
2021-09-06 16:16:52 -07:00
}
2021-01-22 13:28:08 -05:00
token ::Ident ( .. ) if this . token . is_keyword ( kw ::Box ) = > {
2023-02-24 04:38:45 +01:00
make_it! ( this , attrs , | this , _ | this . parse_expr_box ( lo ) )
2021-01-22 13:28:08 -05:00
}
2022-10-28 20:44:26 +02:00
token ::Ident ( .. ) if this . may_recover ( ) & & this . is_mistaken_not_ident_negation ( ) = > {
2021-01-22 13:28:08 -05:00
make_it! ( this , attrs , | this , _ | this . recover_not_expr ( lo ) )
}
2024-06-18 20:00:45 +10:00
_ = > return this . parse_expr_dot_or_call ( attrs ) ,
2021-01-22 13:28:08 -05:00
}
2019-08-11 13:14:30 +02:00
}
2023-02-24 04:38:45 +01:00
fn parse_expr_prefix_common ( & mut self , lo : Span ) -> PResult < ' a , ( Span , P < Expr > ) > {
2019-12-07 03:05:51 +01:00
self . bump ( ) ;
2024-06-19 14:41:01 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-12-29 11:04:49 -08:00
let expr = if self . token . is_range_separator ( ) {
self . parse_expr_prefix_range ( attrs )
} else {
self . parse_expr_prefix ( attrs )
} ? ;
2023-08-15 09:01:22 +10:00
let span = self . interpolated_or_expr_span ( & expr ) ;
2019-12-07 03:07:35 +01:00
Ok ( ( lo . to ( span ) , expr ) )
}
2023-02-24 04:38:45 +01:00
fn parse_expr_unary ( & mut self , lo : Span , op : UnOp ) -> PResult < ' a , ( Span , ExprKind ) > {
let ( span , expr ) = self . parse_expr_prefix_common ( lo ) ? ;
2019-12-07 03:07:35 +01:00
Ok ( ( span , self . mk_unary ( op , expr ) ) )
}
2023-01-14 11:29:22 +00:00
/// Recover on `~expr` in favor of `!expr`.
2019-12-07 03:07:35 +01:00
fn recover_tilde_expr ( & mut self , lo : Span ) -> PResult < ' a , ( Span , ExprKind ) > {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::TildeAsUnaryOperator ( lo ) ) ;
2019-12-07 03:05:51 +01:00
2023-02-24 04:38:45 +01:00
self . parse_expr_unary ( lo , UnOp ::Not )
2019-12-07 03:00:06 +01:00
}
2023-02-27 13:22:43 +00:00
/// Parse `box expr` - this syntax has been removed, but we still parse this
2024-01-17 21:16:22 +00:00
/// for now to provide a more useful error
fn parse_expr_box ( & mut self , box_kw : Span ) -> PResult < ' a , ( Span , ExprKind ) > {
2024-08-01 13:11:24 +00:00
let ( span , expr ) = self . parse_expr_prefix_common ( box_kw ) ? ;
// Make a multipart suggestion instead of `span_to_snippet` in case source isn't available
let box_kw_and_lo = box_kw . until ( self . interpolated_or_expr_span ( & expr ) ) ;
let hi = span . shrink_to_hi ( ) ;
let sugg = errors ::AddBoxNew { box_kw_and_lo , hi } ;
let guar = self . dcx ( ) . emit_err ( errors ::BoxSyntaxRemoved { span , sugg } ) ;
2024-02-25 22:22:11 +01:00
Ok ( ( span , ExprKind ::Err ( guar ) ) )
2019-12-07 02:55:12 +01:00
}
fn is_mistaken_not_ident_negation ( & self ) -> bool {
2020-03-07 15:58:27 +03:00
let token_cannot_continue_expr = | t : & Token | match t . uninterpolate ( ) . kind {
2019-12-07 02:55:12 +01:00
// These tokens can start an expression after `!`, but
// can't continue an expression after an ident
token ::Ident ( name , is_raw ) = > token ::ident_can_begin_expr ( name , t . span , is_raw ) ,
token ::Literal ( .. ) | token ::Pound = > true ,
2024-04-18 21:31:17 +10:00
_ = > t . is_metavar_expr ( ) ,
2019-08-11 13:14:30 +02:00
} ;
2019-12-07 02:55:12 +01:00
self . token . is_ident_named ( sym ::not ) & & self . look_ahead ( 1 , token_cannot_continue_expr )
}
/// Recover on `not expr` in favor of `!expr`.
2019-12-07 02:50:22 +01:00
fn recover_not_expr ( & mut self , lo : Span ) -> PResult < ' a , ( Span , ExprKind ) > {
2022-08-17 19:05:49 +02:00
let negated_token = self . look_ahead ( 1 , | t | t . clone ( ) ) ;
2022-09-16 14:41:42 +08:00
let sub_diag = if negated_token . is_numeric_lit ( ) {
2023-02-05 03:26:33 +01:00
errors ::NotAsNegationOperatorSub ::SuggestNotBitwise
2022-09-15 22:39:16 +08:00
} else if negated_token . is_bool_lit ( ) {
2023-02-05 03:26:33 +01:00
errors ::NotAsNegationOperatorSub ::SuggestNotLogical
2022-09-15 22:39:16 +08:00
} else {
2023-02-05 03:26:33 +01:00
errors ::NotAsNegationOperatorSub ::SuggestNotDefault
2022-09-15 22:39:16 +08:00
} ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::NotAsNegationOperator {
2022-08-17 19:05:49 +02:00
negated : negated_token . span ,
negated_desc : super ::token_descr ( & negated_token ) ,
2019-12-07 02:50:22 +01:00
// Span the `not` plus trailing whitespace to avoid
// trailing whitespace after the `!` in our suggestion
2022-09-16 14:41:42 +08:00
sub : sub_diag (
2024-03-04 16:31:49 +11:00
self . psess . source_map ( ) . span_until_non_whitespace ( lo . to ( negated_token . span ) ) ,
2022-09-16 14:41:42 +08:00
) ,
2022-08-17 19:05:49 +02:00
} ) ;
2019-12-07 03:07:35 +01:00
2023-02-24 04:38:45 +01:00
self . parse_expr_unary ( lo , UnOp ::Not )
2019-08-11 13:14:30 +02:00
}
2023-08-15 09:01:22 +10:00
/// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
fn interpolated_or_expr_span ( & self , expr : & Expr ) -> Span {
match self . prev_token . kind {
2024-04-22 19:46:51 +10:00
TokenKind ::NtIdent ( .. ) | TokenKind ::NtLifetime ( .. ) | TokenKind ::Interpolated ( .. ) = > {
self . prev_token . span
}
2024-04-18 21:31:17 +10:00
TokenKind ::CloseDelim ( Delimiter ::Invisible ( InvisibleOrigin ::MetaVar ( _ ) ) ) = > {
// `expr.span` is the interpolated span, because invisible open
// and close delims both get marked with the same span, one
// that covers the entire thing between them. (See
// `rustc_expand::mbe::transcribe::transcribe`.)
self . prev_token . span
}
2023-08-15 09:01:22 +10:00
_ = > expr . span ,
}
2019-08-11 13:14:30 +02:00
}
fn parse_assoc_op_cast (
& mut self ,
lhs : P < Expr > ,
lhs_span : Span ,
expr_kind : fn ( P < Expr > , P < Ty > ) -> ExprKind ,
) -> PResult < ' a , P < Expr > > {
2021-01-20 20:03:29 -08:00
let mk_expr = | this : & mut Self , lhs : P < Expr > , rhs : P < Ty > | {
2024-06-06 20:39:54 +00:00
this . mk_expr ( this . mk_expr_sp ( & lhs , lhs_span , rhs . span ) , expr_kind ( lhs , rhs ) )
2019-08-11 13:14:30 +02:00
} ;
// Save the state of the parser before parsing type normally, in case there is a
// LessThan comparison after this cast.
let parser_snapshot_before_type = self . clone ( ) ;
2022-01-10 22:02:19 +00:00
let cast_expr = match self . parse_as_cast_ty ( ) {
2021-01-20 20:03:29 -08:00
Ok ( rhs ) = > mk_expr ( self , lhs , rhs ) ,
2022-01-26 03:39:14 +00:00
Err ( type_err ) = > {
2022-10-28 20:44:26 +02:00
if ! self . may_recover ( ) {
return Err ( type_err ) ;
}
2019-08-11 13:14:30 +02:00
// Rewind to before attempting to parse the type with generics, to recover
// from situations like `x as usize < y` in which we first tried to parse
// `usize < y` as a type with generic arguments.
2020-04-17 13:59:14 -07:00
let parser_snapshot_after_type = mem ::replace ( self , parser_snapshot_before_type ) ;
2019-08-11 13:14:30 +02:00
2021-01-20 20:03:29 -08:00
// Check for typo of `'a: loop { break 'a }` with a missing `'`.
match ( & lhs . kind , & self . token . kind ) {
(
// `foo: `
ExprKind ::Path ( None , ast ::Path { segments , .. } ) ,
2024-02-13 23:28:27 +00:00
token ::Ident ( kw ::For | kw ::Loop | kw ::While , IdentIsRaw ::No ) ,
2024-08-07 12:41:49 +02:00
) if let [ segment ] = segments . as_slice ( ) = > {
2022-03-10 22:11:00 +09:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
2021-01-20 20:03:29 -08:00
let label = Label {
ident : Ident ::from_str_and_span (
2024-08-07 12:41:49 +02:00
& format! ( " ' {} " , segment . ident ) ,
segment . ident . span ,
2021-01-20 20:03:29 -08:00
) ,
} ;
2023-02-24 04:38:45 +01:00
match self . parse_expr_labeled ( label , false ) {
2021-01-20 20:03:29 -08:00
Ok ( expr ) = > {
type_err . cancel ( ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::MalformedLoopLabel {
2022-08-17 19:05:49 +02:00
span : label . ident . span ,
2024-07-06 03:07:46 +00:00
suggestion : label . ident . span . shrink_to_lo ( ) ,
2022-08-17 19:05:49 +02:00
} ) ;
2021-01-20 20:03:29 -08:00
return Ok ( expr ) ;
}
2022-01-26 03:39:14 +00:00
Err ( err ) = > {
2021-01-20 20:03:29 -08:00
err . cancel ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2021-01-20 20:03:29 -08:00
}
}
}
_ = > { }
}
2019-08-11 13:14:30 +02:00
match self . parse_path ( PathStyle ::Expr ) {
Ok ( path ) = > {
2022-08-24 22:41:51 +02:00
let span_after_type = parser_snapshot_after_type . token . span ;
2022-09-14 20:11:42 +02:00
let expr = mk_expr (
self ,
lhs ,
self . mk_ty ( path . span , TyKind ::Path ( None , path . clone ( ) ) ) ,
) ;
2022-08-24 22:41:51 +02:00
let args_span = self . look_ahead ( 1 , | t | t . span ) . to ( span_after_type ) ;
2023-02-05 03:26:33 +01:00
let suggestion = errors ::ComparisonOrShiftInterpretedAsGenericSugg {
2022-08-24 22:41:51 +02:00
left : expr . span . shrink_to_lo ( ) ,
right : expr . span . shrink_to_hi ( ) ,
} ;
match self . token . kind {
2023-02-05 03:26:33 +01:00
token ::Lt = > {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::ComparisonInterpretedAsGeneric {
2023-02-05 03:26:33 +01:00
comparison : self . token . span ,
r#type : path ,
args : args_span ,
suggestion ,
} )
}
2024-12-20 07:28:16 +11:00
token ::Shl = > self . dcx ( ) . emit_err ( errors ::ShiftInterpretedAsGeneric {
shift : self . token . span ,
r#type : path ,
args : args_span ,
suggestion ,
} ) ,
2019-08-11 13:14:30 +02:00
_ = > {
// We can end up here even without `<` being the next token, for
// example because `parse_ty_no_plus` returns `Err` on keywords,
// but `parse_path` returns `Ok` on them due to error recovery.
// Return original error and parser state.
2020-04-17 13:59:14 -07:00
* self = parser_snapshot_after_type ;
2019-08-11 13:14:30 +02:00
return Err ( type_err ) ;
}
} ;
// Successfully parsed the type path leaving a `<` yet to parse.
type_err . cancel ( ) ;
2022-08-24 22:41:51 +02:00
// Keep `x as usize` as an expression in AST and continue parsing.
2020-02-15 16:12:59 -08:00
expr
2019-08-11 13:14:30 +02:00
}
2022-01-26 03:39:14 +00:00
Err ( path_err ) = > {
2019-08-11 13:14:30 +02:00
// Couldn't parse as a path, return original error and parser state.
path_err . cancel ( ) ;
2020-04-17 13:59:14 -07:00
* self = parser_snapshot_after_type ;
2020-02-15 16:12:59 -08:00
return Err ( type_err ) ;
2019-08-11 13:14:30 +02:00
}
}
}
2020-02-08 21:34:38 -08:00
} ;
2024-07-16 16:02:45 +10:00
// Try to parse a postfix operator such as `.`, `?`, or index (`[]`)
// after a cast. If one is present, emit an error then return a valid
// parse tree; For something like `&x as T[0]` will be as if it was
// written `((&x) as T)[0]`.
2022-11-16 21:46:06 +01:00
2022-03-18 20:45:15 -07:00
let span = cast_expr . span ;
2024-07-16 16:12:58 +10:00
let with_postfix = self . parse_expr_dot_or_call_with ( AttrVec ::new ( ) , cast_expr , span ) ? ;
2020-02-15 16:12:59 -08:00
// Check if an illegal postfix operator has been added after the cast.
2022-11-08 21:49:58 +04:00
// If the resulting expression is not a cast, it is an illegal postfix operator.
2022-11-16 21:46:06 +01:00
if ! matches! ( with_postfix . kind , ExprKind ::Cast ( _ , _ ) ) {
let msg = format! (
" cast cannot be followed by {} " ,
match with_postfix . kind {
2023-08-03 21:43:17 +02:00
ExprKind ::Index ( .. ) = > " indexing " ,
2022-01-10 22:02:19 +00:00
ExprKind ::Try ( _ ) = > " `?` " ,
2020-02-15 16:12:59 -08:00
ExprKind ::Field ( _ , _ ) = > " a field access " ,
2022-09-08 10:52:51 +10:00
ExprKind ::MethodCall ( _ ) = > " a method call " ,
2020-02-15 16:12:59 -08:00
ExprKind ::Call ( _ , _ ) = > " a function call " ,
2023-04-25 18:59:16 +00:00
ExprKind ::Await ( _ , _ ) = > " `.await` " ,
2024-10-02 16:35:37 -03:00
ExprKind ::Use ( _ , _ ) = > " `.use` " ,
2024-04-02 18:31:42 -04:00
ExprKind ::Match ( _ , _ , MatchKind ::Postfix ) = > " a postfix match " ,
2024-02-25 22:22:11 +01:00
ExprKind ::Err ( _ ) = > return Ok ( with_postfix ) ,
2020-02-15 17:09:42 -08:00
_ = > unreachable! ( " parse_dot_or_call_expr_with_ shouldn't produce this " ) ,
2020-02-08 21:34:38 -08:00
}
) ;
2023-12-18 21:09:22 +11:00
let mut err = self . dcx ( ) . struct_span_err ( span , msg ) ;
2022-03-18 20:45:15 -07:00
2024-02-23 10:20:45 +11:00
let suggest_parens = | err : & mut Diag < '_ > | {
2020-02-22 12:33:06 -08:00
let suggestions = vec! [
( span . shrink_to_lo ( ) , " ( " . to_string ( ) ) ,
( span . shrink_to_hi ( ) , " ) " . to_string ( ) ) ,
] ;
err . multipart_suggestion (
" try surrounding the expression in parentheses " ,
suggestions ,
Applicability ::MachineApplicable ,
) ;
2022-03-18 20:45:15 -07:00
} ;
2022-11-16 21:46:06 +01:00
suggest_parens ( & mut err ) ;
2020-02-15 16:18:50 -08:00
err . emit ( ) ;
2020-02-08 21:34:38 -08:00
} ;
Ok ( with_postfix )
2019-08-11 13:14:30 +02:00
}
2019-11-23 14:22:00 +00:00
/// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
2023-02-24 04:38:45 +01:00
fn parse_expr_borrow ( & mut self , lo : Span ) -> PResult < ' a , ( Span , ExprKind ) > {
2019-11-23 14:15:49 +00:00
self . expect_and ( ) ? ;
2020-03-05 07:54:22 +01:00
let has_lifetime = self . token . is_lifetime ( ) & & self . look_ahead ( 1 , | t | t ! = & token ::Colon ) ;
let lifetime = has_lifetime . then ( | | self . expect_lifetime ( ) ) ; // For recovery, see below.
2024-07-13 13:53:56 +02:00
let ( borrow_kind , mutbl ) = self . parse_borrow_modifiers ( ) ;
2024-06-19 15:37:31 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2022-12-16 18:41:08 +05:30
let expr = if self . token . is_range_separator ( ) {
2024-06-19 15:37:31 +10:00
self . parse_expr_prefix_range ( attrs )
2022-12-14 19:10:03 +05:30
} else {
2024-06-19 14:41:01 +10:00
self . parse_expr_prefix ( attrs )
2023-08-15 09:01:22 +10:00
} ? ;
let hi = self . interpolated_or_expr_span ( & expr ) ;
2020-03-05 07:54:22 +01:00
let span = lo . to ( hi ) ;
if let Some ( lt ) = lifetime {
2024-07-06 03:07:46 +00:00
self . error_remove_borrow_lifetime ( span , lt . ident . span . until ( expr . span ) ) ;
2020-03-05 07:54:22 +01:00
}
Ok ( ( span , ExprKind ::AddrOf ( borrow_kind , mutbl , expr ) ) )
}
fn error_remove_borrow_lifetime ( & self , span : Span , lt_span : Span ) {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::LifetimeInBorrowExpression { span , lifetime_span : lt_span } ) ;
2019-12-07 02:37:03 +01:00
}
/// Parse `mut?` or `raw [ const | mut ]`.
2024-07-13 13:53:56 +02:00
fn parse_borrow_modifiers ( & mut self ) -> ( ast ::BorrowKind , ast ::Mutability ) {
2024-12-04 15:55:06 +11:00
if self . check_keyword ( exp! ( Raw ) ) & & self . look_ahead ( 1 , Token ::is_mutability ) {
2019-12-07 02:37:03 +01:00
// `raw [ const | mut ]`.
2024-12-04 15:55:06 +11:00
let found_raw = self . eat_keyword ( exp! ( Raw ) ) ;
2019-11-23 14:15:49 +00:00
assert! ( found_raw ) ;
let mutability = self . parse_const_or_mut ( ) . unwrap ( ) ;
( ast ::BorrowKind ::Raw , mutability )
} else {
2019-12-07 02:37:03 +01:00
// `mut?`
2019-11-23 14:15:49 +00:00
( ast ::BorrowKind ::Ref , self . parse_mutability ( ) )
2019-12-07 02:37:03 +01:00
}
2019-11-23 14:15:49 +00:00
}
2019-08-11 13:14:30 +02:00
/// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
2024-06-18 20:00:45 +10:00
fn parse_expr_dot_or_call ( & mut self , attrs : AttrWrapper ) -> PResult < ' a , P < Expr > > {
2021-01-22 13:28:08 -05:00
self . collect_tokens_for_expr ( attrs , | this , attrs | {
2023-08-15 09:01:22 +10:00
let base = this . parse_expr_bottom ( ) ? ;
let span = this . interpolated_or_expr_span ( & base ) ;
2024-07-16 15:54:34 +10:00
this . parse_expr_dot_or_call_with ( attrs , base , span )
2021-01-22 13:28:08 -05:00
} )
2019-08-11 13:14:30 +02:00
}
2023-02-24 04:38:45 +01:00
pub ( super ) fn parse_expr_dot_or_call_with (
2019-08-11 13:14:30 +02:00
& mut self ,
2022-08-17 12:34:33 +10:00
mut attrs : ast ::AttrVec ,
2024-07-16 16:12:58 +10:00
mut e : P < Expr > ,
2019-08-11 13:14:30 +02:00
lo : Span ,
) -> PResult < ' a , P < Expr > > {
2024-07-31 19:16:09 +10:00
let mut res = ensure_sufficient_stack ( | | {
2024-07-16 16:12:58 +10:00
loop {
let has_question =
2024-08-09 17:44:47 +10:00
if self . prev_token = = TokenKind ::Ident ( kw ::Return , IdentIsRaw ::No ) {
2024-07-16 16:12:58 +10:00
// We are using noexpect here because we don't expect a `?` directly after
// a `return` which could be suggested otherwise.
self . eat_noexpect ( & token ::Question )
} else {
2024-12-04 15:55:06 +11:00
self . eat ( exp! ( Question ) )
2024-07-16 16:12:58 +10:00
} ;
if has_question {
// `expr?`
e = self . mk_expr ( lo . to ( self . prev_token . span ) , ExprKind ::Try ( e ) ) ;
continue ;
}
2024-08-09 17:44:47 +10:00
let has_dot = if self . prev_token = = TokenKind ::Ident ( kw ::Return , IdentIsRaw ::No ) {
// We are using noexpect here because we don't expect a `.` directly after
// a `return` which could be suggested otherwise.
self . eat_noexpect ( & token ::Dot )
} else if self . token = = TokenKind ::RArrow & & self . may_recover ( ) {
// Recovery for `expr->suffix`.
self . bump ( ) ;
let span = self . prev_token . span ;
self . dcx ( ) . emit_err ( errors ::ExprRArrowCall { span } ) ;
true
} else {
2024-12-04 15:55:06 +11:00
self . eat ( exp! ( Dot ) )
2024-08-09 17:44:47 +10:00
} ;
2024-07-16 16:12:58 +10:00
if has_dot {
// expr.f
e = self . parse_dot_suffix_expr ( lo , e ) ? ;
continue ;
}
if self . expr_is_complete ( & e ) {
return Ok ( e ) ;
}
e = match self . token . kind {
token ::OpenDelim ( Delimiter ::Parenthesis ) = > self . parse_expr_fn_call ( lo , e ) ,
token ::OpenDelim ( Delimiter ::Bracket ) = > self . parse_expr_index ( lo , e ) ? ,
_ = > return Ok ( e ) ,
}
}
} ) ;
// Stitch the list of outer attributes onto the return value. A little
// bit ugly, but the best way given the current code structure.
2024-07-31 19:16:09 +10:00
if ! attrs . is_empty ( )
& & let Ok ( expr ) = & mut res
{
mem ::swap ( & mut expr . attrs , & mut attrs ) ;
expr . attrs . extend ( attrs )
2022-08-23 13:28:20 +10:00
}
2024-07-31 19:16:09 +10:00
res
2019-08-11 13:14:30 +02:00
}
2024-06-03 15:47:46 +10:00
pub ( super ) fn parse_dot_suffix_expr (
& mut self ,
lo : Span ,
base : P < Expr > ,
) -> PResult < ' a , P < Expr > > {
Clarify `parse_dot_suffix_expr`.
For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
`dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
moves the `sym2` token into `prev_token`, and discards the `dot` token
altogether.
New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
wrong -- that value is never used. That comment was added in #77250,
and AFAICT it has always been incorrect.
The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
2024-03-21 16:14:56 +11:00
// At this point we've consumed something like `expr.` and `self.token` holds the token
// after the dot.
2020-03-07 14:37:38 +03:00
match self . token . uninterpolate ( ) . kind {
2019-12-07 01:52:53 +01:00
token ::Ident ( .. ) = > self . parse_dot_suffix ( base , lo ) ,
token ::Literal ( token ::Lit { kind : token ::Integer , symbol , suffix } ) = > {
2024-03-13 15:59:41 +11:00
let ident_span = self . token . span ;
2024-03-13 15:45:27 +11:00
self . bump ( ) ;
2024-03-13 15:59:41 +11:00
Ok ( self . mk_expr_tuple_field_access ( lo , ident_span , base , symbol , suffix ) )
2019-12-07 01:52:53 +01:00
}
2020-04-18 21:26:10 +03:00
token ::Literal ( token ::Lit { kind : token ::Float , symbol , suffix } ) = > {
2024-03-13 15:34:05 +11:00
Ok ( match self . break_up_float ( symbol , self . token . span ) {
// 1e2
DestructuredFloat ::Single ( sym , _sp ) = > {
Clarify `parse_dot_suffix_expr`.
For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
`dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
moves the `sym2` token into `prev_token`, and discards the `dot` token
altogether.
New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
wrong -- that value is never used. That comment was added in #77250,
and AFAICT it has always been incorrect.
The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
2024-03-21 16:14:56 +11:00
// `foo.1e2`: a single complete dot access, fully consumed. We end up with
// the `1e2` token in `self.prev_token` and the following token in
// `self.token`.
2024-03-13 15:59:41 +11:00
let ident_span = self . token . span ;
2024-03-13 15:45:27 +11:00
self . bump ( ) ;
2024-03-13 15:59:41 +11:00
self . mk_expr_tuple_field_access ( lo , ident_span , base , sym , suffix )
2024-03-13 15:34:05 +11:00
}
// 1.
DestructuredFloat ::TrailingDot ( sym , ident_span , dot_span ) = > {
Clarify `parse_dot_suffix_expr`.
For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
`dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
moves the `sym2` token into `prev_token`, and discards the `dot` token
altogether.
New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
wrong -- that value is never used. That comment was added in #77250,
and AFAICT it has always been incorrect.
The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
2024-03-21 16:14:56 +11:00
// `foo.1.`: a single complete dot access and the start of another.
// We end up with the `sym` (`1`) token in `self.prev_token` and a dot in
// `self.token`.
2024-03-13 15:34:05 +11:00
assert! ( suffix . is_none ( ) ) ;
self . token = Token ::new ( token ::Ident ( sym , IdentIsRaw ::No ) , ident_span ) ;
2024-03-13 15:45:27 +11:00
self . bump_with ( ( Token ::new ( token ::Dot , dot_span ) , self . token_spacing ) ) ;
2024-03-13 15:59:41 +11:00
self . mk_expr_tuple_field_access ( lo , ident_span , base , sym , None )
2024-03-13 15:34:05 +11:00
}
// 1.2 | 1.2e3
DestructuredFloat ::MiddleDot (
Clarify `parse_dot_suffix_expr`.
For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
`dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
moves the `sym2` token into `prev_token`, and discards the `dot` token
altogether.
New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
wrong -- that value is never used. That comment was added in #77250,
and AFAICT it has always been incorrect.
The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
2024-03-21 16:14:56 +11:00
sym1 ,
2024-03-13 15:34:05 +11:00
ident1_span ,
Clarify `parse_dot_suffix_expr`.
For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
`dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
moves the `sym2` token into `prev_token`, and discards the `dot` token
altogether.
New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
wrong -- that value is never used. That comment was added in #77250,
and AFAICT it has always been incorrect.
The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
2024-03-21 16:14:56 +11:00
_dot_span ,
sym2 ,
2024-03-13 15:34:05 +11:00
ident2_span ,
) = > {
Clarify `parse_dot_suffix_expr`.
For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
`dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
moves the `sym2` token into `prev_token`, and discards the `dot` token
altogether.
New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
wrong -- that value is never used. That comment was added in #77250,
and AFAICT it has always been incorrect.
The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
2024-03-21 16:14:56 +11:00
// `foo.1.2` (or `foo.1.2e3`): two complete dot accesses. We end up with
// the `sym2` (`2` or `2e3`) token in `self.prev_token` and the following
// token in `self.token`.
2024-03-13 15:34:05 +11:00
let next_token2 =
Clarify `parse_dot_suffix_expr`.
For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
`dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
moves the `sym2` token into `prev_token`, and discards the `dot` token
altogether.
New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
wrong -- that value is never used. That comment was added in #77250,
and AFAICT it has always been incorrect.
The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
2024-03-21 16:14:56 +11:00
Token ::new ( token ::Ident ( sym2 , IdentIsRaw ::No ) , ident2_span ) ;
self . bump_with ( ( next_token2 , self . token_spacing ) ) ;
2024-03-13 15:45:27 +11:00
self . bump ( ) ;
Clarify `parse_dot_suffix_expr`.
For the `MiddleDot` case, current behaviour:
- For a case like `1.2`, `sym1` is `1` and `sym2` is `2`, and `self.token`
holds `1.2`.
- It creates a new ident token from `sym1` that it puts into `self.token`.
- Then it does `bump_with` with a new dot token, which moves the `sym1`
token into `prev_token`.
- Then it does `bump_with` with a new ident token from `sym2`, which moves the
`dot` token into `prev_token` and discards the `sym1` token.
- Then it does `bump`, which puts whatever is next into `self.token`,
moves the `sym2` token into `prev_token`, and discards the `dot` token
altogether.
New behaviour:
- Skips creating and inserting the `sym1` and dot tokens, because they are
unnecessary.
- This also demonstrates that the comment about `Spacing::Alone` is
wrong -- that value is never used. That comment was added in #77250,
and AFAICT it has always been incorrect.
The commit also expands comments. I found this code hard to read
previously, the examples in comments make it easier.
2024-03-21 16:14:56 +11:00
let base1 =
self . mk_expr_tuple_field_access ( lo , ident1_span , base , sym1 , None ) ;
self . mk_expr_tuple_field_access ( lo , ident2_span , base1 , sym2 , suffix )
2024-03-13 15:34:05 +11:00
}
2024-09-20 13:02:14 +10:00
DestructuredFloat ::Error = > base ,
2024-03-13 15:34:05 +11:00
} )
2019-12-07 01:52:53 +01:00
}
_ = > {
self . error_unexpected_after_dot ( ) ;
Ok ( base )
}
}
}
2024-09-20 13:02:14 +10:00
fn error_unexpected_after_dot ( & self ) {
2024-04-18 21:31:17 +10:00
let actual = super ::token_descr ( & self . token ) ;
2023-06-11 14:36:20 +08:00
let span = self . token . span ;
2024-03-04 16:31:49 +11:00
let sm = self . psess . source_map ( ) ;
2023-06-11 14:36:20 +08:00
let ( span , actual ) = match ( & self . token . kind , self . subparser_name ) {
2024-04-18 21:31:17 +10:00
( token ::Eof , Some ( _ ) ) if let Ok ( snippet ) = sm . span_to_snippet ( sm . next_point ( span ) ) = > {
( span . shrink_to_hi ( ) , format! ( " ` {} ` " , snippet ) )
}
( token ::CloseDelim ( Delimiter ::Invisible ( InvisibleOrigin ::MetaVar ( _ ) ) ) , _ ) = > {
// No need to report an error. This case will only occur when parsing a pasted
// metavariable, and we should have emitted an error when parsing the macro call in
// the first place. E.g. in this code:
// ```
// macro_rules! m { ($e:expr) => { $e }; }
//
// fn main() {
// let f = 1;
// m!(f.);
// }
// ```
// we'll get an error "unexpected token: `)` when parsing the `m!(f.)`, so we don't
// want to issue a second error when parsing the expansion `«f.»` (where `«`/`»`
// represent the invisible delimiters).
self . dcx ( ) . span_delayed_bug ( span , " bad dot expr in metavariable " ) ;
return ;
2023-10-13 08:58:33 +00:00
}
2023-06-11 14:36:20 +08:00
_ = > ( span , actual ) ,
} ;
2024-09-20 13:02:14 +10:00
self . dcx ( ) . emit_err ( errors ::UnexpectedTokenAfterDot { span , actual } ) ;
2019-12-07 00:59:56 +01:00
}
2024-09-14 13:17:16 +02:00
/// We need an identifier or integer, but the next token is a float.
/// Break the float into components to extract the identifier or integer.
///
/// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`.
//
2020-04-18 21:26:10 +03:00
// FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
2024-09-14 13:17:16 +02:00
// parts unless those parts are processed immediately. `TokenCursor` should either
// support pushing "future tokens" (would be also helpful to `break_and_eat`), or
// we should break everything including floats into more basic proc-macro style
// tokens in the lexer (probably preferable).
2024-07-04 14:10:17 +02:00
pub ( super ) fn break_up_float ( & self , float : Symbol , span : Span ) -> DestructuredFloat {
2020-04-18 21:26:10 +03:00
#[ derive(Debug) ]
enum FloatComponent {
IdentLike ( String ) ,
Punct ( char ) ,
}
use FloatComponent ::* ;
2020-10-10 02:01:44 +03:00
let float_str = float . as_str ( ) ;
2020-04-18 21:26:10 +03:00
let mut components = Vec ::new ( ) ;
let mut ident_like = String ::new ( ) ;
2020-10-10 02:01:44 +03:00
for c in float_str . chars ( ) {
2020-04-18 21:26:10 +03:00
if c = = '_' | | c . is_ascii_alphanumeric ( ) {
ident_like . push ( c ) ;
} else if matches! ( c , '.' | '+' | '-' ) {
if ! ident_like . is_empty ( ) {
components . push ( IdentLike ( mem ::take ( & mut ident_like ) ) ) ;
2019-12-07 01:52:53 +01:00
}
2020-04-18 21:26:10 +03:00
components . push ( Punct ( c ) ) ;
} else {
2023-07-25 22:00:13 +02:00
panic! ( " unexpected character in a float token: {c:?} " )
2020-04-18 21:26:10 +03:00
}
}
if ! ident_like . is_empty ( ) {
components . push ( IdentLike ( ident_like ) ) ;
}
2020-10-10 02:01:44 +03:00
// With proc macros the span can refer to anything, the source may be too short,
// or too long, or non-ASCII. It only makes sense to break our span into components
// if its underlying text is identical to our float literal.
let can_take_span_apart =
| | self . span_to_snippet ( span ) . as_deref ( ) = = Ok ( float_str ) . as_deref ( ) ;
2020-04-18 21:26:10 +03:00
match & * components {
// 1e2
[ IdentLike ( i ) ] = > {
2023-11-21 20:07:32 +01:00
DestructuredFloat ::Single ( Symbol ::intern ( i ) , span )
2020-04-18 21:26:10 +03:00
}
// 1.
2024-09-14 13:17:16 +02:00
[ IdentLike ( left ) , Punct ( '.' ) ] = > {
let ( left_span , dot_span ) = if can_take_span_apart ( ) {
let left_span = span . with_hi ( span . lo ( ) + BytePos ::from_usize ( left . len ( ) ) ) ;
let dot_span = span . with_lo ( left_span . hi ( ) ) ;
( left_span , dot_span )
2020-10-10 02:01:44 +03:00
} else {
( span , span )
} ;
2024-09-14 13:17:16 +02:00
let left = Symbol ::intern ( left ) ;
DestructuredFloat ::TrailingDot ( left , left_span , dot_span )
2020-04-18 21:26:10 +03:00
}
// 1.2 | 1.2e3
2024-09-14 13:17:16 +02:00
[ IdentLike ( left ) , Punct ( '.' ) , IdentLike ( right ) ] = > {
let ( left_span , dot_span , right_span ) = if can_take_span_apart ( ) {
let left_span = span . with_hi ( span . lo ( ) + BytePos ::from_usize ( left . len ( ) ) ) ;
let dot_span = span . with_lo ( left_span . hi ( ) ) . with_hi ( left_span . hi ( ) + BytePos ( 1 ) ) ;
let right_span = span . with_lo ( dot_span . hi ( ) ) ;
( left_span , dot_span , right_span )
2020-10-10 02:01:44 +03:00
} else {
( span , span , span )
} ;
2024-09-14 13:17:16 +02:00
let left = Symbol ::intern ( left ) ;
let right = Symbol ::intern ( right ) ;
DestructuredFloat ::MiddleDot ( left , left_span , dot_span , right , right_span )
2020-04-18 21:26:10 +03:00
}
// 1e+ | 1e- (recovered)
[ IdentLike ( _ ) , Punct ( '+' | '-' ) ] |
// 1e+2 | 1e-2
[ IdentLike ( _ ) , Punct ( '+' | '-' ) , IdentLike ( _ ) ] |
2021-11-15 17:46:44 +01:00
// 1.2e+ | 1.2e-
[ IdentLike ( _ ) , Punct ( '.' ) , IdentLike ( _ ) , Punct ( '+' | '-' ) ] |
2020-04-18 21:26:10 +03:00
// 1.2e+3 | 1.2e-3
[ IdentLike ( _ ) , Punct ( '.' ) , IdentLike ( _ ) , Punct ( '+' | '-' ) , IdentLike ( _ ) ] = > {
// See the FIXME about `TokenCursor` above.
2024-09-20 13:02:14 +10:00
self . error_unexpected_after_dot ( ) ;
DestructuredFloat ::Error
2020-04-18 21:26:10 +03:00
}
2023-07-25 22:00:13 +02:00
_ = > panic! ( " unexpected components in a float token: {components:?} " ) ,
2019-12-07 00:34:32 +01:00
}
}
2024-01-02 22:12:35 +00:00
/// Parse the field access used in offset_of, matched by `$(e:expr)+`.
/// Currently returns a list of idents. However, it should be possible in
/// future to also do array indices, which might be arbitrary expressions.
fn parse_floating_field_access ( & mut self ) -> PResult < ' a , P < [ Ident ] > > {
let mut fields = Vec ::new ( ) ;
let mut trailing_dot = None ;
loop {
// This is expected to use a metavariable $(args:expr)+, but the builtin syntax
// could be called directly. Calling `parse_expr` allows this function to only
// consider `Expr`s.
let expr = self . parse_expr ( ) ? ;
let mut current = & expr ;
let start_idx = fields . len ( ) ;
loop {
match current . kind {
ExprKind ::Field ( ref left , right ) = > {
// Field access is read right-to-left.
fields . insert ( start_idx , right ) ;
trailing_dot = None ;
current = left ;
}
// Parse this both to give helpful error messages and to
// verify it can be done with this parser setup.
ExprKind ::Index ( ref left , ref _right , span ) = > {
2024-01-02 23:13:08 +00:00
self . dcx ( ) . emit_err ( errors ::ArrayIndexInOffsetOf ( span ) ) ;
2024-01-02 22:12:35 +00:00
current = left ;
}
ExprKind ::Lit ( token ::Lit {
kind : token ::Float | token ::Integer ,
symbol ,
suffix ,
} ) = > {
if let Some ( suffix ) = suffix {
self . expect_no_tuple_index_suffix ( current . span , suffix ) ;
}
match self . break_up_float ( symbol , current . span ) {
// 1e2
DestructuredFloat ::Single ( sym , sp ) = > {
trailing_dot = None ;
fields . insert ( start_idx , Ident ::new ( sym , sp ) ) ;
}
// 1.
DestructuredFloat ::TrailingDot ( sym , sym_span , dot_span ) = > {
assert! ( suffix . is_none ( ) ) ;
trailing_dot = Some ( dot_span ) ;
fields . insert ( start_idx , Ident ::new ( sym , sym_span ) ) ;
}
// 1.2 | 1.2e3
DestructuredFloat ::MiddleDot (
symbol1 ,
span1 ,
_dot_span ,
symbol2 ,
span2 ,
) = > {
trailing_dot = None ;
fields . insert ( start_idx , Ident ::new ( symbol2 , span2 ) ) ;
fields . insert ( start_idx , Ident ::new ( symbol1 , span1 ) ) ;
}
2024-09-20 13:02:14 +10:00
DestructuredFloat ::Error = > {
2024-01-02 22:12:35 +00:00
trailing_dot = None ;
fields . insert ( start_idx , Ident ::new ( symbol , self . prev_token . span ) ) ;
}
}
break ;
}
ExprKind ::Path ( None , Path { ref segments , .. } ) = > {
match & segments [ .. ] {
[ PathSegment { ident , args : None , .. } ] = > {
trailing_dot = None ;
fields . insert ( start_idx , * ident )
}
_ = > {
2024-01-02 23:13:08 +00:00
self . dcx ( ) . emit_err ( errors ::InvalidOffsetOf ( current . span ) ) ;
2024-01-02 22:12:35 +00:00
break ;
}
}
break ;
}
_ = > {
2024-01-02 23:13:08 +00:00
self . dcx ( ) . emit_err ( errors ::InvalidOffsetOf ( current . span ) ) ;
2024-01-02 22:12:35 +00:00
break ;
}
}
2023-06-09 00:07:39 +02:00
}
2024-01-02 22:12:35 +00:00
if matches! ( self . token . kind , token ::CloseDelim ( .. ) | token ::Comma ) {
break ;
} else if trailing_dot . is_none ( ) {
// This loop should only repeat if there is a trailing dot.
2024-01-02 23:13:08 +00:00
self . dcx ( ) . emit_err ( errors ::InvalidOffsetOf ( self . token . span ) ) ;
2024-01-02 22:12:35 +00:00
break ;
2023-06-09 00:07:39 +02:00
}
2024-01-02 22:12:35 +00:00
}
if let Some ( dot ) = trailing_dot {
2024-01-02 23:13:08 +00:00
self . dcx ( ) . emit_err ( errors ::InvalidOffsetOf ( dot ) ) ;
2024-01-02 22:12:35 +00:00
}
Ok ( fields . into_iter ( ) . collect ( ) )
2023-06-09 00:07:39 +02:00
}
2024-03-13 15:59:41 +11:00
fn mk_expr_tuple_field_access (
2024-08-14 08:49:41 +10:00
& self ,
2019-12-07 00:16:19 +01:00
lo : Span ,
2024-03-13 15:59:41 +11:00
ident_span : Span ,
2019-12-07 00:16:19 +01:00
base : P < Expr > ,
field : Symbol ,
suffix : Option < Symbol > ,
) -> P < Expr > {
2022-09-15 10:12:09 +02:00
if let Some ( suffix ) = suffix {
2024-03-13 15:59:41 +11:00
self . expect_no_tuple_index_suffix ( ident_span , suffix ) ;
2022-09-15 10:12:09 +02:00
}
2024-03-13 15:59:41 +11:00
self . mk_expr ( lo . to ( ident_span ) , ExprKind ::Field ( base , Ident ::new ( field , ident_span ) ) )
2019-12-07 00:16:19 +01:00
}
2019-12-07 00:08:44 +01:00
/// Parse a function call expression, `expr(...)`.
2023-02-24 04:38:45 +01:00
fn parse_expr_fn_call ( & mut self , lo : Span , fun : P < Expr > ) -> P < Expr > {
2024-08-09 17:44:47 +10:00
let snapshot = if self . token = = token ::OpenDelim ( Delimiter ::Parenthesis ) {
2022-03-18 16:56:43 +09:00
Some ( ( self . create_snapshot_for_diagnostic ( ) , fun . kind . clone ( ) ) )
2021-09-07 17:45:16 +00:00
} else {
None
} ;
let open_paren = self . token . span ;
2024-01-05 10:42:31 +11:00
let seq = self
2023-02-24 04:38:45 +01:00
. parse_expr_paren_seq ( )
2022-08-15 09:58:38 +10:00
. map ( | args | self . mk_expr ( lo . to ( self . prev_token . span ) , self . mk_call ( fun , args ) ) ) ;
2024-01-05 10:42:31 +11:00
match self . maybe_recover_struct_lit_bad_delims ( lo , open_paren , seq , snapshot ) {
Ok ( expr ) = > expr ,
2024-12-04 15:55:06 +11:00
Err ( err ) = > self . recover_seq_parse_error ( exp! ( OpenParen ) , exp! ( CloseParen ) , lo , err ) ,
2021-09-14 18:16:33 +00:00
}
2019-12-07 00:08:44 +01:00
}
2021-09-14 18:16:33 +00:00
/// If we encounter a parser state that looks like the user has written a `struct` literal with
/// parentheses instead of braces, recover the parser state and provide suggestions.
2021-09-20 15:24:47 +00:00
#[ instrument(skip(self, seq, snapshot), level = " trace " ) ]
2021-09-14 18:16:33 +00:00
fn maybe_recover_struct_lit_bad_delims (
& mut self ,
lo : Span ,
open_paren : Span ,
2024-01-05 10:42:31 +11:00
seq : PResult < ' a , P < Expr > > ,
2022-03-18 16:56:43 +09:00
snapshot : Option < ( SnapshotParser < ' a > , ExprKind ) > ,
2024-01-05 10:42:31 +11:00
) -> PResult < ' a , P < Expr > > {
match ( self . may_recover ( ) , seq , snapshot ) {
( true , Err ( err ) , Some ( ( mut snapshot , ExprKind ::Path ( None , path ) ) ) ) = > {
2021-09-07 17:45:16 +00:00
snapshot . bump ( ) ; // `(`
2024-12-04 15:55:06 +11:00
match snapshot . parse_struct_fields ( path . clone ( ) , false , exp! ( CloseParen ) ) {
Ok ( ( fields , .. ) ) if snapshot . eat ( exp! ( CloseParen ) ) = > {
2021-12-07 16:44:51 +01:00
// We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest
2021-09-07 17:45:16 +00:00
// `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`.
2022-03-18 16:56:43 +09:00
self . restore_snapshot ( snapshot ) ;
2021-09-07 17:45:16 +00:00
let close_paren = self . prev_token . span ;
2023-03-03 14:33:31 +09:00
let span = lo . to ( close_paren ) ;
2023-05-13 18:06:16 +08:00
// filter shorthand fields
2023-05-13 18:06:58 +08:00
let fields : Vec < _ > =
fields . into_iter ( ) . filter ( | field | ! field . is_shorthand ) . collect ( ) ;
2024-02-25 22:22:11 +01:00
let guar = if ! fields . is_empty ( ) & &
2023-03-03 14:33:31 +09:00
// `token.kind` should not be compared here.
// This is because the `snapshot.token.kind` is treated as the same as
2024-01-05 10:42:31 +11:00
// that of the open delim in `TokenTreesReader::parse_token_tree`, even
// if they are different.
2023-05-24 14:19:22 +00:00
self . span_to_snippet ( close_paren ) . is_ok_and ( | snippet | snippet = = " ) " )
2023-03-03 14:33:31 +09:00
{
2024-01-05 10:42:31 +11:00
err . cancel ( ) ;
self . dcx ( )
. create_err ( errors ::ParenthesesWithStructFields {
2023-12-18 14:00:17 +11:00
span ,
r#type : path ,
braces_for_struct : errors ::BracesForStructLiteral {
first : open_paren ,
second : close_paren ,
} ,
no_fields_for_fn : errors ::NoFieldsForFnCall {
fields : fields
. into_iter ( )
. map ( | field | field . span . until ( field . expr . span ) )
. collect ( ) ,
} ,
2024-01-05 10:42:31 +11:00
} )
2024-02-25 22:22:11 +01:00
. emit ( )
2021-12-07 16:44:51 +01:00
} else {
2024-02-25 22:22:11 +01:00
err . emit ( )
} ;
Ok ( self . mk_expr_err ( span , guar ) )
2024-01-05 10:42:31 +11:00
}
Ok ( _ ) = > Err ( err ) ,
Err ( err2 ) = > {
err2 . cancel ( ) ;
Err ( err )
2021-09-07 17:45:16 +00:00
}
}
}
2024-01-05 10:42:31 +11:00
( _ , seq , _ ) = > seq ,
2021-09-07 17:45:16 +00:00
}
2019-12-07 00:08:44 +01:00
}
2019-12-07 00:04:46 +01:00
/// Parse an indexing expression `expr[...]`.
2023-02-24 04:38:45 +01:00
fn parse_expr_index ( & mut self , lo : Span , base : P < Expr > ) -> PResult < ' a , P < Expr > > {
2022-08-10 02:29:28 +09:00
let prev_span = self . prev_token . span ;
let open_delim_span = self . token . span ;
2019-12-07 00:04:46 +01:00
self . bump ( ) ; // `[`
let index = self . parse_expr ( ) ? ;
2022-08-10 02:29:28 +09:00
self . suggest_missing_semicolon_before_array ( prev_span , open_delim_span ) ? ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( CloseBracket ) ) ? ;
2023-08-03 21:43:17 +02:00
Ok ( self . mk_expr (
lo . to ( self . prev_token . span ) ,
self . mk_index ( base , index , open_delim_span . to ( self . prev_token . span ) ) ,
) )
2019-08-11 13:14:30 +02:00
}
/// Assuming we have just parsed `.`, continue parsing into an expression.
fn parse_dot_suffix ( & mut self , self_arg : P < Expr > , lo : Span ) -> PResult < ' a , P < Expr > > {
2025-03-26 15:54:14 +11:00
if self . token_uninterpolated_span ( ) . at_least_rust_2018 ( ) & & self . eat_keyword ( exp! ( Await ) ) {
2021-02-21 13:01:01 +01:00
return Ok ( self . mk_await_expr ( self_arg , lo ) ) ;
2019-08-11 13:14:30 +02:00
}
2024-10-02 16:35:37 -03:00
if self . eat_keyword ( exp! ( Use ) ) {
let use_span = self . prev_token . span ;
self . psess . gated_spans . gate ( sym ::ergonomic_clones , use_span ) ;
return Ok ( self . mk_use_expr ( self_arg , lo ) ) ;
}
2024-02-17 12:43:54 -05:00
// Post-fix match
2024-12-04 15:55:06 +11:00
if self . eat_keyword ( exp! ( Match ) ) {
2024-02-15 19:54:35 -05:00
let match_span = self . prev_token . span ;
self . psess . gated_spans . gate ( sym ::postfix_match , match_span ) ;
2024-02-17 12:43:54 -05:00
return self . parse_match_block ( lo , match_span , self_arg , MatchKind ::Postfix ) ;
2024-02-15 19:54:35 -05:00
}
2025-03-18 10:50:33 -07:00
// Parse a postfix `yield`.
2025-03-12 15:59:28 -07:00
if self . eat_keyword ( exp! ( Yield ) ) {
let yield_span = self . prev_token . span ;
self . psess . gated_spans . gate ( sym ::yield_expr , yield_span ) ;
2025-03-18 12:19:43 -07:00
return Ok (
self . mk_expr ( lo . to ( yield_span ) , ExprKind ::Yield ( YieldKind ::Postfix ( self_arg ) ) )
) ;
2025-03-12 15:59:28 -07:00
}
2020-06-09 15:34:23 -04:00
let fn_span_lo = self . token . span ;
2022-09-08 10:52:51 +10:00
let mut seg = self . parse_path_segment ( PathStyle ::Expr , None ) ? ;
2024-12-04 15:55:06 +11:00
self . check_trailing_angle_brackets ( & seg , & [ exp! ( OpenParen ) ] ) ;
2022-09-08 10:52:51 +10:00
self . check_turbofish_missing_angle_brackets ( & mut seg ) ;
2019-08-11 13:14:30 +02:00
2024-12-04 15:55:06 +11:00
if self . check ( exp! ( OpenParen ) ) {
2019-12-07 00:04:46 +01:00
// Method call `expr.f()`
2023-02-24 04:38:45 +01:00
let args = self . parse_expr_paren_seq ( ) ? ;
2020-06-09 15:34:23 -04:00
let fn_span = fn_span_lo . to ( self . prev_token . span ) ;
2020-02-29 14:56:15 +03:00
let span = lo . to ( self . prev_token . span ) ;
2022-09-08 10:52:51 +10:00
Ok ( self . mk_expr (
span ,
ExprKind ::MethodCall ( Box ::new ( ast ::MethodCall {
seg ,
receiver : self_arg ,
args ,
span : fn_span ,
} ) ) ,
) )
2019-12-07 00:04:46 +01:00
} else {
// Field access `expr.f`
2024-12-11 00:53:07 +01:00
let span = lo . to ( self . prev_token . span ) ;
2022-09-08 10:52:51 +10:00
if let Some ( args ) = seg . args {
2024-12-11 00:53:07 +01:00
// See `StashKey::GenericInFieldExpr` for more info on why we stash this.
self . dcx ( )
. create_err ( errors ::FieldExpressionWithGeneric ( args . span ( ) ) )
. stash ( seg . ident . span , StashKey ::GenericInFieldExpr ) ;
2019-08-11 13:14:30 +02:00
}
2022-09-08 10:52:51 +10:00
Ok ( self . mk_expr ( span , ExprKind ::Field ( self_arg , seg . ident ) ) )
2019-12-07 00:04:46 +01:00
}
2019-08-11 13:14:30 +02:00
}
/// At the bottom (top?) of the precedence hierarchy,
/// Parses things like parenthesized exprs, macros, `return`, etc.
///
/// N.B., this does not parse outer attributes, and is private because it only works
2024-07-16 16:39:04 +10:00
/// correctly if called from `parse_expr_dot_or_call`.
2023-02-24 04:38:45 +01:00
fn parse_expr_bottom ( & mut self ) -> PResult < ' a , P < Expr > > {
2019-08-11 13:14:30 +02:00
maybe_recover_from_interpolated_ty_qpath! ( self , true ) ;
2024-06-17 14:44:55 +10:00
2024-04-18 20:09:37 +10:00
let span = self . token . span ;
2024-06-17 14:44:55 +10:00
if let token ::Interpolated ( nt ) = & self . token . kind {
match & * * nt {
token ::NtBlock ( block ) = > {
let block = block . clone ( ) ;
self . bump ( ) ;
return Ok ( self . mk_expr ( self . prev_token . span , ExprKind ::Block ( block , None ) ) ) ;
}
} ;
2024-04-18 21:31:17 +10:00
} else if let Some ( expr ) = self . eat_metavar_seq_with_matcher (
| mv_kind | matches! ( mv_kind , MetaVarKind ::Expr { .. } ) ,
| this | {
2025-03-31 16:32:55 +11:00
// Force collection (as opposed to just `parse_expr`) is required to avoid the
// attribute duplication seen in #138478.
let expr = this . parse_expr_force_collect ( ) ;
2024-04-18 21:31:17 +10:00
// FIXME(nnethercote) Sometimes with expressions we get a trailing comma, possibly
// related to the FIXME in `collect_tokens_for_expr`. Examples are the multi-line
// `assert_eq!` calls involving arguments annotated with `#[rustfmt::skip]` in
// `compiler/rustc_index/src/bit_set/tests.rs`.
if this . token . kind = = token ::Comma {
this . bump ( ) ;
}
expr
} ,
) {
return Ok ( expr ) ;
} else if let Some ( lit ) =
self . eat_metavar_seq ( MetaVarKind ::Literal , | this | this . parse_literal_maybe_minus ( ) )
{
return Ok ( lit ) ;
2024-04-18 20:09:37 +10:00
} else if let Some ( path ) = self . eat_metavar_seq ( MetaVarKind ::Path , | this | {
this . collect_tokens_no_attrs ( | this | this . parse_path ( PathStyle ::Type ) )
} ) {
return Ok ( self . mk_expr ( span , ExprKind ::Path ( None , path ) ) ) ;
2024-06-17 14:44:55 +10:00
}
2019-08-11 13:14:30 +02:00
// Outer attributes are already parsed and will be
// added to the return value after the fact.
2023-09-08 10:14:36 +00:00
let restrictions = self . restrictions ;
self . with_res ( restrictions - Restrictions ::ALLOW_LET , | this | {
2024-12-04 15:55:06 +11:00
// Note: adding new syntax here? Don't forget to adjust `TokenKind::can_begin_expr()`.
2023-09-08 10:14:36 +00:00
let lo = this . token . span ;
if let token ::Literal ( _ ) = this . token . kind {
// This match arm is a special-case of the `_` match arm below and
// could be removed without changing functionality, but it's faster
// to have it here, especially for programs with large constants.
this . parse_expr_lit ( )
2024-12-04 15:55:06 +11:00
} else if this . check ( exp! ( OpenParen ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_tuple_parens ( restrictions )
2024-12-04 15:55:06 +11:00
} else if this . check ( exp! ( OpenBrace ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_block ( None , lo , BlockCheckMode ::Default )
2024-12-04 15:55:06 +11:00
} else if this . check ( exp! ( Or ) ) | | this . check ( exp! ( OrOr ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_closure ( ) . map_err ( | mut err | {
// If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
// then suggest parens around the lhs.
2024-03-04 16:31:49 +11:00
if let Some ( sp ) = this . psess . ambiguous_block_expr_parse . borrow ( ) . get ( & lo ) {
2024-06-18 11:10:18 +00:00
err . subdiagnostic ( ExprParenthesesNeeded ::surrounding ( * sp ) ) ;
2023-09-08 10:14:36 +00:00
}
err
} )
2024-12-04 15:55:06 +11:00
} else if this . check ( exp! ( OpenBracket ) ) {
this . parse_expr_array_or_repeat ( exp! ( CloseBracket ) )
2023-09-08 10:14:36 +00:00
} else if this . is_builtin ( ) {
this . parse_expr_builtin ( )
} else if this . check_path ( ) {
this . parse_expr_path_start ( )
2024-12-04 15:55:06 +11:00
} else if this . check_keyword ( exp! ( Move ) )
2024-11-01 18:37:32 -03:00
| | this . check_keyword ( exp! ( Use ) )
2024-12-04 15:55:06 +11:00
| | this . check_keyword ( exp! ( Static ) )
2023-09-08 10:14:36 +00:00
| | this . check_const_closure ( )
{
this . parse_expr_closure ( )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( If ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_if ( )
2024-12-04 15:55:06 +11:00
} else if this . check_keyword ( exp! ( For ) ) {
2023-09-08 10:14:36 +00:00
if this . choose_generics_over_qpath ( 1 ) {
this . parse_expr_closure ( )
} else {
2024-12-04 15:55:06 +11:00
assert! ( this . eat_keyword ( exp! ( For ) ) ) ;
2024-11-28 15:06:37 +11:00
this . parse_expr_for ( None , lo )
2022-02-24 17:02:38 -07:00
}
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( While ) ) {
2024-11-28 15:06:37 +11:00
this . parse_expr_while ( None , lo )
2023-09-08 10:14:36 +00:00
} else if let Some ( label ) = this . eat_label ( ) {
this . parse_expr_labeled ( label , true )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Loop ) ) {
2024-11-28 15:06:37 +11:00
this . parse_expr_loop ( None , lo ) . map_err ( | mut err | {
err . span_label ( lo , " while parsing this `loop` expression " ) ;
2022-01-12 20:43:24 +00:00
err
2023-09-08 10:14:36 +00:00
} )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Match ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_match ( ) . map_err ( | mut err | {
2024-11-28 15:06:37 +11:00
err . span_label ( lo , " while parsing this `match` expression " ) ;
2023-09-08 10:14:36 +00:00
err
} )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Unsafe ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_block ( None , lo , BlockCheckMode ::Unsafe ( ast ::UserProvided ) ) . map_err (
| mut err | {
2024-11-28 15:06:37 +11:00
err . span_label ( lo , " while parsing this `unsafe` expression " ) ;
2023-09-08 10:14:36 +00:00
err
} ,
)
} else if this . check_inline_const ( 0 ) {
2024-11-28 15:06:37 +11:00
this . parse_const_block ( lo , false )
2023-09-08 10:14:36 +00:00
} else if this . may_recover ( ) & & this . is_do_catch_block ( ) {
this . recover_do_catch ( )
} else if this . is_try_block ( ) {
2024-12-04 15:55:06 +11:00
this . expect_keyword ( exp! ( Try ) ) ? ;
2023-09-08 10:14:36 +00:00
this . parse_try_block ( lo )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Return ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_return ( )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Continue ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_continue ( lo )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Break ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_break ( )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Yield ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_yield ( )
} else if this . is_do_yeet ( ) {
this . parse_expr_yeet ( )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Become ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_become ( )
2024-12-04 15:55:06 +11:00
} else if this . check_keyword ( exp! ( Let ) ) {
2023-09-08 10:14:36 +00:00
this . parse_expr_let ( restrictions )
2024-12-04 15:55:06 +11:00
} else if this . eat_keyword ( exp! ( Underscore ) ) {
2023-09-08 10:14:36 +00:00
Ok ( this . mk_expr ( this . prev_token . span , ExprKind ::Underscore ) )
2025-03-26 15:54:14 +11:00
} else if this . token_uninterpolated_span ( ) . at_least_rust_2018 ( ) {
2023-12-12 20:08:34 +00:00
// `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
2025-03-26 15:54:14 +11:00
if this . token_uninterpolated_span ( ) . at_least_rust_2024 ( )
2023-12-12 20:08:34 +00:00
// check for `gen {}` and `gen move {}`
// or `async gen {}` and `async gen move {}`
& & ( this . is_gen_block ( kw ::Gen , 0 )
2024-12-04 15:55:06 +11:00
| | ( this . check_keyword ( exp! ( Async ) ) & & this . is_gen_block ( kw ::Gen , 1 ) ) )
2023-12-12 20:08:34 +00:00
{
// FIXME: (async) gen closures aren't yet parsed.
this . parse_gen_block ( )
2024-12-04 15:55:06 +11:00
} else if this . check_keyword ( exp! ( Async ) ) {
2023-12-05 21:45:01 +00:00
// FIXME(gen_blocks): Parse `gen async` and suggest swap
if this . is_gen_block ( kw ::Async , 0 ) {
2023-11-28 18:18:19 +00:00
// Check for `async {` and `async move {`,
2023-10-20 21:26:57 +00:00
this . parse_gen_block ( )
2023-09-08 10:14:36 +00:00
} else {
this . parse_expr_closure ( )
}
2023-12-05 21:45:01 +00:00
} else if this . eat_keyword_noexpect ( kw ::Await ) {
2024-11-28 15:06:37 +11:00
this . recover_incorrect_await_syntax ( lo )
2019-08-11 13:14:30 +02:00
} else {
2023-09-08 10:14:36 +00:00
this . parse_expr_lit ( )
2019-08-11 13:14:30 +02:00
}
2019-12-03 16:38:08 +01:00
} else {
2023-09-08 10:14:36 +00:00
this . parse_expr_lit ( )
2019-08-11 13:14:30 +02:00
}
2023-09-08 10:14:36 +00:00
} )
2019-12-03 15:31:45 +01:00
}
2019-08-11 13:14:30 +02:00
2023-02-24 04:38:45 +01:00
fn parse_expr_lit ( & mut self ) -> PResult < ' a , P < Expr > > {
2019-12-03 15:31:45 +01:00
let lo = self . token . span ;
2022-10-10 13:40:56 +11:00
match self . parse_opt_token_lit ( ) {
Some ( ( token_lit , _ ) ) = > {
let expr = self . mk_expr ( lo . to ( self . prev_token . span ) , ExprKind ::Lit ( token_lit ) ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2019-12-03 15:31:45 +01:00
}
2020-04-17 19:10:29 +02:00
None = > self . try_macro_suggestion ( ) ,
2019-12-03 15:31:45 +01:00
}
2019-08-11 13:14:30 +02:00
}
2023-09-08 10:14:36 +00:00
fn parse_expr_tuple_parens ( & mut self , restrictions : Restrictions ) -> PResult < ' a , P < Expr > > {
2019-12-03 11:36:40 +01:00
let lo = self . token . span ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( OpenParen ) ) ? ;
2019-12-04 10:13:29 +01:00
let ( es , trailing_comma ) = match self . parse_seq_to_end (
2024-12-04 15:55:06 +11:00
exp! ( CloseParen ) ,
SeqSep ::trailing_allowed ( exp! ( Comma ) ) ,
2023-09-08 10:14:36 +00:00
| p | p . parse_expr_catch_underscore ( restrictions . intersection ( Restrictions ::ALLOW_LET ) ) ,
2019-12-04 10:13:29 +01:00
) {
2019-12-03 11:36:40 +01:00
Ok ( x ) = > x ,
2022-04-26 15:40:14 +03:00
Err ( err ) = > {
2024-12-04 15:55:06 +11:00
return Ok ( self . recover_seq_parse_error (
exp! ( OpenParen ) ,
exp! ( CloseParen ) ,
lo ,
err ,
) ) ;
2022-04-26 15:40:14 +03:00
}
2019-12-03 11:36:40 +01:00
} ;
2024-02-13 23:48:23 +00:00
let kind = if es . len ( ) = = 1 & & matches! ( trailing_comma , Trailing ::No ) {
2019-12-03 11:36:40 +01:00
// `(e)` is parenthesized `e`.
2020-03-03 01:19:00 +01:00
ExprKind ::Paren ( es . into_iter ( ) . next ( ) . unwrap ( ) )
2019-12-03 11:36:40 +01:00
} else {
// `(e,)` is a tuple with only one field, `e`.
ExprKind ::Tup ( es )
} ;
2022-08-15 09:58:38 +10:00
let expr = self . mk_expr ( lo . to ( self . prev_token . span ) , kind ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2019-12-03 11:36:40 +01:00
}
2024-12-04 15:55:06 +11:00
fn parse_expr_array_or_repeat ( & mut self , close : ExpTokenPair < '_ > ) -> PResult < ' a , P < Expr > > {
2019-12-03 11:49:56 +01:00
let lo = self . token . span ;
Suggest replacing braces for brackets on array-esque invalid block expr
Newcomers may write `{1, 2, 3}` for making arrays, and the current error
message is not informative enough to quickly convince them what is
needed to fix the error.
This PR implements a diagnostic for this case, and its output looks like
this:
```text
error: this code is interpreted as a block expression, not an array
--> src/lib.rs:1:22
|
1 | const FOO: [u8; 3] = {
| ______________________^
2 | | 1, 2, 3
3 | | };
| |_^
|
= note: to define an array, one would use square brackets instead of curly braces
help: try using [] instead of {}
|
1 | const FOO: [u8; 3] = [
2 | 1, 2, 3
3 | ];
|
```
Fix #87672
2021-08-07 04:34:29 +09:00
self . bump ( ) ; // `[` or other open delim
2019-12-03 11:49:56 +01:00
2019-12-04 10:13:29 +01:00
let kind = if self . eat ( close ) {
2019-12-03 11:49:56 +01:00
// Empty vector
2022-11-23 11:55:16 +11:00
ExprKind ::Array ( ThinVec ::new ( ) )
2019-12-03 11:49:56 +01:00
} else {
// Non-empty vector
let first_expr = self . parse_expr ( ) ? ;
2024-12-04 15:55:06 +11:00
if self . eat ( exp! ( Semi ) ) {
2019-12-03 11:49:56 +01:00
// Repeating array syntax: `[ 0; 512 ]`
2023-02-24 04:38:45 +01:00
let count = self . parse_expr_anon_const ( ) ? ;
2019-12-04 10:13:29 +01:00
self . expect ( close ) ? ;
2019-12-03 11:49:56 +01:00
ExprKind ::Repeat ( first_expr , count )
2024-12-04 15:55:06 +11:00
} else if self . eat ( exp! ( Comma ) ) {
2019-12-03 11:49:56 +01:00
// Vector with two or more elements.
2024-12-04 15:55:06 +11:00
let sep = SeqSep ::trailing_allowed ( exp! ( Comma ) ) ;
2023-01-14 11:44:25 +00:00
let ( mut exprs , _ ) = self . parse_seq_to_end ( close , sep , | p | p . parse_expr ( ) ) ? ;
exprs . insert ( 0 , first_expr ) ;
2019-12-03 11:49:56 +01:00
ExprKind ::Array ( exprs )
} else {
// Vector with one element
2019-12-04 10:13:29 +01:00
self . expect ( close ) ? ;
2022-11-23 11:55:16 +11:00
ExprKind ::Array ( thin_vec! [ first_expr ] )
2019-12-03 11:49:56 +01:00
}
} ;
2022-08-15 09:58:38 +10:00
let expr = self . mk_expr ( lo . to ( self . prev_token . span ) , kind ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2019-12-03 11:49:56 +01:00
}
2023-02-24 04:38:45 +01:00
fn parse_expr_path_start ( & mut self ) -> PResult < ' a , P < Expr > > {
2023-05-04 23:31:04 -04:00
let maybe_eq_tok = self . prev_token . clone ( ) ;
2020-12-10 13:20:07 +01:00
let ( qself , path ) = if self . eat_lt ( ) {
2023-05-04 23:31:04 -04:00
let lt_span = self . prev_token . span ;
let ( qself , path ) = self . parse_qpath ( PathStyle ::Expr ) . map_err ( | mut err | {
// Suggests using '<=' if there is an error parsing qpath when the previous token
// is an '=' token. Only emits suggestion if the '<' token and '=' token are
// directly adjacent (i.e. '=<')
2024-08-09 17:44:47 +10:00
if maybe_eq_tok = = TokenKind ::Eq & & maybe_eq_tok . span . hi ( ) = = lt_span . lo ( ) {
2023-05-04 23:31:04 -04:00
let eq_lt = maybe_eq_tok . span . to ( lt_span ) ;
err . span_suggestion ( eq_lt , " did you mean " , " <= " , Applicability ::Unspecified ) ;
}
err
} ) ? ;
2020-12-10 13:20:07 +01:00
( Some ( qself ) , path )
} else {
( None , self . parse_path ( PathStyle ::Expr ) ? )
} ;
2019-12-03 12:43:45 +01:00
// `!`, as an operator, is prefix, so we know this isn't that.
2024-12-20 14:04:25 +11:00
let ( span , kind ) = if self . eat ( exp! ( Bang ) ) {
2019-12-03 12:43:45 +01:00
// MACRO INVOCATION expression
2020-12-10 13:20:07 +01:00
if qself . is_some ( ) {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::MacroInvocationWithQualifiedPath ( path . span ) ) ;
2020-12-10 13:20:07 +01:00
}
2022-08-15 09:13:03 +10:00
let lo = path . span ;
2022-11-18 11:24:21 +11:00
let mac = P ( MacCall { path , args : self . parse_delim_args ( ) ? } ) ;
2022-08-15 09:13:03 +10:00
( lo . to ( self . prev_token . span ) , ExprKind ::MacCall ( mac ) )
2024-12-04 15:55:06 +11:00
} else if self . check ( exp! ( OpenBrace ) )
2023-01-06 05:34:56 +00:00
& & let Some ( expr ) = self . maybe_parse_struct_expr ( & qself , & path )
{
if qself . is_some ( ) {
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::more_qualified_paths , path . span ) ;
2023-01-06 05:34:56 +00:00
}
return expr ;
2019-12-03 12:43:45 +01:00
} else {
2020-12-10 13:20:07 +01:00
( path . span , ExprKind ::Path ( qself , path ) )
2019-12-03 12:43:45 +01:00
} ;
2022-08-15 09:58:38 +10:00
let expr = self . mk_expr ( span , kind ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2019-12-03 12:43:45 +01:00
}
2020-03-05 07:54:22 +01:00
/// Parse `'label: $expr`. The label is already parsed.
2022-11-16 21:46:06 +01:00
pub ( super ) fn parse_expr_labeled (
2021-01-20 20:03:29 -08:00
& mut self ,
2022-09-01 18:48:09 +00:00
label_ : Label ,
2022-01-13 15:44:17 -08:00
mut consume_colon : bool ,
2021-01-20 20:03:29 -08:00
) -> PResult < ' a , P < Expr > > {
2022-09-01 18:48:09 +00:00
let lo = label_ . ident . span ;
let label = Some ( label_ ) ;
2024-12-04 15:55:06 +11:00
let ate_colon = self . eat ( exp! ( Colon ) ) ;
2024-07-06 03:07:46 +00:00
let tok_sp = self . token . span ;
2024-12-04 15:55:06 +11:00
let expr = if self . eat_keyword ( exp! ( While ) ) {
2023-02-24 04:38:45 +01:00
self . parse_expr_while ( label , lo )
2024-12-04 15:55:06 +11:00
} else if self . eat_keyword ( exp! ( For ) ) {
2023-02-24 04:38:45 +01:00
self . parse_expr_for ( label , lo )
2024-12-04 15:55:06 +11:00
} else if self . eat_keyword ( exp! ( Loop ) ) {
2023-02-24 04:38:45 +01:00
self . parse_expr_loop ( label , lo )
2022-05-01 19:05:35 +02:00
} else if self . check_noexpect ( & token ::OpenDelim ( Delimiter ::Brace ) )
| | self . token . is_whole_block ( )
{
2023-02-24 04:38:45 +01:00
self . parse_expr_block ( label , lo , BlockCheckMode ::Default )
2022-09-01 18:48:09 +00:00
} else if ! ate_colon
2022-10-28 20:44:26 +02:00
& & self . may_recover ( )
2022-09-01 18:48:09 +00:00
& & ( matches! ( self . token . kind , token ::CloseDelim ( _ ) | token ::Comma )
2023-08-08 11:34:07 +10:00
| | self . token . is_punct ( ) )
2024-01-29 09:47:02 +11:00
& & could_be_unclosed_char_literal ( label_ . ident )
2022-09-01 18:48:09 +00:00
{
2022-12-05 14:39:56 +11:00
let ( lit , _ ) =
self . recover_unclosed_char ( label_ . ident , Parser ::mk_token_lit_char , | self_ | {
2023-12-18 21:14:02 +11:00
self_ . dcx ( ) . create_err ( errors ::UnexpectedTokenAfterLabel {
2022-12-05 14:39:56 +11:00
span : self_ . token . span ,
remove_label : None ,
enclose_in_block : None ,
} )
} ) ;
2022-09-01 18:48:09 +00:00
consume_colon = false ;
2022-12-05 14:39:56 +11:00
Ok ( self . mk_expr ( lo , ExprKind ::Lit ( lit ) ) )
2022-05-01 19:05:35 +02:00
} else if ! ate_colon
& & ( self . check_noexpect ( & TokenKind ::Comma ) | | self . check_noexpect ( & TokenKind ::Gt ) )
{
2022-02-02 10:33:13 -08:00
// We're probably inside of a `Path<'a>` that needs a turbofish
2024-02-25 22:22:11 +01:00
let guar = self . dcx ( ) . emit_err ( errors ::UnexpectedTokenAfterLabel {
2022-08-24 22:41:51 +02:00
span : self . token . span ,
remove_label : None ,
enclose_in_block : None ,
} ) ;
2022-01-13 15:44:17 -08:00
consume_colon = false ;
2024-02-25 22:22:11 +01:00
Ok ( self . mk_expr_err ( lo , guar ) )
2020-03-05 01:47:15 +01:00
} else {
2023-02-05 03:26:33 +01:00
let mut err = errors ::UnexpectedTokenAfterLabel {
2022-08-24 22:41:51 +02:00
span : self . token . span ,
remove_label : None ,
enclose_in_block : None ,
} ;
2022-06-05 16:45:29 +04:00
2020-03-05 01:47:15 +01:00
// Continue as an expression in an effort to recover on `'label: non_block_expr`.
2022-06-05 16:45:29 +04:00
let expr = self . parse_expr ( ) . map ( | expr | {
2022-06-05 23:34:11 +04:00
let span = expr . span ;
2022-06-05 23:12:51 +04:00
let found_labeled_breaks = {
2024-02-24 02:52:59 -05:00
struct FindLabeledBreaksVisitor ;
2022-06-05 23:12:51 +04:00
impl < ' ast > Visitor < ' ast > for FindLabeledBreaksVisitor {
2024-02-24 02:52:59 -05:00
type Result = ControlFlow < ( ) > ;
fn visit_expr ( & mut self , ex : & ' ast Expr ) -> ControlFlow < ( ) > {
2022-06-05 23:12:51 +04:00
if let ExprKind ::Break ( Some ( _label ) , _ ) = ex . kind {
2024-02-24 02:52:59 -05:00
ControlFlow ::Break ( ( ) )
} else {
walk_expr ( self , ex )
2022-06-05 23:12:51 +04:00
}
}
}
2024-02-24 02:52:59 -05:00
FindLabeledBreaksVisitor . visit_expr ( & expr ) . is_break ( )
2022-06-05 23:12:51 +04:00
} ;
2023-01-14 11:29:22 +00:00
// Suggestion involves adding a labeled block.
2022-06-05 23:34:11 +04:00
//
// If there are no breaks that may use this label, suggest removing the label and
// recover to the unmodified expression.
2022-06-05 23:12:51 +04:00
if ! found_labeled_breaks {
2022-08-24 22:41:51 +02:00
err . remove_label = Some ( lo . until ( span ) ) ;
2022-06-05 23:34:11 +04:00
2022-06-05 23:12:51 +04:00
return expr ;
}
2023-02-05 03:26:33 +01:00
err . enclose_in_block = Some ( errors ::UnexpectedTokenAfterLabelSugg {
2022-08-24 22:41:51 +02:00
left : span . shrink_to_lo ( ) ,
right : span . shrink_to_hi ( ) ,
} ) ;
2022-06-05 16:45:29 +04:00
2022-08-18 10:13:37 +08:00
// Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`.
2022-06-05 16:45:29 +04:00
let stmt = self . mk_stmt ( span , StmtKind ::Expr ( expr ) ) ;
2023-01-30 14:13:27 +11:00
let blk = self . mk_block ( thin_vec! [ stmt ] , BlockCheckMode ::Default , span ) ;
2022-08-15 09:58:38 +10:00
self . mk_expr ( span , ExprKind ::Block ( blk , label ) )
2022-06-05 16:45:29 +04:00
} ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( err ) ;
2022-06-05 16:45:29 +04:00
expr
2020-03-05 07:54:22 +01:00
} ? ;
2021-01-20 20:03:29 -08:00
if ! ate_colon & & consume_colon {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::RequireColonAfterLabeledExpression {
2022-08-17 19:05:49 +02:00
span : expr . span ,
label : lo ,
2024-07-06 03:07:46 +00:00
label_end : lo . between ( tok_sp ) ,
2022-08-17 19:05:49 +02:00
} ) ;
2019-12-03 12:48:08 +01:00
}
2020-03-05 07:54:22 +01:00
Ok ( expr )
2019-12-03 12:48:08 +01:00
}
2024-01-29 09:28:10 +11:00
/// Emit an error when a char is parsed as a lifetime or label because of a missing quote.
2022-12-05 14:39:56 +11:00
pub ( super ) fn recover_unclosed_char < L > (
2022-10-10 13:40:56 +11:00
& self ,
2024-01-29 09:28:10 +11:00
ident : Ident ,
2022-12-05 14:39:56 +11:00
mk_lit_char : impl FnOnce ( Symbol , Span ) -> L ,
2024-02-23 10:20:45 +11:00
err : impl FnOnce ( & Self ) -> Diag < ' a > ,
2022-12-05 14:39:56 +11:00
) -> L {
2024-01-29 09:47:02 +11:00
assert! ( could_be_unclosed_char_literal ( ident ) ) ;
Overhaul how stashed diagnostics work, again.
Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. #120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.
This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
disallowing the use of `steal_diagnostic` with errors, and introducing
the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
that can be used instead.
Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
return `Option<ErrorGuaranteed>`, which enables the removal of two
`delayed_bug` calls and one `Ty::new_error_with_message` call. This is
possible because we store error guarantees in
`DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
alongside calls to `has_errors`, which is a nice simplification, and
eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
error message.
Fixes #121451.
Fixes #121477.
Fixes #121504.
Fixes #121508.
2024-02-26 15:21:01 +11:00
self . dcx ( )
. try_steal_modify_and_emit_err ( ident . span , StashKey ::LifetimeIsChar , | err | {
err . span_suggestion_verbose (
2024-01-29 09:28:10 +11:00
ident . span . shrink_to_hi ( ) ,
2022-09-01 18:48:09 +00:00
" add `'` to close the char literal " ,
" ' " ,
Applicability ::MaybeIncorrect ,
Overhaul how stashed diagnostics work, again.
Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. #120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.
This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
disallowing the use of `steal_diagnostic` with errors, and introducing
the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
that can be used instead.
Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
return `Option<ErrorGuaranteed>`, which enables the removal of two
`delayed_bug` calls and one `Ty::new_error_with_message` call. This is
possible because we store error guarantees in
`DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
alongside calls to `has_errors`, which is a nice simplification, and
eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
error message.
Fixes #121451.
Fixes #121477.
Fixes #121504.
Fixes #121508.
2024-02-26 15:21:01 +11:00
) ;
} )
. unwrap_or_else ( | | {
err ( self )
. with_span_suggestion_verbose (
ident . span . shrink_to_hi ( ) ,
" add `'` to close the char literal " ,
" ' " ,
Applicability ::MaybeIncorrect ,
)
. emit ( )
} ) ;
2024-01-29 09:28:10 +11:00
let name = ident . without_first_quote ( ) . name ;
mk_lit_char ( name , ident . span )
2022-09-01 18:48:09 +00:00
}
2019-12-03 13:35:05 +01:00
/// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
2022-08-15 09:58:38 +10:00
fn recover_do_catch ( & mut self ) -> PResult < ' a , P < Expr > > {
2019-12-03 13:35:05 +01:00
let lo = self . token . span ;
self . bump ( ) ; // `do`
self . bump ( ) ; // `catch`
2022-08-17 19:05:49 +02:00
let span = lo . to ( self . prev_token . span ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::DoCatchSyntaxRemoved { span } ) ;
2019-12-03 13:35:05 +01:00
2022-08-15 09:58:38 +10:00
self . parse_try_block ( lo )
2019-12-03 13:35:05 +01:00
}
2019-12-03 14:01:24 +01:00
/// Parse an expression if the token can begin one.
fn parse_expr_opt ( & mut self ) -> PResult < ' a , Option < P < Expr > > > {
Ok ( if self . token . can_begin_expr ( ) { Some ( self . parse_expr ( ) ? ) } else { None } )
}
/// Parse `"return" expr?`.
2023-02-24 04:38:45 +01:00
fn parse_expr_return ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-02-29 14:56:15 +03:00
let lo = self . prev_token . span ;
2019-12-03 14:01:24 +01:00
let kind = ExprKind ::Ret ( self . parse_expr_opt ( ) ? ) ;
2022-08-15 09:58:38 +10:00
let expr = self . mk_expr ( lo . to ( self . prev_token . span ) , kind ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2019-12-03 14:01:24 +01:00
}
2022-03-25 23:43:54 -07:00
/// Parse `"do" "yeet" expr?`.
2023-02-24 04:38:45 +01:00
fn parse_expr_yeet ( & mut self ) -> PResult < ' a , P < Expr > > {
2022-03-25 23:43:54 -07:00
let lo = self . token . span ;
self . bump ( ) ; // `do`
self . bump ( ) ; // `yeet`
let kind = ExprKind ::Yeet ( self . parse_expr_opt ( ) ? ) ;
let span = lo . to ( self . prev_token . span ) ;
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::yeet_expr , span ) ;
2022-08-15 09:58:38 +10:00
let expr = self . mk_expr ( span , kind ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2022-03-25 23:43:54 -07:00
}
2022-11-16 18:36:17 +00:00
/// Parse `"become" expr`, with `"become"` token already eaten.
fn parse_expr_become ( & mut self ) -> PResult < ' a , P < Expr > > {
let lo = self . prev_token . span ;
let kind = ExprKind ::Become ( self . parse_expr ( ) ? ) ;
let span = lo . to ( self . prev_token . span ) ;
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::explicit_tail_calls , span ) ;
2022-11-16 18:36:17 +00:00
let expr = self . mk_expr ( span , kind ) ;
self . maybe_recover_from_bad_qpath ( expr )
}
2021-07-10 16:38:55 +02:00
/// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
/// If the label is followed immediately by a `:` token, the label and `:` are
/// parsed as part of the expression (i.e. a labeled loop). The language team has
/// decided in #87026 to require parentheses as a visual aid to avoid confusion if
/// the break expression of an unlabeled break is a labeled loop (as in
/// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
/// expression only gets a warning for compatibility reasons; and a labeled break
/// with a labeled loop does not even get a warning because there is no ambiguity.
2023-02-24 04:38:45 +01:00
fn parse_expr_break ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-02-29 14:56:15 +03:00
let lo = self . prev_token . span ;
2021-07-10 16:38:55 +02:00
let mut label = self . eat_label ( ) ;
2023-01-12 11:28:47 +00:00
let kind = if self . token = = token ::Colon
& & let Some ( label ) = label . take ( )
{
2021-07-10 16:38:55 +02:00
// The value expression can be a labeled loop, see issue #86948, e.g.:
// `loop { break 'label: loop { break 'label 42; }; }`
2023-02-24 04:38:45 +01:00
let lexpr = self . parse_expr_labeled ( label , true ) ? ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::LabeledLoopInBreak {
2022-08-24 22:41:51 +02:00
span : lexpr . span ,
2023-12-18 03:01:05 +00:00
sub : errors ::WrapInParentheses ::Expression {
2022-09-01 19:29:23 +02:00
left : lexpr . span . shrink_to_lo ( ) ,
right : lexpr . span . shrink_to_hi ( ) ,
2022-08-24 22:41:51 +02:00
} ,
} ) ;
2021-07-10 16:38:55 +02:00
Some ( lexpr )
2022-04-26 15:40:14 +03:00
} else if self . token ! = token ::OpenDelim ( Delimiter ::Brace )
2019-12-03 15:06:34 +01:00
| | ! self . restrictions . contains ( Restrictions ::NO_STRUCT_LITERAL )
{
2023-01-12 19:40:22 +00:00
let mut expr = self . parse_expr_opt ( ) ? ;
if let Some ( expr ) = & mut expr {
2021-07-10 16:38:55 +02:00
if label . is_some ( )
& & matches! (
expr . kind ,
ExprKind ::While ( _ , _ , None )
2023-12-08 14:51:50 -08:00
| ExprKind ::ForLoop { label : None , .. }
2022-11-02 21:22:24 -07:00
| ExprKind ::Loop ( _ , None , _ )
2021-07-10 16:38:55 +02:00
| ExprKind ::Block ( _ , None )
)
{
2024-05-20 17:47:54 +00:00
self . psess . buffer_lint (
2021-07-10 16:38:55 +02:00
BREAK_WITH_LABEL_AND_LOOP ,
lo . to ( expr . span ) ,
ast ::CRATE_NODE_ID ,
2024-02-29 16:40:44 +11:00
BuiltinLintDiag ::BreakWithLabelAndLoop ( expr . span ) ,
2021-07-10 16:38:55 +02:00
) ;
}
2023-01-12 19:40:22 +00:00
// Recover `break label aaaaa`
if self . may_recover ( )
& & let ExprKind ::Path ( None , p ) = & expr . kind
& & let [ segment ] = & * p . segments
& & let & ast ::PathSegment { ident , args : None , .. } = segment
& & let Some ( next ) = self . parse_expr_opt ( ) ?
{
label = Some ( self . recover_ident_into_label ( ident ) ) ;
* expr = next ;
}
2021-07-10 16:38:55 +02:00
}
2023-01-12 19:40:22 +00:00
2021-07-10 16:38:55 +02:00
expr
2019-12-03 15:06:34 +01:00
} else {
None
} ;
2022-08-15 09:58:38 +10:00
let expr = self . mk_expr ( lo . to ( self . prev_token . span ) , ExprKind ::Break ( label , kind ) ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2019-12-03 15:06:34 +01:00
}
2023-01-12 19:40:22 +00:00
/// Parse `"continue" label?`.
2023-02-24 04:38:45 +01:00
fn parse_expr_continue ( & mut self , lo : Span ) -> PResult < ' a , P < Expr > > {
2023-01-12 19:40:22 +00:00
let mut label = self . eat_label ( ) ;
// Recover `continue label` -> `continue 'label`
if self . may_recover ( )
& & label . is_none ( )
& & let Some ( ( ident , _ ) ) = self . token . ident ( )
{
self . bump ( ) ;
label = Some ( self . recover_ident_into_label ( ident ) ) ;
}
let kind = ExprKind ::Continue ( label ) ;
Ok ( self . mk_expr ( lo . to ( self . prev_token . span ) , kind ) )
}
2019-12-03 14:01:24 +01:00
/// Parse `"yield" expr?`.
2023-02-24 04:38:45 +01:00
fn parse_expr_yield ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-02-29 14:56:15 +03:00
let lo = self . prev_token . span ;
2025-03-18 12:19:43 -07:00
let kind = ExprKind ::Yield ( YieldKind ::Prefix ( self . parse_expr_opt ( ) ? ) ) ;
2020-02-29 14:56:15 +03:00
let span = lo . to ( self . prev_token . span ) ;
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::yield_expr , span ) ;
2022-08-15 09:58:38 +10:00
let expr = self . mk_expr ( span , kind ) ;
2022-05-19 15:51:49 +10:00
self . maybe_recover_from_bad_qpath ( expr )
2019-12-03 14:01:24 +01:00
}
2023-01-19 10:24:17 +01:00
/// Parse `builtin # ident(args,*)`.
fn parse_expr_builtin ( & mut self ) -> PResult < ' a , P < Expr > > {
2023-04-22 16:29:34 +02:00
self . parse_builtin ( | this , lo , ident | {
2024-03-20 22:13:15 -04:00
Ok ( match ident . name {
sym ::offset_of = > Some ( this . parse_expr_offset_of ( lo ) ? ) ,
sym ::type_ascribe = > Some ( this . parse_expr_type_ascribe ( lo ) ? ) ,
2024-09-13 14:00:10 -04:00
sym ::wrap_binder = > {
Some ( this . parse_expr_unsafe_binder_cast ( lo , UnsafeBinderCastKind ::Wrap ) ? )
}
sym ::unwrap_binder = > {
Some ( this . parse_expr_unsafe_binder_cast ( lo , UnsafeBinderCastKind ::Unwrap ) ? )
}
2024-03-20 22:13:15 -04:00
_ = > None ,
} )
2023-01-19 10:24:17 +01:00
} )
}
pub ( crate ) fn parse_builtin < T > (
& mut self ,
parse : impl FnOnce ( & mut Parser < ' a > , Span , Ident ) -> PResult < ' a , Option < T > > ,
) -> PResult < ' a , T > {
let lo = self . token . span ;
self . bump ( ) ; // `builtin`
self . bump ( ) ; // `#`
2024-02-13 23:28:27 +00:00
let Some ( ( ident , IdentIsRaw ::No ) ) = self . token . ident ( ) else {
2023-12-18 14:00:17 +11:00
let err = self . dcx ( ) . create_err ( errors ::ExpectedBuiltinIdent { span : self . token . span } ) ;
2023-01-19 10:24:17 +01:00
return Err ( err ) ;
} ;
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::builtin_syntax , ident . span ) ;
2023-01-19 10:24:17 +01:00
self . bump ( ) ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( OpenParen ) ) ? ;
2023-01-19 10:24:17 +01:00
let ret = if let Some ( res ) = parse ( self , lo , ident ) ? {
Ok ( res )
} else {
2023-12-18 14:00:17 +11:00
let err = self . dcx ( ) . create_err ( errors ::UnknownBuiltinConstruct {
span : lo . to ( ident . span ) ,
2025-01-27 01:16:12 +00:00
name : ident ,
2023-12-18 14:00:17 +11:00
} ) ;
2023-01-19 10:24:17 +01:00
return Err ( err ) ;
} ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( CloseParen ) ) ? ;
2023-01-19 10:24:17 +01:00
ret
}
2024-03-20 22:13:15 -04:00
/// Built-in macro for `offset_of!` expressions.
2023-04-22 16:29:34 +02:00
pub ( crate ) fn parse_expr_offset_of ( & mut self , lo : Span ) -> PResult < ' a , P < Expr > > {
let container = self . parse_ty ( ) ? ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( Comma ) ) ? ;
2023-04-22 16:29:34 +02:00
2024-01-02 22:12:35 +00:00
let fields = self . parse_floating_field_access ( ) ? ;
let trailing_comma = self . eat_noexpect ( & TokenKind ::Comma ) ;
2024-12-04 15:55:06 +11:00
if let Err ( mut e ) = self . expect_one_of ( & [ ] , & [ exp! ( CloseParen ) ] ) {
2024-01-02 22:12:35 +00:00
if trailing_comma {
e . note ( " unexpected third argument to offset_of " ) ;
} else {
e . note ( " offset_of expects dot-separated field and variant names " ) ;
}
e . emit ( ) ;
}
// Eat tokens until the macro call ends.
if self . may_recover ( ) {
while ! matches! ( self . token . kind , token ::CloseDelim ( .. ) | token ::Eof ) {
self . bump ( ) ;
}
}
2023-04-22 16:29:34 +02:00
let span = lo . to ( self . token . span ) ;
2024-01-02 22:12:35 +00:00
Ok ( self . mk_expr ( span , ExprKind ::OffsetOf ( container , fields ) ) )
2023-04-22 16:29:34 +02:00
}
2024-03-20 22:13:15 -04:00
/// Built-in macro for type ascription expressions.
pub ( crate ) fn parse_expr_type_ascribe ( & mut self , lo : Span ) -> PResult < ' a , P < Expr > > {
let expr = self . parse_expr ( ) ? ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( Comma ) ) ? ;
2024-03-20 22:13:15 -04:00
let ty = self . parse_ty ( ) ? ;
let span = lo . to ( self . token . span ) ;
Ok ( self . mk_expr ( span , ExprKind ::Type ( expr , ty ) ) )
}
2024-09-13 14:00:10 -04:00
pub ( crate ) fn parse_expr_unsafe_binder_cast (
& mut self ,
lo : Span ,
kind : UnsafeBinderCastKind ,
) -> PResult < ' a , P < Expr > > {
let expr = self . parse_expr ( ) ? ;
2024-12-04 15:55:06 +11:00
let ty = if self . eat ( exp! ( Comma ) ) { Some ( self . parse_ty ( ) ? ) } else { None } ;
2024-09-13 14:00:10 -04:00
let span = lo . to ( self . token . span ) ;
Ok ( self . mk_expr ( span , ExprKind ::UnsafeBinderCast ( kind , expr , ty ) ) )
}
2019-11-16 20:11:05 +03:00
/// Returns a string literal if the next token is a string literal.
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
/// and returns `None` if the next token is not literal at all.
2022-11-23 15:39:42 +11:00
pub fn parse_str_lit ( & mut self ) -> Result < ast ::StrLit , Option < MetaItemLit > > {
match self . parse_opt_meta_item_lit ( ) {
2019-11-10 17:04:12 +03:00
Some ( lit ) = > match lit . kind {
ast ::LitKind ::Str ( symbol_unescaped , style ) = > Ok ( ast ::StrLit {
style ,
2022-11-29 13:36:00 +11:00
symbol : lit . symbol ,
suffix : lit . suffix ,
2019-11-10 17:04:12 +03:00
span : lit . span ,
symbol_unescaped ,
} ) ,
_ = > Err ( Some ( lit ) ) ,
} ,
None = > Err ( None ) ,
}
}
2022-12-05 14:39:56 +11:00
pub ( crate ) fn mk_token_lit_char ( name : Symbol , span : Span ) -> ( token ::Lit , Span ) {
( token ::Lit { symbol : name , suffix : None , kind : token ::Char } , span )
}
fn mk_meta_item_lit_char ( name : Symbol , span : Span ) -> MetaItemLit {
ast ::MetaItemLit {
symbol : name ,
suffix : None ,
kind : ast ::LitKind ::Char ( name . as_str ( ) . chars ( ) . next ( ) . unwrap_or ( '_' ) ) ,
span ,
}
}
fn handle_missing_lit < L > (
& mut self ,
mk_lit_char : impl FnOnce ( Symbol , Span ) -> L ,
) -> PResult < ' a , L > {
2022-10-10 13:40:56 +11:00
let token = self . token . clone ( ) ;
let err = | self_ : & Self | {
let msg = format! ( " unexpected token: {} " , super ::token_descr ( & token ) ) ;
2023-12-18 21:09:22 +11:00
self_ . dcx ( ) . struct_span_err ( token . span , msg )
2022-10-10 13:40:56 +11:00
} ;
2024-01-29 09:47:02 +11:00
// On an error path, eagerly consider a lifetime to be an unclosed character lit, if that
// makes sense.
2024-09-05 05:43:55 -04:00
if let Some ( ( ident , IdentIsRaw ::No ) ) = self . token . lifetime ( )
2024-01-29 09:47:02 +11:00
& & could_be_unclosed_char_literal ( ident )
{
2022-10-10 13:40:56 +11:00
let lt = self . expect_lifetime ( ) ;
2022-12-05 14:39:56 +11:00
Ok ( self . recover_unclosed_char ( lt . ident , mk_lit_char , err ) )
2022-10-10 13:40:56 +11:00
} else {
Err ( err ( self ) )
}
2019-11-10 15:32:41 +03:00
}
2022-10-10 13:40:56 +11:00
pub ( super ) fn parse_token_lit ( & mut self ) -> PResult < ' a , ( token ::Lit , Span ) > {
self . parse_opt_token_lit ( )
. ok_or ( ( ) )
2022-12-05 14:39:56 +11:00
. or_else ( | ( ) | self . handle_missing_lit ( Parser ::mk_token_lit_char ) )
2022-10-10 13:40:56 +11:00
}
2022-11-23 15:39:42 +11:00
pub ( super ) fn parse_meta_item_lit ( & mut self ) -> PResult < ' a , MetaItemLit > {
2022-12-05 14:39:56 +11:00
self . parse_opt_meta_item_lit ( )
. ok_or ( ( ) )
. or_else ( | ( ) | self . handle_missing_lit ( Parser ::mk_meta_item_lit_char ) )
2022-10-10 13:40:56 +11:00
}
2024-04-18 21:31:17 +10:00
fn recover_after_dot ( & mut self ) {
2019-10-11 18:40:56 +02:00
if self . token = = token ::Dot {
2019-11-10 15:32:41 +03:00
// Attempt to recover `.4` as `0.4`. We don't currently have any syntax where
// dot would follow an optional literal, so we do this unconditionally.
2024-04-18 21:31:17 +10:00
let recovered = self . look_ahead ( 1 , | next_token | {
// If it's an integer that looks like a float, then recover as such.
//
// We will never encounter the exponent part of a floating
// point literal here, since there's no use of the exponent
// syntax that also constitutes a valid integer, so we need
// not check for that.
2019-10-11 18:40:56 +02:00
if let token ::Literal ( token ::Lit { kind : token ::Integer , symbol , suffix } ) =
next_token . kind
2024-04-18 21:31:17 +10:00
& & suffix . is_none_or ( | s | s = = sym ::f32 | | s = = sym ::f64 )
& & symbol . as_str ( ) . chars ( ) . all ( | c | c . is_numeric ( ) | | c = = '_' )
& & self . token . span . hi ( ) = = next_token . span . lo ( )
2019-10-11 18:40:56 +02:00
{
2024-04-18 21:31:17 +10:00
let s = String ::from ( " 0. " ) + symbol . as_str ( ) ;
let kind = TokenKind ::lit ( token ::Float , Symbol ::intern ( & s ) , suffix ) ;
Some ( Token ::new ( kind , self . token . span . to ( next_token . span ) ) )
} else {
None
2019-10-11 18:40:56 +02:00
}
} ) ;
2024-04-18 21:31:17 +10:00
if let Some ( recovered ) = recovered {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::FloatLiteralRequiresIntegerPart {
2024-04-18 21:31:17 +10:00
span : recovered . span ,
suggestion : recovered . span . shrink_to_lo ( ) ,
2022-08-24 22:41:51 +02:00
} ) ;
2024-04-18 21:31:17 +10:00
self . bump ( ) ;
self . token = recovered ;
2019-10-11 18:40:56 +02:00
}
}
2024-04-18 21:31:17 +10:00
}
2019-10-11 18:40:56 +02:00
2024-04-18 21:31:17 +10:00
/// Keep this in sync with `Token::can_begin_literal_maybe_minus` and
/// `Lit::from_token` (excluding unary negation).
fn eat_token_lit ( & mut self ) -> Option < token ::Lit > {
match self . token . uninterpolate ( ) . kind {
token ::Ident ( name , IdentIsRaw ::No ) if name . is_bool_lit ( ) = > {
self . bump ( ) ;
Some ( token ::Lit ::new ( token ::Bool , name , None ) )
}
token ::Literal ( token_lit ) = > {
self . bump ( ) ;
Some ( token_lit )
}
token ::OpenDelim ( Delimiter ::Invisible ( InvisibleOrigin ::MetaVar (
MetaVarKind ::Literal ,
) ) ) = > {
let lit = self
. eat_metavar_seq ( MetaVarKind ::Literal , | this | this . parse_literal_maybe_minus ( ) )
. expect ( " metavar seq literal " ) ;
let ast ::ExprKind ::Lit ( token_lit ) = lit . kind else {
panic! ( " didn't reparse a literal " ) ;
} ;
Some ( token_lit )
}
token ::OpenDelim ( Delimiter ::Invisible ( InvisibleOrigin ::MetaVar (
mv_kind @ MetaVarKind ::Expr { can_begin_literal_maybe_minus : true , .. } ,
) ) ) = > {
let expr = self
. eat_metavar_seq ( mv_kind , | this | this . parse_expr ( ) )
. expect ( " metavar seq expr " ) ;
let ast ::ExprKind ::Lit ( token_lit ) = expr . kind else {
panic! ( " didn't reparse an expr " ) ;
} ;
Some ( token_lit )
}
_ = > None ,
}
2019-10-11 18:40:56 +02:00
}
2022-10-10 13:40:56 +11:00
/// Matches `lit = true | false | token_lit`.
/// Returns `None` if the next token is not a literal.
2024-04-18 21:31:17 +10:00
fn parse_opt_token_lit ( & mut self ) -> Option < ( token ::Lit , Span ) > {
self . recover_after_dot ( ) ;
let span = self . token . span ;
self . eat_token_lit ( ) . map ( | token_lit | ( token_lit , span ) )
2022-10-10 13:40:56 +11:00
}
2022-01-17 22:13:15 +00:00
2022-10-10 13:40:56 +11:00
/// Matches `lit = true | false | token_lit`.
/// Returns `None` if the next token is not a literal.
2024-04-18 21:31:17 +10:00
fn parse_opt_meta_item_lit ( & mut self ) -> Option < MetaItemLit > {
self . recover_after_dot ( ) ;
let span = self . token . span ;
2025-03-26 15:54:14 +11:00
let uninterpolated_span = self . token_uninterpolated_span ( ) ;
2024-04-18 21:31:17 +10:00
self . eat_token_lit ( ) . map ( | token_lit | {
match MetaItemLit ::from_token_lit ( token_lit , span ) {
Ok ( lit ) = > lit ,
Err ( err ) = > {
let guar = report_lit_error ( & self . psess , err , token_lit , uninterpolated_span ) ;
// Pack possible quotes and prefixes from the original literal into
// the error literal's symbol so they can be pretty-printed faithfully.
let suffixless_lit = token ::Lit ::new ( token_lit . kind , token_lit . symbol , None ) ;
let symbol = Symbol ::intern ( & suffixless_lit . to_string ( ) ) ;
let token_lit = token ::Lit ::new ( token ::Err ( guar ) , symbol , token_lit . suffix ) ;
MetaItemLit ::from_token_lit ( token_lit , uninterpolated_span ) . unwrap ( )
2019-10-11 18:40:56 +02:00
}
}
2024-04-18 21:31:17 +10:00
} )
2019-10-11 18:40:56 +02:00
}
2022-09-15 10:12:09 +02:00
pub ( super ) fn expect_no_tuple_index_suffix ( & self , span : Span , suffix : Symbol ) {
if [ sym ::i32 , sym ::u32 , sym ::isize , sym ::usize ] . contains ( & suffix ) {
// #59553: warn instead of reject out of hand to allow the fix to percolate
// through the ecosystem when people fix their macros
2024-01-04 11:28:14 +11:00
self . dcx ( ) . emit_warn ( errors ::InvalidLiteralSuffixOnTupleIndex {
2022-09-15 10:12:09 +02:00
span ,
suffix ,
2024-08-21 00:57:58 -04:00
exception : true ,
2022-09-15 10:12:09 +02:00
} ) ;
} else {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::InvalidLiteralSuffixOnTupleIndex {
2023-02-05 03:26:33 +01:00
span ,
suffix ,
2024-08-21 00:57:58 -04:00
exception : false ,
2023-02-05 03:26:33 +01:00
} ) ;
2019-10-11 18:40:56 +02:00
}
}
2019-08-11 13:14:30 +02:00
/// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
2020-03-16 23:36:14 +01:00
/// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
2020-08-28 23:04:42 +02:00
pub fn parse_literal_maybe_minus ( & mut self ) -> PResult < ' a , P < Expr > > {
2024-04-18 21:31:17 +10:00
if let Some ( expr ) = self . eat_metavar_seq_with_matcher (
| mv_kind | matches! ( mv_kind , MetaVarKind ::Expr { .. } ) ,
| this | {
// FIXME(nnethercote) The `expr` case should only match if
2024-06-17 14:44:55 +10:00
// `e` is an `ExprKind::Lit` or an `ExprKind::Unary` containing
// an `UnOp::Neg` and an `ExprKind::Lit`, like how
// `can_begin_literal_maybe_minus` works. But this method has
// been over-accepting for a long time, and to make that change
// here requires also changing some `parse_literal_maybe_minus`
// call sites to accept additional expression kinds. E.g.
// `ExprKind::Path` must be accepted when parsing range
// patterns. That requires some care. So for now, we continue
// being less strict here than we should be.
2024-04-18 21:31:17 +10:00
this . parse_expr ( )
} ,
) {
return Ok ( expr ) ;
} else if let Some ( lit ) =
self . eat_metavar_seq ( MetaVarKind ::Literal , | this | this . parse_literal_maybe_minus ( ) )
{
return Ok ( lit ) ;
2024-06-17 14:44:55 +10:00
}
2019-08-11 13:14:30 +02:00
let lo = self . token . span ;
2024-12-04 15:55:06 +11:00
let minus_present = self . eat ( exp! ( Minus ) ) ;
2022-10-10 13:40:56 +11:00
let ( token_lit , span ) = self . parse_token_lit ( ) ? ;
let expr = self . mk_expr ( span , ExprKind ::Lit ( token_lit ) ) ;
2019-08-11 13:14:30 +02:00
if minus_present {
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr ( lo . to ( self . prev_token . span ) , self . mk_unary ( UnOp ::Neg , expr ) ) )
2019-08-11 13:14:30 +02:00
} else {
Ok ( expr )
}
}
Suggest replacing braces for brackets on array-esque invalid block expr
Newcomers may write `{1, 2, 3}` for making arrays, and the current error
message is not informative enough to quickly convince them what is
needed to fix the error.
This PR implements a diagnostic for this case, and its output looks like
this:
```text
error: this code is interpreted as a block expression, not an array
--> src/lib.rs:1:22
|
1 | const FOO: [u8; 3] = {
| ______________________^
2 | | 1, 2, 3
3 | | };
| |_^
|
= note: to define an array, one would use square brackets instead of curly braces
help: try using [] instead of {}
|
1 | const FOO: [u8; 3] = [
2 | 1, 2, 3
3 | ];
|
```
Fix #87672
2021-08-07 04:34:29 +09:00
fn is_array_like_block ( & mut self ) -> bool {
2025-03-20 15:46:19 +00:00
matches! ( self . token . kind , TokenKind ::OpenDelim ( Delimiter ::Brace ) )
& & self
. look_ahead ( 1 , | t | matches! ( t . kind , TokenKind ::Ident ( .. ) | TokenKind ::Literal ( _ ) ) )
Suggest replacing braces for brackets on array-esque invalid block expr
Newcomers may write `{1, 2, 3}` for making arrays, and the current error
message is not informative enough to quickly convince them what is
needed to fix the error.
This PR implements a diagnostic for this case, and its output looks like
this:
```text
error: this code is interpreted as a block expression, not an array
--> src/lib.rs:1:22
|
1 | const FOO: [u8; 3] = {
| ______________________^
2 | | 1, 2, 3
3 | | };
| |_^
|
= note: to define an array, one would use square brackets instead of curly braces
help: try using [] instead of {}
|
1 | const FOO: [u8; 3] = [
2 | 1, 2, 3
3 | ];
|
```
Fix #87672
2021-08-07 04:34:29 +09:00
& & self . look_ahead ( 2 , | t | t = = & token ::Comma )
& & self . look_ahead ( 3 , | t | t . can_begin_expr ( ) )
}
/// Emits a suggestion if it looks like the user meant an array but
/// accidentally used braces, causing the code to be interpreted as a block
/// expression.
2022-08-15 09:58:38 +10:00
fn maybe_suggest_brackets_instead_of_braces ( & mut self , lo : Span ) -> Option < P < Expr > > {
2022-03-10 22:11:00 +09:00
let mut snapshot = self . create_snapshot_for_diagnostic ( ) ;
2024-12-04 15:55:06 +11:00
match snapshot . parse_expr_array_or_repeat ( exp! ( CloseBrace ) ) {
Suggest replacing braces for brackets on array-esque invalid block expr
Newcomers may write `{1, 2, 3}` for making arrays, and the current error
message is not informative enough to quickly convince them what is
needed to fix the error.
This PR implements a diagnostic for this case, and its output looks like
this:
```text
error: this code is interpreted as a block expression, not an array
--> src/lib.rs:1:22
|
1 | const FOO: [u8; 3] = {
| ______________________^
2 | | 1, 2, 3
3 | | };
| |_^
|
= note: to define an array, one would use square brackets instead of curly braces
help: try using [] instead of {}
|
1 | const FOO: [u8; 3] = [
2 | 1, 2, 3
3 | ];
|
```
Fix #87672
2021-08-07 04:34:29 +09:00
Ok ( arr ) = > {
2025-03-20 15:46:19 +00:00
let guar = self . dcx ( ) . emit_err ( errors ::ArrayBracketsInsteadOfBraces {
2022-08-24 22:41:51 +02:00
span : arr . span ,
2025-03-20 15:46:19 +00:00
sub : errors ::ArrayBracketsInsteadOfBracesSugg {
2022-08-24 22:41:51 +02:00
left : lo ,
right : snapshot . prev_token . span ,
} ,
} ) ;
Suggest replacing braces for brackets on array-esque invalid block expr
Newcomers may write `{1, 2, 3}` for making arrays, and the current error
message is not informative enough to quickly convince them what is
needed to fix the error.
This PR implements a diagnostic for this case, and its output looks like
this:
```text
error: this code is interpreted as a block expression, not an array
--> src/lib.rs:1:22
|
1 | const FOO: [u8; 3] = {
| ______________________^
2 | | 1, 2, 3
3 | | };
| |_^
|
= note: to define an array, one would use square brackets instead of curly braces
help: try using [] instead of {}
|
1 | const FOO: [u8; 3] = [
2 | 1, 2, 3
3 | ];
|
```
Fix #87672
2021-08-07 04:34:29 +09:00
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( snapshot ) ;
2024-02-25 22:22:11 +01:00
Some ( self . mk_expr_err ( arr . span , guar ) )
Suggest replacing braces for brackets on array-esque invalid block expr
Newcomers may write `{1, 2, 3}` for making arrays, and the current error
message is not informative enough to quickly convince them what is
needed to fix the error.
This PR implements a diagnostic for this case, and its output looks like
this:
```text
error: this code is interpreted as a block expression, not an array
--> src/lib.rs:1:22
|
1 | const FOO: [u8; 3] = {
| ______________________^
2 | | 1, 2, 3
3 | | };
| |_^
|
= note: to define an array, one would use square brackets instead of curly braces
help: try using [] instead of {}
|
1 | const FOO: [u8; 3] = [
2 | 1, 2, 3
3 | ];
|
```
Fix #87672
2021-08-07 04:34:29 +09:00
}
2022-01-26 03:39:14 +00:00
Err ( e ) = > {
Suggest replacing braces for brackets on array-esque invalid block expr
Newcomers may write `{1, 2, 3}` for making arrays, and the current error
message is not informative enough to quickly convince them what is
needed to fix the error.
This PR implements a diagnostic for this case, and its output looks like
this:
```text
error: this code is interpreted as a block expression, not an array
--> src/lib.rs:1:22
|
1 | const FOO: [u8; 3] = {
| ______________________^
2 | | 1, 2, 3
3 | | };
| |_^
|
= note: to define an array, one would use square brackets instead of curly braces
help: try using [] instead of {}
|
1 | const FOO: [u8; 3] = [
2 | 1, 2, 3
3 | ];
|
```
Fix #87672
2021-08-07 04:34:29 +09:00
e . cancel ( ) ;
None
}
}
}
2022-08-10 02:29:28 +09:00
fn suggest_missing_semicolon_before_array (
& self ,
prev_span : Span ,
open_delim_span : Span ,
) -> PResult < ' a , ( ) > {
2022-10-28 20:44:26 +02:00
if ! self . may_recover ( ) {
return Ok ( ( ) ) ;
}
2024-08-09 17:44:47 +10:00
if self . token = = token ::Comma {
2024-03-04 16:31:49 +11:00
if ! self . psess . source_map ( ) . is_multiline ( prev_span . until ( self . token . span ) ) {
2022-09-07 03:59:47 +09:00
return Ok ( ( ) ) ;
}
2022-08-10 02:29:28 +09:00
let mut snapshot = self . create_snapshot_for_diagnostic ( ) ;
snapshot . bump ( ) ;
match snapshot . parse_seq_to_before_end (
2024-12-04 15:55:06 +11:00
exp! ( CloseBracket ) ,
SeqSep ::trailing_allowed ( exp! ( Comma ) ) ,
2022-08-10 02:29:28 +09:00
| p | p . parse_expr ( ) ,
) {
Ok ( _ )
// When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
// but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
// This is because the `token.kind` of the close delim is treated as the same as
// that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
// Therefore, `token.kind` should not be compared here.
if snapshot
. span_to_snippet ( snapshot . token . span )
2023-05-24 14:19:22 +00:00
. is_ok_and ( | snippet | snippet = = " ] " ) = >
2022-08-10 02:29:28 +09:00
{
2023-12-18 14:00:17 +11:00
return Err ( self . dcx ( ) . create_err ( errors ::MissingSemicolonBeforeArray {
2022-08-17 19:05:49 +02:00
open_delim : open_delim_span ,
semicolon : prev_span . shrink_to_hi ( ) ,
2023-12-18 14:00:17 +11:00
} ) ) ;
2022-08-10 02:29:28 +09:00
}
Ok ( _ ) = > ( ) ,
Err ( err ) = > err . cancel ( ) ,
}
}
Ok ( ( ) )
}
2019-08-11 13:14:30 +02:00
/// Parses a block or unsafe block.
2023-02-24 04:38:45 +01:00
pub ( super ) fn parse_expr_block (
2019-08-11 13:14:30 +02:00
& mut self ,
opt_label : Option < Label > ,
lo : Span ,
blk_mode : BlockCheckMode ,
) -> PResult < ' a , P < Expr > > {
2022-10-28 20:44:26 +02:00
if self . may_recover ( ) & & self . is_array_like_block ( ) {
2022-08-15 09:58:38 +10:00
if let Some ( arr ) = self . maybe_suggest_brackets_instead_of_braces ( lo ) {
Suggest replacing braces for brackets on array-esque invalid block expr
Newcomers may write `{1, 2, 3}` for making arrays, and the current error
message is not informative enough to quickly convince them what is
needed to fix the error.
This PR implements a diagnostic for this case, and its output looks like
this:
```text
error: this code is interpreted as a block expression, not an array
--> src/lib.rs:1:22
|
1 | const FOO: [u8; 3] = {
| ______________________^
2 | | 1, 2, 3
3 | | };
| |_^
|
= note: to define an array, one would use square brackets instead of curly braces
help: try using [] instead of {}
|
1 | const FOO: [u8; 3] = [
2 | 1, 2, 3
3 | ];
|
```
Fix #87672
2021-08-07 04:34:29 +09:00
return Ok ( arr ) ;
}
}
2020-03-05 05:49:30 +01:00
if self . token . is_whole_block ( ) {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::InvalidBlockMacroSegment {
2022-08-17 19:05:49 +02:00
span : self . token . span ,
context : lo . to ( self . token . span ) ,
2023-06-23 19:18:18 +00:00
wrap : errors ::WrapInExplicitBlock {
lo : self . token . span . shrink_to_lo ( ) ,
hi : self . token . span . shrink_to_hi ( ) ,
} ,
2022-08-17 19:05:49 +02:00
} ) ;
2020-03-05 05:49:30 +01:00
}
2019-08-11 13:14:30 +02:00
2025-03-24 00:12:53 +01:00
let ( attrs , blk ) = self . parse_block_common ( lo , blk_mode , None ) ? ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr_with_attrs ( blk . span , ExprKind ::Block ( blk , opt_label ) , attrs ) )
2019-08-11 13:14:30 +02:00
}
2022-05-22 16:06:36 -07:00
/// Parse a block which takes no attributes and has no label
fn parse_simple_block ( & mut self ) -> PResult < ' a , P < Expr > > {
let blk = self . parse_block ( ) ? ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr ( blk . span , ExprKind ::Block ( blk , None ) ) )
2022-05-22 16:06:36 -07:00
}
2022-06-02 20:15:05 +04:00
/// Parses a closure expression (e.g., `move |args| expr`).
2023-02-24 04:38:45 +01:00
fn parse_expr_closure ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-03-21 08:32:55 +01:00
let lo = self . token . span ;
2023-10-11 23:20:41 +00:00
let before = self . prev_token . clone ( ) ;
2024-12-04 15:55:06 +11:00
let binder = if self . check_keyword ( exp! ( For ) ) {
2022-06-02 20:15:05 +04:00
let lo = self . token . span ;
2024-06-28 19:37:21 -04:00
let ( lifetime_defs , _ ) = self . parse_late_bound_lifetime_defs ( ) ? ;
2022-06-02 20:15:05 +04:00
let span = lo . to ( self . prev_token . span ) ;
2020-03-21 08:32:55 +01:00
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::closure_lifetime_binder , span ) ;
2020-03-21 08:32:55 +01:00
2022-11-22 09:17:20 +11:00
ClosureBinder ::For { span , generic_params : lifetime_defs }
2022-06-02 20:15:05 +04:00
} else {
ClosureBinder ::NotPresent
} ;
2019-08-11 13:14:30 +02:00
2023-03-11 21:29:15 +00:00
let constness = self . parse_closure_constness ( ) ;
2022-12-20 16:15:55 +00:00
2019-08-11 13:14:30 +02:00
let movability =
2024-12-04 15:55:06 +11:00
if self . eat_keyword ( exp! ( Static ) ) { Movability ::Static } else { Movability ::Movable } ;
2019-08-11 13:14:30 +02:00
2025-03-26 15:54:14 +11:00
let coroutine_kind = if self . token_uninterpolated_span ( ) . at_least_rust_2018 ( ) {
2023-12-05 21:45:01 +00:00
self . parse_coroutine_kind ( Case ::Sensitive )
2020-03-05 00:34:57 +03:00
} else {
2023-11-30 16:39:56 -08:00
None
2020-03-05 00:34:57 +03:00
} ;
2019-08-11 13:14:30 +02:00
2020-12-18 17:32:26 +01:00
let capture_clause = self . parse_capture_clause ( ) ? ;
2022-11-09 20:39:28 +05:30
let ( fn_decl , fn_arg_span ) = self . parse_fn_block_decl ( ) ? ;
2020-02-29 14:56:15 +03:00
let decl_hi = self . prev_token . span ;
2025-03-20 15:44:44 +00:00
let mut body = match & fn_decl . output {
// No return type.
2020-02-15 12:10:59 +09:00
FnRetTy ::Default ( _ ) = > {
2023-09-08 10:14:36 +00:00
let restrictions =
self . restrictions - Restrictions ::STMT_EXPR - Restrictions ::ALLOW_LET ;
2023-10-11 23:20:41 +00:00
let prev = self . prev_token . clone ( ) ;
let token = self . token . clone ( ) ;
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
match self . parse_expr_res ( restrictions , attrs ) {
2024-08-06 17:16:40 +10:00
Ok ( ( expr , _ ) ) = > expr ,
2023-10-11 23:20:41 +00:00
Err ( err ) = > self . recover_closure_body ( err , before , prev , token , lo , decl_hi ) ? ,
}
2019-08-11 13:14:30 +02:00
}
2025-03-20 15:44:44 +00:00
// Explicit return type (`->`) needs block `-> T { }`.
FnRetTy ::Ty ( ty ) = > self . parse_closure_block_body ( ty . span ) ? ,
2019-08-11 13:14:30 +02:00
} ;
2023-12-05 21:45:01 +00:00
match coroutine_kind {
2024-11-06 17:53:59 +00:00
Some ( CoroutineKind ::Async { .. } ) = > { }
2023-12-05 21:45:01 +00:00
Some ( CoroutineKind ::Gen { span , .. } ) | Some ( CoroutineKind ::AsyncGen { span , .. } ) = > {
// Feature-gate `gen ||` and `async gen ||` closures.
// FIXME(gen_blocks): This perhaps should be a different gate.
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::gen_blocks , span ) ;
2023-12-05 21:45:01 +00:00
}
None = > { }
2020-09-09 15:16:34 -07:00
}
2024-08-09 17:44:47 +10:00
if self . token = = TokenKind ::Semi
2024-12-10 19:18:44 +11:00
& & let Some ( last ) = self . token_cursor . stack . last ( )
& & let Some ( TokenTree ::Delimited ( _ , _ , Delimiter ::Parenthesis , _ ) ) = last . curr ( )
2022-10-25 21:24:01 +02:00
& & self . may_recover ( )
2021-08-16 15:22:36 +02:00
{
// It is likely that the closure body is a block but where the
// braces have been removed. We will recover and eat the next
// statements later in the parsing process.
2024-02-25 22:22:11 +01:00
body = self . mk_expr_err (
body . span ,
self . dcx ( ) . span_delayed_bug ( body . span , " recovered a closure body as a block " ) ,
) ;
2021-08-16 15:22:36 +02:00
}
let body_span = body . span ;
let closure = self . mk_expr (
2019-08-11 13:14:30 +02:00
lo . to ( body . span ) ,
2022-09-08 10:52:51 +10:00
ExprKind ::Closure ( Box ::new ( ast ::Closure {
2022-06-02 20:15:05 +04:00
binder ,
capture_clause ,
2022-12-20 16:15:55 +00:00
constness ,
2023-12-05 21:45:01 +00:00
coroutine_kind ,
2022-06-02 20:15:05 +04:00
movability ,
2022-09-08 10:52:51 +10:00
fn_decl ,
2022-06-02 20:15:05 +04:00
body ,
2022-09-08 10:52:51 +10:00
fn_decl_span : lo . to ( decl_hi ) ,
2022-11-09 20:39:28 +05:30
fn_arg_span ,
2022-09-08 10:52:51 +10:00
} ) ) ,
2021-08-16 15:22:36 +02:00
) ;
// Disable recovery for closure body
let spans =
ClosureSpans { whole_closure : closure . span , closing_pipe : decl_hi , body : body_span } ;
self . current_closure = Some ( spans ) ;
Ok ( closure )
2019-08-11 13:14:30 +02:00
}
2025-03-20 15:44:44 +00:00
/// If an explicit return type is given, require a block to appear (RFC 968).
fn parse_closure_block_body ( & mut self , ret_span : Span ) -> PResult < ' a , P < Expr > > {
if self . may_recover ( )
& & self . token . can_begin_expr ( )
& & ! matches! ( self . token . kind , TokenKind ::OpenDelim ( Delimiter ::Brace ) )
& & ! self . token . is_whole_block ( )
{
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
let restrictions =
self . restrictions - Restrictions ::STMT_EXPR - Restrictions ::ALLOW_LET ;
let tok = self . token . clone ( ) ;
match self . parse_expr_res ( restrictions , AttrWrapper ::empty ( ) ) {
Ok ( ( expr , _ ) ) = > {
let descr = super ::token_descr ( & tok ) ;
let mut diag = self
. dcx ( )
. struct_span_err ( tok . span , format! ( " expected ` {{ `, found {descr} " ) ) ;
diag . span_label (
ret_span ,
" explicit return type requires closure body to be enclosed in braces " ,
) ;
diag . multipart_suggestion_verbose (
" wrap the expression in curly braces " ,
vec! [
( expr . span . shrink_to_lo ( ) , " { " . to_string ( ) ) ,
( expr . span . shrink_to_hi ( ) , " } " . to_string ( ) ) ,
] ,
Applicability ::MachineApplicable ,
) ;
diag . emit ( ) ;
return Ok ( expr ) ;
}
Err ( diag ) = > {
diag . cancel ( ) ;
self . restore_snapshot ( snapshot ) ;
}
}
}
let body_lo = self . token . span ;
self . parse_expr_block ( None , body_lo , BlockCheckMode ::Default )
}
2024-11-01 18:37:32 -03:00
/// Parses an optional `move` or `use` prefix to a closure-like construct.
2020-12-18 17:32:26 +01:00
fn parse_capture_clause ( & mut self ) -> PResult < ' a , CaptureBy > {
2024-12-04 15:55:06 +11:00
if self . eat_keyword ( exp! ( Move ) ) {
2023-11-04 19:39:32 +01:00
let move_kw_span = self . prev_token . span ;
2020-12-18 17:32:26 +01:00
// Check for `move async` and recover
2024-12-04 15:55:06 +11:00
if self . check_keyword ( exp! ( Async ) ) {
2020-12-18 17:32:26 +01:00
let move_async_span = self . token . span . with_lo ( self . prev_token . span . data ( ) . lo ) ;
2023-12-18 14:00:17 +11:00
Err ( self
. dcx ( )
. create_err ( errors ::AsyncMoveOrderIncorrect { span : move_async_span } ) )
2020-12-18 17:32:26 +01:00
} else {
2023-11-04 20:04:02 +01:00
Ok ( CaptureBy ::Value { move_kw : move_kw_span } )
2020-12-18 17:32:26 +01:00
}
2024-11-01 18:37:32 -03:00
} else if self . eat_keyword ( exp! ( Use ) ) {
let use_kw_span = self . prev_token . span ;
self . psess . gated_spans . gate ( sym ::ergonomic_clones , use_kw_span ) ;
// Check for `use async` and recover
if self . check_keyword ( exp! ( Async ) ) {
let use_async_span = self . token . span . with_lo ( self . prev_token . span . data ( ) . lo ) ;
Err ( self . dcx ( ) . create_err ( errors ::AsyncUseOrderIncorrect { span : use_async_span } ) )
} else {
Ok ( CaptureBy ::Use { use_kw : use_kw_span } )
}
2020-12-18 17:32:26 +01:00
} else {
Ok ( CaptureBy ::Ref )
}
2019-08-11 13:14:30 +02:00
}
2019-08-11 20:04:09 +02:00
/// Parses the `|arg, arg|` header of a closure.
2022-11-09 20:39:28 +05:30
fn parse_fn_block_decl ( & mut self ) -> PResult < ' a , ( P < FnDecl > , Span ) > {
let arg_start = self . token . span . lo ( ) ;
2024-12-04 15:55:06 +11:00
let inputs = if self . eat ( exp! ( OrOr ) ) {
2022-11-23 11:55:16 +11:00
ThinVec ::new ( )
2019-12-06 23:35:48 +01:00
} else {
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( Or ) ) ? ;
2019-12-06 23:35:48 +01:00
let args = self
. parse_seq_to_before_tokens (
2024-12-04 15:55:06 +11:00
& [ exp! ( Or ) ] ,
2024-06-05 17:02:18 -04:00
& [ & token ::OrOr ] ,
2024-12-04 15:55:06 +11:00
SeqSep ::trailing_allowed ( exp! ( Comma ) ) ,
2019-12-06 23:35:48 +01:00
| p | p . parse_fn_block_param ( ) ,
) ?
. 0 ;
self . expect_or ( ) ? ;
args
2019-08-11 20:04:09 +02:00
} ;
2022-11-09 20:39:28 +05:30
let arg_span = self . prev_token . span . with_lo ( arg_start ) ;
2020-10-15 21:21:45 +02:00
let output =
self . parse_ret_ty ( AllowPlus ::Yes , RecoverQPath ::Yes , RecoverReturnSign ::Yes ) ? ;
2019-08-11 20:04:09 +02:00
2022-11-09 20:39:28 +05:30
Ok ( ( P ( FnDecl { inputs , output } ) , arg_span ) )
2019-08-11 20:04:09 +02:00
}
2019-09-06 03:56:45 +01:00
/// Parses a parameter in a closure header (e.g., `|arg, arg|`).
2019-08-27 13:24:32 +02:00
fn parse_fn_block_param ( & mut self ) -> PResult < ' a , Param > {
2019-08-11 20:04:09 +02:00
let lo = self . token . span ;
2019-08-29 20:44:30 -03:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
self . collect_tokens ( None , attrs , ForceCollect ::No , | this , attrs | {
2023-08-03 00:00:56 +08:00
let pat = this . parse_pat_no_top_alt ( Some ( Expected ::ParameterName ) , None ) ? ;
2024-12-04 15:55:06 +11:00
let ty = if this . eat ( exp! ( Colon ) ) {
2021-01-22 13:28:08 -05:00
this . parse_ty ( ) ?
} else {
2023-07-30 16:42:16 +02:00
this . mk_ty ( pat . span , TyKind ::Infer )
2021-01-22 13:28:08 -05:00
} ;
Ok ( (
Param {
2022-08-17 12:34:33 +10:00
attrs ,
2021-01-22 13:28:08 -05:00
ty ,
pat ,
2022-07-23 17:46:20 +00:00
span : lo . to ( this . prev_token . span ) ,
2021-01-22 13:28:08 -05:00
id : DUMMY_NODE_ID ,
is_placeholder : false ,
} ,
2024-08-06 10:17:46 +10:00
Trailing ::from ( this . token = = token ::Comma ) ,
2024-08-06 17:16:40 +10:00
UsePreAttrPos ::No ,
2021-01-22 13:28:08 -05:00
) )
2019-08-11 20:04:09 +02:00
} )
}
2019-08-11 13:14:30 +02:00
/// Parses an `if` expression (`if` token already eaten).
2023-02-24 04:38:45 +01:00
fn parse_expr_if ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-02-29 14:56:15 +03:00
let lo = self . prev_token . span ;
2023-02-24 04:38:45 +01:00
let cond = self . parse_expr_cond ( ) ? ;
2022-08-15 09:58:38 +10:00
self . parse_if_after_cond ( lo , cond )
2022-05-22 16:06:36 -07:00
}
2022-08-15 09:58:38 +10:00
fn parse_if_after_cond ( & mut self , lo : Span , mut cond : P < Expr > ) -> PResult < ' a , P < Expr > > {
2022-05-27 21:58:48 -07:00
let cond_span = cond . span ;
// Tries to interpret `cond` as either a missing expression if it's a block,
// or as an unfinished expression if it's a binop and the RHS is a block.
// We could probably add more recoveries here too...
let mut recover_block_from_condition = | this : & mut Self | {
let block = match & mut cond . kind {
ExprKind ::Binary ( Spanned { span : binop_span , .. } , _ , right )
if let ExprKind ::Block ( _ , None ) = right . kind = >
{
2024-02-25 22:22:11 +01:00
let guar = this . dcx ( ) . emit_err ( errors ::IfExpressionMissingThenBlock {
2022-08-17 19:05:49 +02:00
if_span : lo ,
2023-01-23 20:31:45 -08:00
missing_then_block_sub :
2023-02-05 03:26:33 +01:00
errors ::IfExpressionMissingThenBlockSub ::UnfinishedCondition (
cond_span . shrink_to_lo ( ) . to ( * binop_span ) ,
2023-10-13 08:58:33 +00:00
) ,
2023-01-23 20:31:45 -08:00
let_else_sub : None ,
2022-08-17 19:05:49 +02:00
} ) ;
2024-02-25 22:22:11 +01:00
std ::mem ::replace ( right , this . mk_expr_err ( binop_span . shrink_to_hi ( ) , guar ) )
2022-05-27 21:58:48 -07:00
}
ExprKind ::Block ( _ , None ) = > {
2024-02-25 22:22:11 +01:00
let guar = this . dcx ( ) . emit_err ( errors ::IfExpressionMissingCondition {
2024-01-05 17:30:14 +03:00
if_span : lo . with_neighbor ( cond . span ) . shrink_to_hi ( ) ,
2024-03-04 16:31:49 +11:00
block_span : self . psess . source_map ( ) . start_point ( cond_span ) ,
2022-08-17 19:05:49 +02:00
} ) ;
2024-02-25 22:22:11 +01:00
std ::mem ::replace ( & mut cond , this . mk_expr_err ( cond_span . shrink_to_hi ( ) , guar ) )
2022-05-27 21:58:48 -07:00
}
_ = > {
return None ;
}
} ;
if let ExprKind ::Block ( block , _ ) = & block . kind {
Some ( block . clone ( ) )
} else {
unreachable! ( )
2021-12-01 22:36:50 +01:00
}
} ;
2022-05-27 21:58:48 -07:00
// Parse then block
let thn = if self . token . is_keyword ( kw ::Else ) {
if let Some ( block ) = recover_block_from_condition ( self ) {
block
2021-12-01 22:36:50 +01:00
} else {
2023-01-23 20:31:45 -08:00
let let_else_sub = matches! ( cond . kind , ExprKind ::Let ( .. ) )
2023-02-05 03:26:33 +01:00
. then ( | | errors ::IfExpressionLetSomeSub { if_span : lo . until ( cond_span ) } ) ;
2023-01-23 20:31:45 -08:00
2024-02-25 22:22:11 +01:00
let guar = self . dcx ( ) . emit_err ( errors ::IfExpressionMissingThenBlock {
2022-08-17 19:05:49 +02:00
if_span : lo ,
2023-02-05 03:26:33 +01:00
missing_then_block_sub : errors ::IfExpressionMissingThenBlockSub ::AddThenBlock (
2023-01-23 20:31:45 -08:00
cond_span . shrink_to_hi ( ) ,
) ,
let_else_sub ,
2022-08-17 19:05:49 +02:00
} ) ;
2024-02-25 22:22:11 +01:00
self . mk_block_err ( cond_span . shrink_to_hi ( ) , guar )
2021-12-01 22:36:50 +01:00
}
2019-12-06 23:23:30 +01:00
} else {
2022-11-13 13:08:58 +00:00
let attrs = self . parse_outer_attributes ( ) ? ; // For recovery.
2023-10-27 15:14:55 -07:00
let maybe_fatarrow = self . token . clone ( ) ;
2024-12-04 15:55:06 +11:00
let block = if self . check ( exp! ( OpenBrace ) ) {
2022-05-27 21:58:48 -07:00
self . parse_block ( ) ?
2024-09-11 17:23:56 -04:00
} else if let Some ( block ) = recover_block_from_condition ( self ) {
block
2022-05-27 21:58:48 -07:00
} else {
2024-09-11 17:23:56 -04:00
self . error_on_extra_if ( & cond ) ? ;
// Parse block, which will always fail, but we can add a nice note to the error
self . parse_block ( ) . map_err ( | mut err | {
2023-11-09 00:31:42 -08:00
if self . prev_token = = token ::Semi
& & self . token = = token ::AndAnd
& & let maybe_let = self . look_ahead ( 1 , | t | t . clone ( ) )
& & maybe_let . is_keyword ( kw ::Let )
{
err . span_suggestion (
self . prev_token . span ,
" consider removing this semicolon to parse the `let` as part of the same chain " ,
" " ,
Applicability ::MachineApplicable ,
) . span_note (
self . token . span . to ( maybe_let . span ) ,
" you likely meant to continue parsing the let-chain starting here " ,
) ;
} else {
2023-10-27 15:14:55 -07:00
// Look for usages of '=>' where '>=' might be intended
2024-08-09 17:44:47 +10:00
if maybe_fatarrow = = token ::FatArrow {
2023-10-27 15:14:55 -07:00
err . span_suggestion (
maybe_fatarrow . span ,
" you might have meant to write a \" greater than or equal to \" comparison " ,
" >= " ,
Applicability ::MaybeIncorrect ,
) ;
}
2023-11-09 00:31:42 -08:00
err . span_note (
cond_span ,
" the `if` expression is missing a block after this condition " ,
) ;
}
2022-05-27 21:58:48 -07:00
err
} ) ?
} ;
2022-11-13 13:08:58 +00:00
self . error_on_if_block_attrs ( lo , false , block . span , attrs ) ;
2020-03-07 17:16:29 +01:00
block
2019-12-06 23:23:30 +01:00
} ;
2024-12-04 15:55:06 +11:00
let els = if self . eat_keyword ( exp! ( Else ) ) { Some ( self . parse_expr_else ( ) ? ) } else { None } ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr ( lo . to ( self . prev_token . span ) , ExprKind ::If ( cond , thn , els ) ) )
2019-08-11 13:14:30 +02:00
}
2019-09-06 03:56:45 +01:00
/// Parses the condition of a `if` or `while` expression.
2025-03-14 18:50:41 +01:00
// Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions.
pub fn parse_expr_cond ( & mut self ) -> PResult < ' a , P < Expr > > {
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
let ( mut cond , _ ) =
2024-06-19 16:24:21 +10:00
self . parse_expr_res ( Restrictions ::NO_STRUCT_LITERAL | Restrictions ::ALLOW_LET , attrs ) ? ;
2022-08-20 20:40:08 +02:00
2023-11-22 23:27:15 +00:00
CondChecker ::new ( self ) . visit_expr ( & mut cond ) ;
2023-09-08 10:14:36 +00:00
2024-05-09 18:44:40 +10:00
if let ExprKind ::Let ( _ , _ , _ , Recovered ::No ) = cond . kind {
2022-08-20 20:40:08 +02:00
// Remove the last feature gating of a `let` expression since it's stable.
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . ungate_last ( sym ::let_chains , cond . span ) ;
2022-08-20 20:40:08 +02:00
}
Ok ( cond )
2019-08-11 13:14:30 +02:00
}
2022-08-01 01:13:16 +00:00
/// Parses a `let $pat = $expr` pseudo-expression.
2023-09-08 10:14:36 +00:00
fn parse_expr_let ( & mut self , restrictions : Restrictions ) -> PResult < ' a , P < Expr > > {
2024-05-09 18:44:40 +10:00
let recovered = if ! restrictions . contains ( Restrictions ::ALLOW_LET ) {
2023-10-11 23:20:41 +00:00
let err = errors ::ExpectedExpressionFoundLet {
2023-09-08 10:14:36 +00:00
span : self . token . span ,
2023-09-13 15:00:31 +00:00
reason : ForbiddenLetReason ::OtherForbidden ,
2023-11-22 23:27:15 +00:00
missing_let : None ,
comparison : None ,
2023-10-11 23:20:41 +00:00
} ;
2024-12-20 07:28:16 +11:00
if self . prev_token = = token ::Or {
2023-10-11 23:20:41 +00:00
// This was part of a closure, the that part of the parser recover.
2023-12-18 14:00:17 +11:00
return Err ( self . dcx ( ) . create_err ( err ) ) ;
2023-10-11 23:20:41 +00:00
} else {
2024-05-09 18:44:40 +10:00
Recovered ::Yes ( self . dcx ( ) . emit_err ( err ) )
2023-10-11 23:20:41 +00:00
}
2023-09-08 10:14:36 +00:00
} else {
2024-05-09 18:44:40 +10:00
Recovered ::No
2023-09-08 10:14:36 +00:00
} ;
2022-08-01 01:13:16 +00:00
self . bump ( ) ; // Eat `let` token
2020-02-29 14:56:15 +03:00
let lo = self . prev_token . span ;
2024-08-22 22:05:48 -07:00
let pat = self . parse_pat_no_top_guard (
2022-01-12 20:43:24 +00:00
None ,
RecoverComma ::Yes ,
RecoverColon ::Yes ,
CommaRecoveryMode ::LikelyTuple ,
) ? ;
2022-10-27 14:43:15 +08:00
if self . token = = token ::EqEq {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::ExpectedEqForLetExpr {
2022-10-27 14:43:15 +08:00
span : self . token . span ,
sugg_span : self . token . span ,
} ) ;
self . bump ( ) ;
} else {
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( Eq ) ) ? ;
2022-10-27 14:43:15 +08:00
}
2024-06-19 16:06:16 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-11-28 14:03:16 -08:00
let ( expr , _ ) =
self . parse_expr_assoc_with ( Bound ::Excluded ( prec_let_scrutinee_needs_par ( ) ) , attrs ) ? ;
2019-08-11 13:14:30 +02:00
let span = lo . to ( expr . span ) ;
2024-05-09 18:44:40 +10:00
Ok ( self . mk_expr ( span , ExprKind ::Let ( pat , expr , span , recovered ) ) )
2019-08-11 13:14:30 +02:00
}
2019-09-06 03:56:45 +01:00
/// Parses an `else { ... }` expression (`else` token already eaten).
2023-02-24 04:38:45 +01:00
fn parse_expr_else ( & mut self ) -> PResult < ' a , P < Expr > > {
2022-05-22 16:06:36 -07:00
let else_span = self . prev_token . span ; // `else`
2022-11-13 13:08:58 +00:00
let attrs = self . parse_outer_attributes ( ) ? ; // For recovery.
2024-12-04 15:55:06 +11:00
let expr = if self . eat_keyword ( exp! ( If ) ) {
2023-08-19 12:55:01 +02:00
ensure_sufficient_stack ( | | self . parse_expr_if ( ) ) ?
2024-12-04 15:55:06 +11:00
} else if self . check ( exp! ( OpenBrace ) ) {
2022-05-22 16:06:36 -07:00
self . parse_simple_block ( ) ?
2019-08-11 13:14:30 +02:00
} else {
2022-05-22 16:06:36 -07:00
let snapshot = self . create_snapshot_for_diagnostic ( ) ;
let first_tok = super ::token_descr ( & self . token ) ;
let first_tok_span = self . token . span ;
match self . parse_expr ( ) {
Ok ( cond )
2023-12-29 17:37:32 -08:00
// Try to guess the difference between a "condition-like" vs
// "statement-like" expression.
//
// We are seeing the following code, in which $cond is neither
// ExprKind::Block nor ExprKind::If (the 2 cases wherein this
// would be valid syntax).
//
// if ... {
// } else $cond
//
// If $cond is "condition-like" such as ExprKind::Binary, we
// want to suggest inserting `if`.
//
// if ... {
// } else if a == b {
// ^^
// }
//
2024-11-14 20:39:25 +00:00
// We account for macro calls that were meant as conditions as well.
//
// if ... {
// } else if macro! { foo bar } {
// ^^
// }
//
2023-12-29 17:37:32 -08:00
// If $cond is "statement-like" such as ExprKind::While then we
// want to suggest wrapping in braces.
//
// if ... {
// } else {
// ^
// while true {}
// }
// ^
2024-12-04 15:55:06 +11:00
if self . check ( exp! ( OpenBrace ) )
2024-11-14 20:39:25 +00:00
& & ( classify ::expr_requires_semi_to_be_stmt ( & cond )
| | matches! ( cond . kind , ExprKind ::MacCall ( .. ) ) )
= >
2022-05-22 16:06:36 -07:00
{
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::ExpectedElseBlock {
2022-08-17 19:05:49 +02:00
first_tok_span ,
first_tok ,
else_span ,
condition_start : cond . span . shrink_to_lo ( ) ,
} ) ;
2022-08-15 09:58:38 +10:00
self . parse_if_after_cond ( cond . span . shrink_to_lo ( ) , cond ) ?
2022-05-22 16:06:36 -07:00
}
Err ( e ) = > {
e . cancel ( ) ;
self . restore_snapshot ( snapshot ) ;
self . parse_simple_block ( ) ?
} ,
Ok ( _ ) = > {
self . restore_snapshot ( snapshot ) ;
self . parse_simple_block ( ) ?
} ,
}
2020-03-07 17:16:29 +01:00
} ;
2022-11-13 13:08:58 +00:00
self . error_on_if_block_attrs ( else_span , true , expr . span , attrs ) ;
2020-03-07 17:16:29 +01:00
Ok ( expr )
}
fn error_on_if_block_attrs (
& self ,
ctx_span : Span ,
is_ctx_else : bool ,
branch_span : Span ,
2022-11-13 13:08:58 +00:00
attrs : AttrWrapper ,
2020-03-07 17:16:29 +01:00
) {
2024-02-19 09:59:56 +11:00
if ! attrs . is_empty ( )
2024-03-04 16:31:49 +11:00
& & let [ x0 @ xn ] | [ x0 , .. , xn ] = & * attrs . take_for_recovery ( self . psess )
2024-02-19 09:59:56 +11:00
{
2024-07-06 03:07:46 +00:00
let attributes = x0 . span . until ( branch_span ) ;
2024-02-19 09:59:56 +11:00
let last = xn . span ;
let ctx = if is_ctx_else { " else " } else { " if " } ;
self . dcx ( ) . emit_err ( errors ::OuterAttributeNotAllowedOnIfElse {
last ,
branch_span ,
ctx_span ,
ctx : ctx . to_string ( ) ,
attributes ,
} ) ;
2022-11-13 13:08:58 +00:00
}
2019-08-11 13:14:30 +02:00
}
2022-11-15 08:53:17 +08:00
fn error_on_extra_if ( & mut self , cond : & P < Expr > ) -> PResult < ' a , ( ) > {
if let ExprKind ::Binary ( Spanned { span : binop_span , node : binop } , _ , right ) = & cond . kind
& & let BinOpKind ::And = binop
& & let ExprKind ::If ( cond , .. ) = & right . kind
{
2023-12-18 21:14:02 +11:00
Err ( self . dcx ( ) . create_err ( errors ::UnexpectedIfWithIf (
2023-02-05 03:26:33 +01:00
binop_span . shrink_to_hi ( ) . to ( cond . span . shrink_to_lo ( ) ) ,
) ) )
2022-11-15 08:53:17 +08:00
} else {
Ok ( ( ) )
}
}
2023-11-06 23:41:49 +00:00
fn parse_for_head ( & mut self ) -> PResult < ' a , ( P < Pat > , P < Expr > ) > {
2024-08-09 17:44:47 +10:00
let begin_paren = if self . token = = token ::OpenDelim ( Delimiter ::Parenthesis ) {
2023-11-06 23:41:49 +00:00
// Record whether we are about to parse `for (`.
// This is used below for recovery in case of `for ( $stuff ) $block`
// in which case we will suggest `for $stuff $block`.
let start_span = self . token . span ;
let left = self . prev_token . span . between ( self . look_ahead ( 1 , | t | t . span ) ) ;
2023-11-06 23:55:40 +00:00
Some ( ( start_span , left ) )
2023-11-06 23:41:49 +00:00
} else {
2023-11-06 23:55:40 +00:00
None
} ;
// Try to parse the pattern `for ($PAT) in $EXPR`.
let pat = match (
2024-11-24 17:36:52 +01:00
self . parse_pat_allow_top_guard (
2023-11-06 23:41:49 +00:00
None ,
RecoverComma ::Yes ,
RecoverColon ::Yes ,
CommaRecoveryMode ::LikelyTuple ,
2023-11-06 23:55:40 +00:00
) ,
begin_paren ,
) {
( Ok ( pat ) , _ ) = > pat , // Happy path.
2024-12-04 15:55:06 +11:00
( Err ( err ) , Some ( ( start_span , left ) ) ) if self . eat_keyword ( exp! ( In ) ) = > {
2023-11-06 23:55:40 +00:00
// We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
// happen right before the return of this method.
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
let ( expr , _ ) = match self . parse_expr_res ( Restrictions ::NO_STRUCT_LITERAL , attrs ) {
2023-11-06 23:55:40 +00:00
Ok ( expr ) = > expr ,
Err ( expr_err ) = > {
// We don't know what followed the `in`, so cancel and bubble up the
// original error.
expr_err . cancel ( ) ;
return Err ( err ) ;
}
} ;
2024-08-09 17:44:47 +10:00
return if self . token = = token ::CloseDelim ( Delimiter ::Parenthesis ) {
2023-11-06 23:55:40 +00:00
// We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
2024-03-27 21:19:17 +08:00
// parser state and emit a targeted suggestion.
2023-11-06 23:55:40 +00:00
let span = vec! [ start_span , self . token . span ] ;
let right = self . prev_token . span . between ( self . look_ahead ( 1 , | t | t . span ) ) ;
self . bump ( ) ; // )
err . cancel ( ) ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::ParenthesesInForHead {
2023-11-06 23:55:40 +00:00
span ,
// With e.g. `for (x) in y)` this would replace `(x) in y)`
// with `x) in y)` which is syntactically invalid.
// However, this is prevented before we get here.
sugg : errors ::ParenthesesInForHeadSugg { left , right } ,
} ) ;
Ok ( ( self . mk_pat ( start_span . to ( right ) , ast ::PatKind ::Wild ) , expr ) )
} else {
Err ( err ) // Some other error, bubble up.
} ;
}
( Err ( err ) , _ ) = > return Err ( err ) , // Some other error, bubble up.
2019-08-11 13:14:30 +02:00
} ;
2024-12-04 15:55:06 +11:00
if ! self . eat_keyword ( exp! ( In ) ) {
2019-12-06 22:41:10 +01:00
self . error_missing_in_for_loop ( ) ;
2019-08-11 13:14:30 +02:00
}
2020-02-29 14:56:15 +03:00
self . check_for_for_in_in_typo ( self . prev_token . span ) ;
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
let ( expr , _ ) = self . parse_expr_res ( Restrictions ::NO_STRUCT_LITERAL , attrs ) ? ;
2023-11-06 23:41:49 +00:00
Ok ( ( pat , expr ) )
}
2019-08-11 13:14:30 +02:00
2023-12-08 14:51:50 -08:00
/// Parses `for await? <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
2023-11-06 23:41:49 +00:00
fn parse_expr_for ( & mut self , opt_label : Option < Label > , lo : Span ) -> PResult < ' a , P < Expr > > {
2023-12-12 17:33:51 -08:00
let is_await =
2025-03-26 15:54:14 +11:00
self . token_uninterpolated_span ( ) . at_least_rust_2018 ( ) & & self . eat_keyword ( exp! ( Await ) ) ;
2023-12-08 14:51:50 -08:00
if is_await {
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::async_for_loop , self . prev_token . span ) ;
2023-12-08 14:51:50 -08:00
}
let kind = if is_await { ForLoopKind ::ForAwait } else { ForLoopKind ::For } ;
2023-11-06 23:41:49 +00:00
let ( pat , expr ) = self . parse_for_head ( ) ? ;
2023-02-03 12:23:37 +03:00
// Recover from missing expression in `for` loop
if matches! ( expr . kind , ExprKind ::Block ( .. ) )
2023-08-02 09:56:26 +10:00
& & ! matches! ( self . token . kind , token ::OpenDelim ( Delimiter ::Brace ) )
2023-02-03 12:23:37 +03:00
& & self . may_recover ( )
{
2024-02-25 22:22:11 +01:00
let guar = self
. dcx ( )
2023-02-03 12:23:37 +03:00
. emit_err ( errors ::MissingExpressionInForLoop { span : expr . span . shrink_to_lo ( ) } ) ;
2024-02-25 22:22:11 +01:00
let err_expr = self . mk_expr ( expr . span , ExprKind ::Err ( guar ) ) ;
2023-01-30 14:13:27 +11:00
let block = self . mk_block ( thin_vec! [ ] , BlockCheckMode ::Default , self . prev_token . span ) ;
2023-02-03 12:23:37 +03:00
return Ok ( self . mk_expr (
lo . to ( self . prev_token . span ) ,
ExprKind ::ForLoop { pat , iter : err_expr , body : block , label : opt_label , kind } ,
) ) ;
}
2025-03-17 00:25:15 -05:00
let ( attrs , loop_block ) = self . parse_inner_attrs_and_block (
// Only suggest moving erroneous block label to the loop header
// if there is not already a label there
opt_label . is_none ( ) . then_some ( lo ) ,
) ? ;
2019-08-11 13:14:30 +02:00
2023-12-08 14:51:50 -08:00
let kind = ExprKind ::ForLoop { pat , iter : expr , body : loop_block , label : opt_label , kind } ;
2023-02-23 20:12:01 +01:00
self . recover_loop_else ( " for " , lo ) ? ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr_with_attrs ( lo . to ( self . prev_token . span ) , kind , attrs ) )
2019-12-06 22:41:10 +01:00
}
2023-02-23 20:12:01 +01:00
/// Recovers from an `else` clause after a loop (`for...else`, `while...else`)
fn recover_loop_else ( & mut self , loop_kind : & 'static str , loop_kw : Span ) -> PResult < ' a , ( ) > {
if self . token . is_keyword ( kw ::Else ) & & self . may_recover ( ) {
let else_span = self . token . span ;
self . bump ( ) ;
let else_clause = self . parse_expr_else ( ) ? ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::LoopElseNotSupported {
2023-02-23 20:12:01 +01:00
span : else_span . to ( else_clause . span ) ,
loop_kind ,
loop_kw ,
} ) ;
}
Ok ( ( ) )
}
2020-08-08 20:53:40 -07:00
fn error_missing_in_for_loop ( & mut self ) {
2022-08-17 19:05:49 +02:00
let ( span , sub ) : ( _ , fn ( _ ) -> _ ) = if self . token . is_ident_named ( sym ::of ) {
2020-08-08 20:53:40 -07:00
// Possibly using JS syntax (#75311).
let span = self . token . span ;
self . bump ( ) ;
2023-02-05 03:26:33 +01:00
( span , errors ::MissingInInForLoopSub ::InNotOf )
2020-08-08 20:53:40 -07:00
} else {
2023-02-05 03:26:33 +01:00
( self . prev_token . span . between ( self . token . span ) , errors ::MissingInInForLoopSub ::AddIn )
2020-08-08 20:53:40 -07:00
} ;
2022-08-17 19:05:49 +02:00
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::MissingInInForLoop { span , sub : sub ( span ) } ) ;
2019-08-11 13:14:30 +02:00
}
/// Parses a `while` or `while let` expression (`while` token already eaten).
2023-02-24 04:38:45 +01:00
fn parse_expr_while ( & mut self , opt_label : Option < Label > , lo : Span ) -> PResult < ' a , P < Expr > > {
let cond = self . parse_expr_cond ( ) . map_err ( | mut err | {
2022-01-12 20:43:24 +00:00
err . span_label ( lo , " while parsing the condition of this `while` expression " ) ;
err
} ) ? ;
2025-03-17 00:25:15 -05:00
let ( attrs , body ) = self
. parse_inner_attrs_and_block (
// Only suggest moving erroneous block label to the loop header
// if there is not already a label there
opt_label . is_none ( ) . then_some ( lo ) ,
)
. map_err ( | mut err | {
err . span_label ( lo , " while parsing the body of this `while` expression " ) ;
err . span_label ( cond . span , " this `while` condition successfully parsed " ) ;
err
} ) ? ;
2023-02-23 20:12:01 +01:00
self . recover_loop_else ( " while " , lo ) ? ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr_with_attrs (
lo . to ( self . prev_token . span ) ,
ExprKind ::While ( cond , body , opt_label ) ,
attrs ,
) )
2019-08-11 13:14:30 +02:00
}
2019-09-06 03:56:45 +01:00
/// Parses `loop { ... }` (`loop` token already eaten).
2023-02-24 04:38:45 +01:00
fn parse_expr_loop ( & mut self , opt_label : Option < Label > , lo : Span ) -> PResult < ' a , P < Expr > > {
2022-11-02 21:22:24 -07:00
let loop_span = self . prev_token . span ;
2025-03-17 00:25:15 -05:00
let ( attrs , body ) = self . parse_inner_attrs_and_block (
// Only suggest moving erroneous block label to the loop header
// if there is not already a label there
opt_label . is_none ( ) . then_some ( lo ) ,
) ? ;
2023-02-23 20:12:01 +01:00
self . recover_loop_else ( " loop " , lo ) ? ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr_with_attrs (
lo . to ( self . prev_token . span ) ,
2022-11-02 21:22:24 -07:00
ExprKind ::Loop ( body , opt_label , loop_span ) ,
2022-08-15 09:58:38 +10:00
attrs ,
) )
2019-08-11 13:14:30 +02:00
}
2022-05-20 19:51:09 -04:00
pub ( crate ) fn eat_label ( & mut self ) -> Option < Label > {
2024-09-05 05:43:55 -04:00
if let Some ( ( ident , is_raw ) ) = self . token . lifetime ( ) {
2024-06-20 16:36:35 -04:00
// Disallow `'fn`, but with a better error message than `expect_lifetime`.
2024-09-05 05:43:55 -04:00
if matches! ( is_raw , IdentIsRaw ::No ) & & ident . without_first_quote ( ) . is_reserved ( ) {
2024-06-20 16:36:35 -04:00
self . dcx ( ) . emit_err ( errors ::InvalidLabel { span : ident . span , name : ident . name } ) ;
}
2019-08-11 13:14:30 +02:00
self . bump ( ) ;
2024-06-20 16:36:35 -04:00
Some ( Label { ident } )
} else {
None
}
2019-08-11 13:14:30 +02:00
}
2019-09-06 03:56:45 +01:00
/// Parses a `match ... { ... }` expression (`match` token already eaten).
2023-02-24 04:38:45 +01:00
fn parse_expr_match ( & mut self ) -> PResult < ' a , P < Expr > > {
2020-02-29 14:56:15 +03:00
let match_span = self . prev_token . span ;
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
let ( scrutinee , _ ) = self . parse_expr_res ( Restrictions ::NO_STRUCT_LITERAL , attrs ) ? ;
2024-02-15 19:54:35 -05:00
2024-02-17 12:43:54 -05:00
self . parse_match_block ( match_span , match_span , scrutinee , MatchKind ::Prefix )
2024-02-15 19:54:35 -05:00
}
2024-02-17 12:43:54 -05:00
/// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
/// expression. This is after the match token and scrutinee are eaten
2024-02-15 19:54:35 -05:00
fn parse_match_block (
& mut self ,
lo : Span ,
match_span : Span ,
scrutinee : P < Expr > ,
2024-02-17 12:43:54 -05:00
match_kind : MatchKind ,
2024-02-15 19:54:35 -05:00
) -> PResult < ' a , P < Expr > > {
2024-12-04 15:55:06 +11:00
if let Err ( mut e ) = self . expect ( exp! ( OpenBrace ) ) {
2019-08-11 13:14:30 +02:00
if self . token = = token ::Semi {
e . span_suggestion_short (
match_span ,
" try removing this `match` " ,
2022-06-13 15:48:40 +09:00
" " ,
2019-08-11 13:14:30 +02:00
Applicability ::MaybeIncorrect , // speculative
) ;
}
2025-03-17 00:25:15 -05:00
if self . maybe_recover_unexpected_block_label ( None ) {
2022-01-12 20:43:24 +00:00
e . cancel ( ) ;
self . bump ( ) ;
} else {
return Err ( e ) ;
}
2019-08-11 13:14:30 +02:00
}
2022-08-15 09:58:38 +10:00
let attrs = self . parse_inner_attributes ( ) ? ;
2019-08-11 13:14:30 +02:00
2023-01-30 15:10:59 +11:00
let mut arms = ThinVec ::new ( ) ;
2022-04-26 15:40:14 +03:00
while self . token ! = token ::CloseDelim ( Delimiter ::Brace ) {
2019-08-11 13:14:30 +02:00
match self . parse_arm ( ) {
Ok ( arm ) = > arms . push ( arm ) ,
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
Err ( e ) = > {
2019-08-11 13:14:30 +02:00
// Recover by skipping to the end of the block.
2024-02-01 22:45:00 +00:00
let guar = e . emit ( ) ;
2019-08-11 13:14:30 +02:00
self . recover_stmt ( ) ;
let span = lo . to ( self . token . span ) ;
2022-04-26 15:40:14 +03:00
if self . token = = token ::CloseDelim ( Delimiter ::Brace ) {
2019-08-11 13:14:30 +02:00
self . bump ( ) ;
}
2024-02-01 22:45:00 +00:00
// Always push at least one arm to make the match non-empty
arms . push ( Arm {
attrs : Default ::default ( ) ,
pat : self . mk_pat ( span , ast ::PatKind ::Err ( guar ) ) ,
guard : None ,
2024-02-25 22:22:11 +01:00
body : Some ( self . mk_expr_err ( span , guar ) ) ,
2024-02-01 22:45:00 +00:00
span ,
id : DUMMY_NODE_ID ,
is_placeholder : false ,
} ) ;
2022-08-15 09:58:38 +10:00
return Ok ( self . mk_expr_with_attrs (
span ,
2024-02-17 12:43:54 -05:00
ExprKind ::Match ( scrutinee , arms , match_kind ) ,
2022-08-15 09:58:38 +10:00
attrs ,
) ) ;
2019-08-11 13:14:30 +02:00
}
}
}
let hi = self . token . span ;
self . bump ( ) ;
2024-02-17 12:43:54 -05:00
Ok ( self . mk_expr_with_attrs ( lo . to ( hi ) , ExprKind ::Match ( scrutinee , arms , match_kind ) , attrs ) )
2019-08-11 13:14:30 +02:00
}
2021-02-25 19:29:50 -08:00
/// Attempt to recover from match arm body with statements and no surrounding braces.
fn parse_arm_body_missing_braces (
& mut self ,
first_expr : & P < Expr > ,
arrow_span : Span ,
2024-05-09 18:44:40 +10:00
) -> Option < ( Span , ErrorGuaranteed ) > {
2024-08-09 17:44:47 +10:00
if self . token ! = token ::Semi {
2021-02-25 19:29:50 -08:00
return None ;
}
2022-03-10 22:11:00 +09:00
let start_snapshot = self . create_snapshot_for_diagnostic ( ) ;
2021-02-25 19:29:50 -08:00
let semi_sp = self . token . span ;
self . bump ( ) ; // `;`
let mut stmts =
vec! [ self . mk_stmt ( first_expr . span , ast ::StmtKind ::Expr ( first_expr . clone ( ) ) ) ] ;
2022-08-24 22:41:51 +02:00
let err = | this : & Parser < '_ > , stmts : Vec < ast ::Stmt > | {
2021-02-25 19:29:50 -08:00
let span = stmts [ 0 ] . span . to ( stmts [ stmts . len ( ) - 1 ] . span ) ;
2022-08-24 22:41:51 +02:00
2024-02-25 22:22:11 +01:00
let guar = this . dcx ( ) . emit_err ( errors ::MatchArmBodyWithoutBraces {
2022-08-24 22:41:51 +02:00
statements : span ,
arrow : arrow_span ,
num_statements : stmts . len ( ) ,
sub : if stmts . len ( ) > 1 {
2023-02-05 03:26:33 +01:00
errors ::MatchArmBodyWithoutBracesSugg ::AddBraces {
2022-08-24 22:41:51 +02:00
left : span . shrink_to_lo ( ) ,
right : span . shrink_to_hi ( ) ,
}
} else {
2023-02-05 03:26:33 +01:00
errors ::MatchArmBodyWithoutBracesSugg ::UseComma { semicolon : semi_sp }
2022-08-24 22:41:51 +02:00
} ,
} ) ;
2024-05-09 18:44:40 +10:00
( span , guar )
2021-02-25 19:29:50 -08:00
} ;
// We might have either a `,` -> `;` typo, or a block without braces. We need
// a more subtle parsing strategy.
loop {
2024-08-09 17:44:47 +10:00
if self . token = = token ::CloseDelim ( Delimiter ::Brace ) {
2021-02-25 19:29:50 -08:00
// We have reached the closing brace of the `match` expression.
return Some ( err ( self , stmts ) ) ;
}
2024-08-09 17:44:47 +10:00
if self . token = = token ::Comma {
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( start_snapshot ) ;
2021-02-25 19:29:50 -08:00
return None ;
}
2022-03-10 22:11:00 +09:00
let pre_pat_snapshot = self . create_snapshot_for_diagnostic ( ) ;
2023-08-03 00:00:56 +08:00
match self . parse_pat_no_top_alt ( None , None ) {
2021-02-25 19:29:50 -08:00
Ok ( _pat ) = > {
2024-08-09 17:44:47 +10:00
if self . token = = token ::FatArrow {
2021-02-25 19:29:50 -08:00
// Reached arm end.
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( pre_pat_snapshot ) ;
2021-02-25 19:29:50 -08:00
return Some ( err ( self , stmts ) ) ;
}
}
2022-01-26 03:39:14 +00:00
Err ( err ) = > {
2021-02-25 19:29:50 -08:00
err . cancel ( ) ;
}
}
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( pre_pat_snapshot ) ;
2024-04-18 14:53:52 +10:00
match self . parse_stmt_without_recovery ( true , ForceCollect ::No , false ) {
2021-02-25 19:29:50 -08:00
// Consume statements for as long as possible.
Ok ( Some ( stmt ) ) = > {
stmts . push ( stmt ) ;
}
Ok ( None ) = > {
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( start_snapshot ) ;
2021-02-25 19:29:50 -08:00
break ;
}
// We couldn't parse either yet another statement missing it's
// enclosing block nor the next arm's pattern or closing brace.
2022-01-26 03:39:14 +00:00
Err ( stmt_err ) = > {
2021-02-25 19:29:50 -08:00
stmt_err . cancel ( ) ;
2022-03-10 22:11:00 +09:00
self . restore_snapshot ( start_snapshot ) ;
2021-02-25 19:29:50 -08:00
break ;
}
}
}
None
}
2019-10-08 09:35:34 +02:00
pub ( super ) fn parse_arm ( & mut self ) -> PResult < ' a , Arm > {
2019-08-11 13:14:30 +02:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
self . collect_tokens ( None , attrs , ForceCollect ::No , | this , attrs | {
2021-01-22 13:28:08 -05:00
let lo = this . token . span ;
2023-11-06 23:31:13 +00:00
let ( pat , guard ) = this . parse_match_arm_pat_and_guard ( ) ? ;
2023-11-27 03:15:56 +01:00
let span_before_body = this . prev_token . span ;
let arm_body ;
2024-12-04 15:55:06 +11:00
let is_fat_arrow = this . check ( exp! ( FatArrow ) ) ;
2025-01-22 16:50:22 +01:00
let is_almost_fat_arrow =
TokenKind ::FatArrow . similar_tokens ( ) . contains ( & this . token . kind ) ;
2023-12-28 15:02:17 +01:00
// this avoids the compiler saying that a `,` or `}` was expected even though
// the pattern isn't a never pattern (and thus an arm body is required)
let armless = ( ! is_fat_arrow & & ! is_almost_fat_arrow & & pat . could_be_never_pattern ( ) )
| | matches! ( this . token . kind , token ::Comma | token ::CloseDelim ( Delimiter ::Brace ) ) ;
let mut result = if armless {
2023-11-27 03:15:56 +01:00
// A pattern without a body, allowed for never patterns.
arm_body = None ;
2025-02-22 18:29:12 +00:00
let span = lo . to ( this . prev_token . span ) ;
2024-12-04 15:55:06 +11:00
this . expect_one_of ( & [ exp! ( Comma ) ] , & [ exp! ( CloseBrace ) ] ) . map ( | x | {
// Don't gate twice
if ! pat . contains_never_pattern ( ) {
2025-02-22 18:29:12 +00:00
this . psess . gated_spans . gate ( sym ::never_patterns , span ) ;
2024-12-04 15:55:06 +11:00
}
x
} )
2023-11-27 03:15:56 +01:00
} else {
2024-12-04 15:55:06 +11:00
if let Err ( mut err ) = this . expect ( exp! ( FatArrow ) ) {
2023-11-27 03:15:56 +01:00
// We might have a `=>` -> `=` or `->` typo (issue #89396).
if is_almost_fat_arrow {
err . span_suggestion (
this . token . span ,
" use a fat arrow to start a match arm " ,
" => " ,
Applicability ::MachineApplicable ,
) ;
if matches! (
( & this . prev_token . kind , & this . token . kind ) ,
( token ::DotDotEq , token ::Gt )
) {
// `error_inclusive_range_match_arrow` handles cases like `0..=> {}`,
// so we suppress the error here
err . delay_as_bug ( ) ;
} else {
err . emit ( ) ;
}
this . bump ( ) ;
2023-11-14 00:46:37 +00:00
} else {
2023-11-27 03:15:56 +01:00
return Err ( err ) ;
2023-11-14 00:46:37 +00:00
}
2021-10-03 14:14:35 +02:00
}
2023-11-27 03:15:56 +01:00
let arrow_span = this . prev_token . span ;
let arm_start_span = this . token . span ;
2019-08-11 13:14:30 +02:00
2024-06-19 16:24:21 +10:00
let attrs = this . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
let ( expr , _ ) =
2024-06-19 16:24:21 +10:00
this . parse_expr_res ( Restrictions ::STMT_EXPR , attrs ) . map_err ( | mut err | {
2023-11-27 03:15:56 +01:00
err . span_label ( arrow_span , " while parsing the `match` arm starting here " ) ;
err
} ) ? ;
2019-08-11 13:14:30 +02:00
2024-04-19 18:46:16 -07:00
let require_comma = ! classify ::expr_is_complete ( & expr )
& & this . token ! = token ::CloseDelim ( Delimiter ::Brace ) ;
2023-11-27 03:15:56 +01:00
if ! require_comma {
arm_body = Some ( expr ) ;
2024-07-29 21:21:15 -04:00
// Eat a comma if it exists, though.
2024-12-04 15:55:06 +11:00
let _ = this . eat ( exp! ( Comma ) ) ;
2024-02-13 23:44:33 +00:00
Ok ( Recovered ::No )
2024-05-09 18:44:40 +10:00
} else if let Some ( ( span , guar ) ) =
this . parse_arm_body_missing_braces ( & expr , arrow_span )
{
let body = this . mk_expr_err ( span , guar ) ;
2023-11-27 03:15:56 +01:00
arm_body = Some ( body ) ;
2024-05-09 18:44:40 +10:00
Ok ( Recovered ::Yes ( guar ) )
2023-11-27 03:15:56 +01:00
} else {
let expr_span = expr . span ;
arm_body = Some ( expr ) ;
2024-12-04 15:55:06 +11:00
this . expect_one_of ( & [ exp! ( Comma ) ] , & [ exp! ( CloseBrace ) ] ) . map_err ( | mut err | {
if this . token = = token ::FatArrow {
let sm = this . psess . source_map ( ) ;
if let Ok ( expr_lines ) = sm . span_to_lines ( expr_span )
& & let Ok ( arm_start_lines ) = sm . span_to_lines ( arm_start_span )
& & arm_start_lines . lines [ 0 ] . end_col = = expr_lines . lines [ 0 ] . end_col
& & expr_lines . lines . len ( ) = = 2
{
// We check whether there's any trailing code in the parse span,
// if there isn't, we very likely have the following:
//
// X | &Y => "y"
// | -- - missing comma
// | |
// | arrow_span
// X | &X => "x"
// | - ^^ self.token.span
// | |
// | parsed until here as `"y" & X`
err . span_suggestion_short (
arm_start_span . shrink_to_hi ( ) ,
" missing a comma here to end this `match` arm " ,
" , " ,
Applicability ::MachineApplicable ,
2021-01-22 13:28:08 -05:00
) ;
}
2024-12-04 15:55:06 +11:00
} else {
err . span_label (
arrow_span ,
" while parsing the `match` arm starting here " ,
) ;
}
err
} )
2023-11-27 03:15:56 +01:00
}
} ;
let hi_span = arm_body . as_ref ( ) . map_or ( span_before_body , | body | body . span ) ;
let arm_span = lo . to ( hi_span ) ;
// We want to recover:
// X | Some(_) => foo()
// | - missing comma
// X | None => "x"
// | ^^^^ self.token.span
// as well as:
// X | Some(!)
// | - missing comma
// X | None => "x"
// | ^^^^ self.token.span
// But we musn't recover
// X | pat[0] => {}
// | ^ self.token.span
let recover_missing_comma = arm_body . is_some ( ) | | pat . could_be_never_pattern ( ) ;
if recover_missing_comma {
result = result . or_else ( | err | {
// FIXME(compiler-errors): We could also recover `; PAT =>` here
// Try to parse a following `PAT =>`, if successful
// then we should recover.
let mut snapshot = this . create_snapshot_for_diagnostic ( ) ;
let pattern_follows = snapshot
2024-08-22 22:05:48 -07:00
. parse_pat_no_top_guard (
2023-11-27 03:15:56 +01:00
None ,
RecoverComma ::Yes ,
RecoverColon ::Yes ,
CommaRecoveryMode ::EitherTupleOrPipe ,
)
. map_err ( | err | err . cancel ( ) )
. is_ok ( ) ;
2024-12-04 15:55:06 +11:00
if pattern_follows & & snapshot . check ( exp! ( FatArrow ) ) {
2023-11-27 03:15:56 +01:00
err . cancel ( ) ;
2024-05-09 18:44:40 +10:00
let guar = this . dcx ( ) . emit_err ( errors ::MissingCommaAfterMatchArm {
2023-11-27 03:15:56 +01:00
span : arm_span . shrink_to_hi ( ) ,
} ) ;
2024-05-09 18:44:40 +10:00
return Ok ( Recovered ::Yes ( guar ) ) ;
2023-11-27 03:15:56 +01:00
}
Err ( err )
} ) ;
2021-01-22 13:28:08 -05:00
}
2023-11-27 03:15:56 +01:00
result ? ;
2019-08-11 13:14:30 +02:00
2021-01-22 13:28:08 -05:00
Ok ( (
ast ::Arm {
2022-08-17 12:34:33 +10:00
attrs ,
2021-01-22 13:28:08 -05:00
pat ,
guard ,
2023-11-27 03:15:56 +01:00
body : arm_body ,
span : arm_span ,
2021-01-22 13:28:08 -05:00
id : DUMMY_NODE_ID ,
is_placeholder : false ,
} ,
2024-08-06 10:17:46 +10:00
Trailing ::No ,
2024-08-06 17:16:40 +10:00
UsePreAttrPos ::No ,
2021-01-22 13:28:08 -05:00
) )
2019-08-11 13:14:30 +02:00
} )
}
2023-11-06 23:31:13 +00:00
fn parse_match_arm_guard ( & mut self ) -> PResult < ' a , Option < P < Expr > > > {
// Used to check the `let_chains` and `if_let_guard` features mostly by scanning
// `&&` tokens.
fn check_let_expr ( expr : & Expr ) -> ( bool , bool ) {
match & expr . kind {
ExprKind ::Binary ( BinOp { node : BinOpKind ::And , .. } , lhs , rhs ) = > {
let lhs_rslt = check_let_expr ( lhs ) ;
let rhs_rslt = check_let_expr ( rhs ) ;
( lhs_rslt . 0 | | rhs_rslt . 0 , false )
}
ExprKind ::Let ( .. ) = > ( true , true ) ,
_ = > ( false , true ) ,
}
}
2024-12-04 15:55:06 +11:00
if ! self . eat_keyword ( exp! ( If ) ) {
2023-11-06 23:31:13 +00:00
// No match arm guard present.
return Ok ( None ) ;
}
let if_span = self . prev_token . span ;
let mut cond = self . parse_match_guard_condition ( ) ? ;
CondChecker ::new ( self ) . visit_expr ( & mut cond ) ;
let ( has_let_expr , does_not_have_bin_op ) = check_let_expr ( & cond ) ;
if has_let_expr {
if does_not_have_bin_op {
// Remove the last feature gating of a `let` expression since it's stable.
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . ungate_last ( sym ::let_chains , cond . span ) ;
2023-11-06 23:31:13 +00:00
}
let span = if_span . to ( cond . span ) ;
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::if_let_guard , span ) ;
2023-11-06 23:31:13 +00:00
}
Ok ( Some ( cond ) )
}
fn parse_match_arm_pat_and_guard ( & mut self ) -> PResult < ' a , ( P < Pat > , Option < P < Expr > > ) > {
2024-08-09 17:44:47 +10:00
if self . token = = token ::OpenDelim ( Delimiter ::Parenthesis ) {
2023-11-06 23:31:13 +00:00
let left = self . token . span ;
2024-11-24 17:36:52 +01:00
let pat = self . parse_pat_no_top_guard (
2023-11-06 23:31:13 +00:00
None ,
RecoverComma ::Yes ,
RecoverColon ::Yes ,
CommaRecoveryMode ::EitherTupleOrPipe ,
2024-11-24 17:36:52 +01:00
) ? ;
if let ast ::PatKind ::Paren ( subpat ) = & pat . kind
& & let ast ::PatKind ::Guard ( .. ) = & subpat . kind
{
// Detect and recover from `($pat if $cond) => $arm`.
// FIXME(guard_patterns): convert this to a normal guard instead
let span = pat . span ;
let ast ::PatKind ::Paren ( subpat ) = pat . into_inner ( ) . kind else { unreachable! ( ) } ;
let ast ::PatKind ::Guard ( _ , mut cond ) = subpat . into_inner ( ) . kind else {
unreachable! ( )
} ;
self . psess . gated_spans . ungate_last ( sym ::guard_patterns , cond . span ) ;
CondChecker ::new ( self ) . visit_expr ( & mut cond ) ;
let right = self . prev_token . span ;
self . dcx ( ) . emit_err ( errors ::ParenthesesInMatchPat {
span : vec ! [ left , right ] ,
sugg : errors ::ParenthesesInMatchPatSugg { left , right } ,
} ) ;
Ok ( ( self . mk_pat ( span , ast ::PatKind ::Wild ) , Some ( cond ) ) )
} else {
Ok ( ( pat , self . parse_match_arm_guard ( ) ? ) )
2023-11-06 23:31:13 +00:00
}
} else {
// Regular parser flow:
2024-08-22 22:05:48 -07:00
let pat = self . parse_pat_no_top_guard (
2023-11-06 23:31:13 +00:00
None ,
RecoverComma ::Yes ,
RecoverColon ::Yes ,
CommaRecoveryMode ::EitherTupleOrPipe ,
) ? ;
Ok ( ( pat , self . parse_match_arm_guard ( ) ? ) )
}
}
2023-10-03 21:21:02 +00:00
fn parse_match_guard_condition ( & mut self ) -> PResult < ' a , P < Expr > > {
2024-06-19 16:24:21 +10:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-08-06 17:16:40 +10:00
match self . parse_expr_res ( Restrictions ::ALLOW_LET | Restrictions ::IN_IF_GUARD , attrs ) {
Ok ( ( expr , _ ) ) = > Ok ( expr ) ,
Err ( mut err ) = > {
2023-10-03 21:21:02 +00:00
if self . prev_token = = token ::OpenDelim ( Delimiter ::Brace ) {
let sugg_sp = self . prev_token . span . shrink_to_lo ( ) ;
// Consume everything within the braces, let's avoid further parse
// errors.
self . recover_stmt_ ( SemiColonMode ::Ignore , BlockMode ::Ignore ) ;
let msg = " you might have meant to start a match arm after the match guard " ;
2024-12-04 15:55:06 +11:00
if self . eat ( exp! ( CloseBrace ) ) {
2024-08-09 17:44:47 +10:00
let applicability = if self . token ! = token ::FatArrow {
2023-10-03 21:21:02 +00:00
// We have high confidence that we indeed didn't have a struct
// literal in the match guard, but rather we had some operation
// that ended in a path, immediately followed by a block that was
// meant to be the match arm.
Applicability ::MachineApplicable
} else {
Applicability ::MaybeIncorrect
} ;
2024-02-02 15:16:05 -08:00
err . span_suggestion_verbose ( sugg_sp , msg , " => " , applicability ) ;
2023-10-03 21:21:02 +00:00
}
}
2024-08-06 17:16:40 +10:00
Err ( err )
}
}
2023-10-03 21:21:02 +00:00
}
2023-01-19 10:24:17 +01:00
pub ( crate ) fn is_builtin ( & self ) -> bool {
self . token . is_keyword ( kw ::Builtin ) & & self . look_ahead ( 1 , | t | * t = = token ::Pound )
}
2019-08-11 13:14:30 +02:00
/// Parses a `try {...}` expression (`try` token already eaten).
2022-08-15 09:58:38 +10:00
fn parse_try_block ( & mut self , span_lo : Span ) -> PResult < ' a , P < Expr > > {
2025-03-17 00:25:15 -05:00
let ( attrs , body ) = self . parse_inner_attrs_and_block ( None ) ? ;
2024-12-04 15:55:06 +11:00
if self . eat_keyword ( exp! ( Catch ) ) {
2023-12-18 14:00:17 +11:00
Err ( self . dcx ( ) . create_err ( errors ::CatchAfterTry { span : self . prev_token . span } ) )
2019-08-11 13:14:30 +02:00
} else {
2019-09-21 23:09:17 +02:00
let span = span_lo . to ( body . span ) ;
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::try_blocks , span ) ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr_with_attrs ( span , ExprKind ::TryBlock ( body ) , attrs ) )
2019-08-11 13:14:30 +02:00
}
}
fn is_do_catch_block ( & self ) -> bool {
self . token . is_keyword ( kw ::Do )
& & self . is_keyword_ahead ( 1 , & [ kw ::Catch ] )
2023-06-23 05:31:14 +00:00
& & self
. look_ahead ( 2 , | t | * t = = token ::OpenDelim ( Delimiter ::Brace ) | | t . is_whole_block ( ) )
2019-08-11 13:14:30 +02:00
& & ! self . restrictions . contains ( Restrictions ::NO_STRUCT_LITERAL )
}
2022-03-25 23:43:54 -07:00
fn is_do_yeet ( & self ) -> bool {
self . token . is_keyword ( kw ::Do ) & & self . is_keyword_ahead ( 1 , & [ kw ::Yeet ] )
}
2019-08-11 13:14:30 +02:00
fn is_try_block ( & self ) -> bool {
2020-04-14 17:45:00 +02:00
self . token . is_keyword ( kw ::Try )
2023-06-23 05:31:14 +00:00
& & self
. look_ahead ( 1 , | t | * t = = token ::OpenDelim ( Delimiter ::Brace ) | | t . is_whole_block ( ) )
2025-03-26 15:54:14 +11:00
& & self . token_uninterpolated_span ( ) . at_least_rust_2018 ( )
2019-08-11 13:14:30 +02:00
}
2023-10-20 21:26:57 +00:00
/// Parses an `async move? {...}` or `gen move? {...}` expression.
fn parse_gen_block ( & mut self ) -> PResult < ' a , P < Expr > > {
2019-12-06 22:05:47 +01:00
let lo = self . token . span ;
2024-12-04 15:55:06 +11:00
let kind = if self . eat_keyword ( exp! ( Async ) ) {
if self . eat_keyword ( exp! ( Gen ) ) { GenBlockKind ::AsyncGen } else { GenBlockKind ::Async }
2023-10-20 21:26:57 +00:00
} else {
2024-12-04 15:55:06 +11:00
assert! ( self . eat_keyword ( exp! ( Gen ) ) ) ;
2023-10-20 21:26:57 +00:00
GenBlockKind ::Gen
} ;
2023-12-12 20:08:34 +00:00
match kind {
GenBlockKind ::Async = > {
// `async` blocks are stable
}
GenBlockKind ::Gen | GenBlockKind ::AsyncGen = > {
2024-03-04 16:31:49 +11:00
self . psess . gated_spans . gate ( sym ::gen_blocks , lo . to ( self . prev_token . span ) ) ;
2023-12-12 20:08:34 +00:00
}
}
2020-12-18 17:32:26 +01:00
let capture_clause = self . parse_capture_clause ( ) ? ;
2024-06-27 14:56:57 -04:00
let decl_span = lo . to ( self . prev_token . span ) ;
2025-03-17 00:25:15 -05:00
let ( attrs , body ) = self . parse_inner_attrs_and_block ( None ) ? ;
2024-06-27 14:56:57 -04:00
let kind = ExprKind ::Gen ( capture_clause , body , kind , decl_span ) ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr_with_attrs ( lo . to ( self . prev_token . span ) , kind , attrs ) )
2019-08-11 13:14:30 +02:00
}
2023-11-28 18:18:19 +00:00
fn is_gen_block ( & self , kw : Symbol , lookahead : usize ) -> bool {
self . is_keyword_ahead ( lookahead , & [ kw ] )
2019-08-11 13:14:30 +02:00
& & ( (
// `async move {`
2024-11-01 18:37:32 -03:00
self . is_keyword_ahead ( lookahead + 1 , & [ kw ::Move , kw ::Use ] )
2023-11-28 18:18:19 +00:00
& & self . look_ahead ( lookahead + 2 , | t | {
2023-06-23 05:31:14 +00:00
* t = = token ::OpenDelim ( Delimiter ::Brace ) | | t . is_whole_block ( )
} )
2019-08-11 13:14:30 +02:00
) | | (
// `async {`
2023-11-28 18:18:19 +00:00
self . look_ahead ( lookahead + 1 , | t | {
2023-06-23 05:31:14 +00:00
* t = = token ::OpenDelim ( Delimiter ::Brace ) | | t . is_whole_block ( )
} )
2019-08-11 13:14:30 +02:00
) )
}
2023-11-28 18:18:19 +00:00
pub ( super ) fn is_async_gen_block ( & self ) -> bool {
self . token . is_keyword ( kw ::Async ) & & self . is_gen_block ( kw ::Gen , 1 )
}
2019-12-04 04:31:44 +01:00
fn is_certainly_not_a_block ( & self ) -> bool {
2025-03-24 00:01:30 +01:00
// `{ ident, ` and `{ ident: ` cannot start a block.
2019-12-04 04:31:44 +01:00
self . look_ahead ( 1 , | t | t . is_ident ( ) )
2025-03-24 00:01:30 +01:00
& & self . look_ahead ( 2 , | t | t = = & token ::Comma | | t = = & token ::Colon )
2019-12-04 04:31:44 +01:00
}
2019-08-11 13:14:30 +02:00
fn maybe_parse_struct_expr (
& mut self ,
2022-09-08 10:52:51 +10:00
qself : & Option < P < ast ::QSelf > > ,
2019-08-11 13:14:30 +02:00
path : & ast ::Path ,
) -> Option < PResult < ' a , P < Expr > > > {
let struct_allowed = ! self . restrictions . contains ( Restrictions ::NO_STRUCT_LITERAL ) ;
2019-12-04 04:31:44 +01:00
if struct_allowed | | self . is_certainly_not_a_block ( ) {
2024-12-04 15:55:06 +11:00
if let Err ( err ) = self . expect ( exp! ( OpenBrace ) ) {
2020-08-12 15:39:15 -07:00
return Some ( Err ( err ) ) ;
}
2023-02-24 04:38:45 +01:00
let expr = self . parse_expr_struct ( qself . clone ( ) , path . clone ( ) , true ) ;
2019-08-11 13:14:30 +02:00
if let ( Ok ( expr ) , false ) = ( & expr , struct_allowed ) {
2020-08-12 15:39:15 -07:00
// This is a struct literal, but we don't can't accept them here.
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::StructLiteralNotAllowedHere {
2022-08-24 22:41:51 +02:00
span : expr . span ,
2023-02-05 03:26:33 +01:00
sub : errors ::StructLiteralNotAllowedHereSugg {
2022-08-24 22:41:51 +02:00
left : path . span . shrink_to_lo ( ) ,
right : expr . span . shrink_to_hi ( ) ,
} ,
} ) ;
2019-08-11 13:14:30 +02:00
}
return Some ( expr ) ;
}
None
}
2021-09-07 17:45:16 +00:00
pub ( super ) fn parse_struct_fields (
2019-08-11 13:14:30 +02:00
& mut self ,
pth : ast ::Path ,
2020-08-12 15:39:15 -07:00
recover : bool ,
2024-12-04 15:55:06 +11:00
close : ExpTokenPair < '_ > ,
2024-02-25 22:22:11 +01:00
) -> PResult <
' a ,
(
ThinVec < ExprField > ,
ast ::StructRest ,
Option < ErrorGuaranteed > , /* async blocks are forbidden in Rust 2015 */
) ,
> {
2023-01-30 15:39:22 +11:00
let mut fields = ThinVec ::new ( ) ;
2020-11-07 14:28:55 +00:00
let mut base = ast ::StructRest ::None ;
2024-02-25 22:22:11 +01:00
let mut recovered_async = None ;
2023-10-03 21:21:02 +00:00
let in_if_guard = self . restrictions . contains ( Restrictions ::IN_IF_GUARD ) ;
2019-08-11 13:14:30 +02:00
2024-02-23 10:20:45 +11:00
let async_block_err = | e : & mut Diag < '_ > , span : Span | {
2024-03-06 14:00:16 +11:00
errors ::AsyncBlockIn2015 { span } . add_to_diag ( e ) ;
errors ::HelpUseLatestEdition ::new ( ) . add_to_diag ( e ) ;
2020-05-01 18:24:14 -07:00
} ;
2024-12-04 15:55:06 +11:00
while self . token ! = * close . tok {
if self . eat ( exp! ( DotDot ) ) | | self . recover_struct_field_dots ( close . tok ) {
2020-02-29 14:56:15 +03:00
let exp_span = self . prev_token . span ;
2020-11-07 14:28:55 +00:00
// We permit `.. }` on the left-hand side of a destructuring assignment.
2024-12-04 15:55:06 +11:00
if self . check ( close ) {
2024-08-24 17:22:48 +00:00
base = ast ::StructRest ::Rest ( self . prev_token . span ) ;
2020-11-07 14:28:55 +00:00
break ;
}
2019-08-11 13:14:30 +02:00
match self . parse_expr ( ) {
2020-11-07 14:28:55 +00:00
Ok ( e ) = > base = ast ::StructRest ::Base ( e ) ,
Make `DiagnosticBuilder::emit` consuming.
This works for most of its call sites. This is nice, because `emit` very
much makes sense as a consuming operation -- indeed,
`DiagnosticBuilderState` exists to ensure no diagnostic is emitted
twice, but it uses runtime checks.
For the small number of call sites where a consuming emit doesn't work,
the commit adds `DiagnosticBuilder::emit_without_consuming`. (This will
be removed in subsequent commits.)
Likewise, `emit_unless` becomes consuming. And `delay_as_bug` becomes
consuming, while `delay_as_bug_without_consuming` is added (which will
also be removed in subsequent commits.)
All this requires significant changes to `DiagnosticBuilder`'s chaining
methods. Currently `DiagnosticBuilder` method chaining uses a
non-consuming `&mut self -> &mut Self` style, which allows chaining to
be used when the chain ends in `emit()`, like so:
```
struct_err(msg).span(span).emit();
```
But it doesn't work when producing a `DiagnosticBuilder` value,
requiring this:
```
let mut err = self.struct_err(msg);
err.span(span);
err
```
This style of chaining won't work with consuming `emit` though. For
that, we need to use to a `self -> Self` style. That also would allow
`DiagnosticBuilder` production to be chained, e.g.:
```
self.struct_err(msg).span(span)
```
However, removing the `&mut self -> &mut Self` style would require that
individual modifications of a `DiagnosticBuilder` go from this:
```
err.span(span);
```
to this:
```
err = err.span(span);
```
There are *many* such places. I have a high tolerance for tedious
refactorings, but even I gave up after a long time trying to convert
them all.
Instead, this commit has it both ways: the existing `&mut self -> Self`
chaining methods are kept, and new `self -> Self` chaining methods are
added, all of which have a `_mv` suffix (short for "move"). Changes to
the existing `forward!` macro lets this happen with very little
additional boilerplate code. I chose to add the suffix to the new
chaining methods rather than the existing ones, because the number of
changes required is much smaller that way.
This doubled chainging is a bit clumsy, but I think it is worthwhile
because it allows a *lot* of good things to subsequently happen. In this
commit, there are many `mut` qualifiers removed in places where
diagnostics are emitted without being modified. In subsequent commits:
- chaining can be used more, making the code more concise;
- more use of chaining also permits the removal of redundant diagnostic
APIs like `struct_err_with_code`, which can be replaced easily with
`struct_err` + `code_mv`;
- `emit_without_diagnostic` can be removed, which simplifies a lot of
machinery, removing the need for `DiagnosticBuilderState`.
2024-01-03 12:17:35 +11:00
Err ( e ) if recover = > {
2019-08-11 13:14:30 +02:00
e . emit ( ) ;
self . recover_stmt ( ) ;
}
2020-08-12 15:39:15 -07:00
Err ( e ) = > return Err ( e ) ,
2019-08-11 13:14:30 +02:00
}
2019-12-04 03:31:32 +01:00
self . recover_struct_comma_after_dotdot ( exp_span ) ;
2019-08-11 13:14:30 +02:00
break ;
}
2024-02-25 22:22:11 +01:00
// Peek the field's ident before parsing its expr in order to emit better diagnostics.
let peek = self
. token
. ident ( )
. filter ( | ( ident , is_raw ) | {
( ! ident . is_reserved ( ) | | matches! ( is_raw , IdentIsRaw ::Yes ) )
& & self . look_ahead ( 1 , | tok | * tok = = token ::Colon )
} )
. map ( | ( ident , _ ) | ident ) ;
// We still want a field even if its expr didn't parse.
let field_ident = | this : & Self , guar : ErrorGuaranteed | {
peek . map ( | ident | {
let span = ident . span ;
ExprField {
ident ,
span ,
expr : this . mk_expr_err ( span , guar ) ,
is_shorthand : false ,
attrs : AttrVec ::new ( ) ,
id : DUMMY_NODE_ID ,
is_placeholder : false ,
}
} )
} ;
2021-03-16 00:36:07 +03:00
let parsed_field = match self . parse_expr_field ( ) {
2024-02-25 22:22:11 +01:00
Ok ( f ) = > Ok ( f ) ,
2019-08-11 13:14:30 +02:00
Err ( mut e ) = > {
2020-05-01 18:24:14 -07:00
if pth = = kw ::Async {
async_block_err ( & mut e , pth . span ) ;
} else {
e . span_label ( pth . span , " while parsing this struct " ) ;
}
2022-11-16 21:46:06 +01:00
2023-10-03 21:21:02 +00:00
if let Some ( ( ident , _ ) ) = self . token . ident ( )
& & ! self . token . is_reserved_ident ( )
& & self . look_ahead ( 1 , | t | {
2023-11-21 20:07:32 +01:00
AssocOp ::from_token ( t ) . is_some ( )
2024-04-17 09:37:00 +10:00
| | matches! (
t . kind ,
token ::OpenDelim (
Delimiter ::Parenthesis
| Delimiter ::Bracket
| Delimiter ::Brace
)
)
2024-08-09 17:44:47 +10:00
| | * t = = token ::Dot
2023-10-03 21:21:02 +00:00
} )
{
2024-04-17 09:37:00 +10:00
// Looks like they tried to write a shorthand, complex expression,
// E.g.: `n + m`, `f(a)`, `a[i]`, `S { x: 3 }`, or `x.y`.
2023-10-03 21:21:02 +00:00
e . span_suggestion_verbose (
self . token . span . shrink_to_lo ( ) ,
" try naming a field " ,
& format! ( " {ident} : " , ) ,
2023-10-04 01:35:07 +00:00
Applicability ::MaybeIncorrect ,
2023-10-03 21:21:02 +00:00
) ;
}
2024-12-04 15:55:06 +11:00
if in_if_guard & & close . token_type = = TokenType ::CloseBrace {
2023-10-03 21:21:02 +00:00
return Err ( e ) ;
}
2022-11-16 21:46:06 +01:00
if ! recover {
return Err ( e ) ;
}
2024-02-25 22:22:11 +01:00
let guar = e . emit ( ) ;
if pth = = kw ::Async {
recovered_async = Some ( guar ) ;
}
2019-08-11 13:14:30 +02:00
// If the next token is a comma, then try to parse
// what comes next as additional fields, rather than
// bailing out until next `}`.
if self . token ! = token ::Comma {
self . recover_stmt_ ( SemiColonMode ::Comma , BlockMode ::Ignore ) ;
if self . token ! = token ::Comma {
break ;
}
}
2022-11-16 21:46:06 +01:00
2024-02-25 22:22:11 +01:00
Err ( guar )
2019-08-11 13:14:30 +02:00
}
2019-12-04 03:47:18 +01:00
} ;
2019-08-11 13:14:30 +02:00
2024-02-25 22:22:11 +01:00
let is_shorthand = parsed_field . as_ref ( ) . is_ok_and ( | f | f . is_shorthand ) ;
2022-07-07 14:59:54 -07:00
// A shorthand field can be turned into a full field with `:`.
// We should point this out.
2024-12-04 15:55:06 +11:00
self . check_or_expected ( ! is_shorthand , TokenType ::Colon ) ;
2022-07-07 14:59:54 -07:00
2024-12-04 15:55:06 +11:00
match self . expect_one_of ( & [ exp! ( Comma ) ] , & [ close ] ) {
2019-08-11 13:14:30 +02:00
Ok ( _ ) = > {
2024-04-07 17:59:11 +02:00
if let Ok ( f ) = parsed_field . or_else ( | guar | field_ident ( self , guar ) . ok_or ( guar ) )
2024-02-25 22:22:11 +01:00
{
2019-09-06 03:56:45 +01:00
// Only include the field if there's no parse error for the field name.
2019-08-11 13:14:30 +02:00
fields . push ( f ) ;
2019-12-22 17:42:04 -05:00
}
2019-08-11 13:14:30 +02:00
}
Err ( mut e ) = > {
2020-05-01 18:24:14 -07:00
if pth = = kw ::Async {
async_block_err ( & mut e , pth . span ) ;
} else {
e . span_label ( pth . span , " while parsing this struct " ) ;
2024-02-25 22:22:11 +01:00
if peek . is_some ( ) {
2020-05-01 18:24:14 -07:00
e . span_suggestion (
self . prev_token . span . shrink_to_hi ( ) ,
" try adding a comma " ,
2022-04-26 06:17:33 +01:00
" , " ,
2020-05-01 18:24:14 -07:00
Applicability ::MachineApplicable ,
) ;
}
2019-08-11 13:14:30 +02:00
}
2020-08-12 15:39:15 -07:00
if ! recover {
return Err ( e ) ;
}
2024-02-25 22:22:11 +01:00
let guar = e . emit ( ) ;
if pth = = kw ::Async {
recovered_async = Some ( guar ) ;
} else if let Some ( f ) = field_ident ( self , guar ) {
fields . push ( f ) ;
}
2019-08-11 13:14:30 +02:00
self . recover_stmt_ ( SemiColonMode ::Comma , BlockMode ::Ignore ) ;
2024-12-04 15:55:06 +11:00
let _ = self . eat ( exp! ( Comma ) ) ;
2019-08-11 13:14:30 +02:00
}
}
}
2024-02-25 22:22:11 +01:00
Ok ( ( fields , base , recovered_async ) )
2021-09-07 17:45:16 +00:00
}
2019-08-11 13:14:30 +02:00
2021-09-07 17:45:16 +00:00
/// Precondition: already parsed the '{'.
2023-02-24 04:38:45 +01:00
pub ( super ) fn parse_expr_struct (
2021-09-07 17:45:16 +00:00
& mut self ,
2022-09-08 10:52:51 +10:00
qself : Option < P < ast ::QSelf > > ,
2021-09-07 17:45:16 +00:00
pth : ast ::Path ,
recover : bool ,
) -> PResult < ' a , P < Expr > > {
let lo = pth . span ;
2024-02-25 22:22:11 +01:00
let ( fields , base , recovered_async ) =
2024-12-04 15:55:06 +11:00
self . parse_struct_fields ( pth . clone ( ) , recover , exp! ( CloseBrace ) ) ? ;
2021-09-07 17:45:16 +00:00
let span = lo . to ( self . token . span ) ;
2024-12-04 15:55:06 +11:00
self . expect ( exp! ( CloseBrace ) ) ? ;
2024-02-25 22:22:11 +01:00
let expr = if let Some ( guar ) = recovered_async {
ExprKind ::Err ( guar )
2021-03-16 03:15:53 +03:00
} else {
2020-12-10 13:20:07 +01:00
ExprKind ::Struct ( P ( ast ::StructExpr { qself , path : pth , fields , rest : base } ) )
2021-03-16 03:15:53 +03:00
} ;
2022-08-15 09:58:38 +10:00
Ok ( self . mk_expr ( span , expr ) )
2019-12-04 03:47:18 +01:00
}
2019-12-04 03:31:32 +01:00
fn recover_struct_comma_after_dotdot ( & mut self , span : Span ) {
if self . token ! = token ::Comma {
return ;
}
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::CommaAfterBaseStruct {
2022-08-17 19:05:49 +02:00
span : span . to ( self . prev_token . span ) ,
comma : self . token . span ,
} ) ;
2019-12-04 03:31:32 +01:00
self . recover_stmt ( ) ;
2019-08-11 13:14:30 +02:00
}
2024-12-04 15:55:06 +11:00
fn recover_struct_field_dots ( & mut self , close : & TokenKind ) -> bool {
if ! self . look_ahead ( 1 , | t | t = = close ) & & self . eat ( exp! ( DotDotDot ) ) {
2022-10-14 06:52:23 +08:00
// recover from typo of `...`, suggest `..`
let span = self . prev_token . span ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::MissingDotDot { token_span : span , sugg_span : span } ) ;
2022-10-14 06:52:23 +08:00
return true ;
}
false
}
2023-01-12 19:40:22 +00:00
/// Converts an ident into 'label and emits an "expected a label, found an identifier" error.
fn recover_ident_into_label ( & mut self , ident : Ident ) -> Label {
// Convert `label` -> `'label`,
// so that nameres doesn't complain about non-existing label
let label = format! ( " ' {} " , ident . name ) ;
let ident = Ident { name : Symbol ::intern ( & label ) , span : ident . span } ;
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::ExpectedLabelFoundIdent {
2023-04-27 01:53:06 +01:00
span : ident . span ,
start : ident . span . shrink_to_lo ( ) ,
} ) ;
2023-01-12 19:40:22 +00:00
Label { ident }
}
2019-09-06 03:56:45 +01:00
/// Parses `ident (COLON expr)?`.
2021-03-16 00:36:07 +03:00
fn parse_expr_field ( & mut self ) -> PResult < ' a , ExprField > {
2021-01-22 13:28:08 -05:00
let attrs = self . parse_outer_attributes ( ) ? ;
2024-05-08 14:22:09 +02:00
self . recover_vcs_conflict_marker ( ) ;
2024-08-06 17:16:40 +10:00
self . collect_tokens ( None , attrs , ForceCollect ::No , | this , attrs | {
2021-01-22 13:28:08 -05:00
let lo = this . token . span ;
2019-08-11 13:14:30 +02:00
2021-01-22 13:28:08 -05:00
// Check if a colon exists one ahead. This means we're parsing a fieldname.
let is_shorthand = ! this . look_ahead ( 1 , | t | t = = & token ::Colon | | t = = & token ::Eq ) ;
2023-10-04 01:35:07 +00:00
// Proactively check whether parsing the field will be incorrect.
2023-10-03 21:21:02 +00:00
let is_wrong = this . token . is_ident ( )
& & ! this . token . is_reserved_ident ( )
& & ! this . look_ahead ( 1 , | t | {
t = = & token ::Colon
| | t = = & token ::Eq
| | t = = & token ::Comma
| | t = = & token ::CloseDelim ( Delimiter ::Brace )
| | t = = & token ::CloseDelim ( Delimiter ::Parenthesis )
} ) ;
if is_wrong {
2023-12-18 14:00:17 +11:00
return Err ( this . dcx ( ) . create_err ( errors ::ExpectedStructField {
2023-10-03 21:21:02 +00:00
span : this . look_ahead ( 1 , | t | t . span ) ,
ident_span : this . token . span ,
token : this . look_ahead ( 1 , | t | t . clone ( ) ) ,
2023-12-18 14:00:17 +11:00
} ) ) ;
2023-10-03 21:21:02 +00:00
}
2021-01-22 13:28:08 -05:00
let ( ident , expr ) = if is_shorthand {
// Mimic `x: x` for the `x` field shorthand.
let ident = this . parse_ident_common ( false ) ? ;
let path = ast ::Path ::from_ident ( ident ) ;
2022-08-15 09:58:38 +10:00
( ident , this . mk_expr ( ident . span , ExprKind ::Path ( None , path ) ) )
2021-01-22 13:28:08 -05:00
} else {
let ident = this . parse_field_name ( ) ? ;
this . error_on_eq_field_init ( ident ) ;
this . bump ( ) ; // `:`
( ident , this . parse_expr ( ) ? )
} ;
Ok ( (
2021-03-16 00:36:07 +03:00
ast ::ExprField {
2021-01-22 13:28:08 -05:00
ident ,
span : lo . to ( expr . span ) ,
expr ,
is_shorthand ,
2022-08-17 12:34:33 +10:00
attrs ,
2021-01-22 13:28:08 -05:00
id : DUMMY_NODE_ID ,
is_placeholder : false ,
} ,
2024-08-06 10:17:46 +10:00
Trailing ::from ( this . token = = token ::Comma ) ,
2024-08-06 17:16:40 +10:00
UsePreAttrPos ::No ,
2021-01-22 13:28:08 -05:00
) )
2019-08-11 13:14:30 +02:00
} )
}
2019-12-04 03:23:20 +01:00
/// Check for `=`. This means the source incorrectly attempts to
/// initialize a field with an eq rather than a colon.
fn error_on_eq_field_init ( & self , field_name : Ident ) {
if self . token ! = token ::Eq {
return ;
}
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::EqFieldInit {
2022-08-17 19:05:49 +02:00
span : self . token . span ,
eq : field_name . span . shrink_to_hi ( ) . to ( self . token . span ) ,
} ) ;
2019-12-04 03:23:20 +01:00
}
2019-08-11 13:14:30 +02:00
fn err_dotdotdot_syntax ( & self , span : Span ) {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::DotDotDot { span } ) ;
2019-08-11 13:14:30 +02:00
}
2019-08-11 23:37:05 +02:00
fn err_larrow_operator ( & self , span : Span ) {
2023-12-18 21:14:02 +11:00
self . dcx ( ) . emit_err ( errors ::LeftArrowOperator { span } ) ;
2019-08-11 23:37:05 +02:00
}
2024-12-20 10:15:05 +11:00
fn mk_assign_op ( & self , assign_op : AssignOp , lhs : P < Expr > , rhs : P < Expr > ) -> ExprKind {
ExprKind ::AssignOp ( assign_op , lhs , rhs )
2019-08-11 13:14:30 +02:00
}
fn mk_range (
2021-06-25 19:46:41 -07:00
& mut self ,
2019-08-11 13:14:30 +02:00
start : Option < P < Expr > > ,
end : Option < P < Expr > > ,
limits : RangeLimits ,
2021-02-21 12:54:49 +01:00
) -> ExprKind {
2019-08-11 13:14:30 +02:00
if end . is_none ( ) & & limits = = RangeLimits ::Closed {
2024-02-25 22:22:11 +01:00
let guar = self . inclusive_range_with_incorrect_end ( ) ;
ExprKind ::Err ( guar )
2019-08-11 13:14:30 +02:00
} else {
2021-02-21 12:54:49 +01:00
ExprKind ::Range ( start , end , limits )
2019-08-11 13:14:30 +02:00
}
}
fn mk_unary ( & self , unop : UnOp , expr : P < Expr > ) -> ExprKind {
ExprKind ::Unary ( unop , expr )
}
fn mk_binary ( & self , binop : BinOp , lhs : P < Expr > , rhs : P < Expr > ) -> ExprKind {
ExprKind ::Binary ( binop , lhs , rhs )
}
2023-08-03 21:43:17 +02:00
fn mk_index ( & self , expr : P < Expr > , idx : P < Expr > , brackets_span : Span ) -> ExprKind {
ExprKind ::Index ( expr , idx , brackets_span )
2019-08-11 13:14:30 +02:00
}
2022-11-23 11:55:16 +11:00
fn mk_call ( & self , f : P < Expr > , args : ThinVec < P < Expr > > ) -> ExprKind {
2019-08-11 13:14:30 +02:00
ExprKind ::Call ( f , args )
}
2021-02-21 13:01:01 +01:00
fn mk_await_expr ( & mut self , self_arg : P < Expr > , lo : Span ) -> P < Expr > {
2020-02-29 14:56:15 +03:00
let span = lo . to ( self . prev_token . span ) ;
2023-04-25 18:59:16 +00:00
let await_expr = self . mk_expr ( span , ExprKind ::Await ( self_arg , self . prev_token . span ) ) ;
2019-08-11 13:14:30 +02:00
self . recover_from_await_method_call ( ) ;
2021-02-21 13:01:01 +01:00
await_expr
2019-08-11 13:14:30 +02:00
}
2024-10-02 16:35:37 -03:00
fn mk_use_expr ( & mut self , self_arg : P < Expr > , lo : Span ) -> P < Expr > {
let span = lo . to ( self . prev_token . span ) ;
let use_expr = self . mk_expr ( span , ExprKind ::Use ( self_arg , self . prev_token . span ) ) ;
self . recover_from_use ( ) ;
use_expr
}
2022-08-17 12:34:33 +10:00
pub ( crate ) fn mk_expr_with_attrs ( & self , span : Span , kind : ExprKind , attrs : AttrVec ) -> P < Expr > {
P ( Expr { kind , span , attrs , id : DUMMY_NODE_ID , tokens : None } )
2022-08-15 09:58:38 +10:00
}
pub ( crate ) fn mk_expr ( & self , span : Span , kind : ExprKind ) -> P < Expr > {
2024-01-05 17:29:57 +03:00
self . mk_expr_with_attrs ( span , kind , AttrVec ::new ( ) )
2019-08-11 13:14:30 +02:00
}
2019-10-08 14:39:58 +02:00
2024-02-25 22:22:11 +01:00
pub ( super ) fn mk_expr_err ( & self , span : Span , guar : ErrorGuaranteed ) -> P < Expr > {
self . mk_expr ( span , ExprKind ::Err ( guar ) )
2019-10-08 14:39:58 +02:00
}
2020-10-09 23:40:27 -05:00
2024-06-06 20:39:54 +00:00
/// Create expression span ensuring the span of the parent node
/// is larger than the span of lhs and rhs, including the attributes.
fn mk_expr_sp ( & self , lhs : & P < Expr > , lhs_span : Span , rhs_span : Span ) -> Span {
lhs . attrs
. iter ( )
. find ( | a | a . style = = AttrStyle ::Outer )
. map_or ( lhs_span , | a | a . span )
. to ( rhs_span )
}
2021-01-22 13:28:08 -05:00
fn collect_tokens_for_expr (
& mut self ,
attrs : AttrWrapper ,
2022-08-17 12:34:33 +10:00
f : impl FnOnce ( & mut Self , ast ::AttrVec ) -> PResult < ' a , P < Expr > > ,
2021-01-22 13:28:08 -05:00
) -> PResult < ' a , P < Expr > > {
2024-08-06 17:16:40 +10:00
self . collect_tokens ( None , attrs , ForceCollect ::No , | this , attrs | {
2021-01-22 13:28:08 -05:00
let res = f ( this , attrs ) ? ;
2024-08-06 10:17:46 +10:00
let trailing = Trailing ::from (
this . restrictions . contains ( Restrictions ::STMT_EXPR )
& & this . token = = token ::Semi
// FIXME: pass an additional condition through from the place
// where we know we need a comma, rather than assuming that
// `#[attr] expr,` always captures a trailing comma.
| | this . token = = token ::Comma ,
) ;
2024-08-06 17:16:40 +10:00
Ok ( ( res , trailing , UsePreAttrPos ::No ) )
2021-01-22 13:28:08 -05:00
} )
}
2019-08-11 13:14:30 +02:00
}
2023-09-08 10:14:36 +00:00
2024-01-29 09:47:02 +11:00
/// Could this lifetime/label be an unclosed char literal? For example, `'a`
/// could be, but `'abc` could not.
pub ( crate ) fn could_be_unclosed_char_literal ( ident : Ident ) -> bool {
ident . name . as_str ( ) . starts_with ( '\'' )
& & unescape_char ( ident . without_first_quote ( ) . name . as_str ( ) ) . is_ok ( )
}
2023-09-08 10:14:36 +00:00
/// Used to forbid `let` expressions in certain syntactic locations.
#[ derive(Clone, Copy, Subdiagnostic) ]
pub ( crate ) enum ForbiddenLetReason {
/// `let` is not valid and the source environment is not important
2023-09-13 15:00:31 +00:00
OtherForbidden ,
2023-09-08 10:14:36 +00:00
/// A let chain with the `||` operator
#[ note(parse_not_supported_or) ]
NotSupportedOr ( #[ primary_span ] Span ) ,
/// A let chain with invalid parentheses
///
/// For example, `let 1 = 1 && (expr && expr)` is allowed
/// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
#[ note(parse_not_supported_parentheses) ]
NotSupportedParentheses ( #[ primary_span ] Span ) ,
}
2023-09-13 15:00:31 +00:00
/// Visitor to check for invalid/unstable use of `ExprKind::Let` that can't
/// easily be caught in parsing. For example:
///
/// ```rust,ignore (example)
/// // Only know that the let isn't allowed once the `||` token is reached
/// if let Some(x) = y || true {}
/// // Only know that the let isn't allowed once the second `=` token is reached.
/// if let Some(x) = y && z = 1 {}
/// ```
2023-09-08 10:14:36 +00:00
struct CondChecker < ' a > {
parser : & ' a Parser < ' a > ,
forbid_let_reason : Option < ForbiddenLetReason > ,
2023-11-22 23:27:15 +00:00
missing_let : Option < errors ::MaybeMissingLet > ,
comparison : Option < errors ::MaybeComparison > ,
}
impl < ' a > CondChecker < ' a > {
fn new ( parser : & ' a Parser < ' a > ) -> Self {
CondChecker { parser , forbid_let_reason : None , missing_let : None , comparison : None }
}
2023-09-08 10:14:36 +00:00
}
impl MutVisitor for CondChecker < '_ > {
fn visit_expr ( & mut self , e : & mut P < Expr > ) {
use ForbiddenLetReason ::* ;
let span = e . span ;
match e . kind {
2024-05-09 18:44:40 +10:00
ExprKind ::Let ( _ , _ , _ , ref mut recovered @ Recovered ::No ) = > {
2023-09-08 10:14:36 +00:00
if let Some ( reason ) = self . forbid_let_reason {
2024-05-09 18:44:40 +10:00
* recovered = Recovered ::Yes ( self . parser . dcx ( ) . emit_err (
errors ::ExpectedExpressionFoundLet {
2023-11-22 23:27:15 +00:00
span ,
reason ,
missing_let : self . missing_let ,
comparison : self . comparison ,
2024-05-09 18:44:40 +10:00
} ,
) ) ;
2023-09-11 16:16:59 +00:00
} else {
2024-03-04 16:31:49 +11:00
self . parser . psess . gated_spans . gate ( sym ::let_chains , span ) ;
2023-09-08 10:14:36 +00:00
}
}
ExprKind ::Binary ( Spanned { node : BinOpKind ::And , .. } , _ , _ ) = > {
2024-07-17 11:23:35 +00:00
mut_visit ::walk_expr ( self , e ) ;
2023-09-08 10:14:36 +00:00
}
ExprKind ::Binary ( Spanned { node : BinOpKind ::Or , span : or_span } , _ , _ )
if let None | Some ( NotSupportedOr ( _ ) ) = self . forbid_let_reason = >
{
let forbid_let_reason = self . forbid_let_reason ;
self . forbid_let_reason = Some ( NotSupportedOr ( or_span ) ) ;
2024-07-17 11:23:35 +00:00
mut_visit ::walk_expr ( self , e ) ;
2023-09-08 10:14:36 +00:00
self . forbid_let_reason = forbid_let_reason ;
}
ExprKind ::Paren ( ref inner )
if let None | Some ( NotSupportedParentheses ( _ ) ) = self . forbid_let_reason = >
{
let forbid_let_reason = self . forbid_let_reason ;
self . forbid_let_reason = Some ( NotSupportedParentheses ( inner . span ) ) ;
2024-07-17 11:23:35 +00:00
mut_visit ::walk_expr ( self , e ) ;
2023-09-08 10:14:36 +00:00
self . forbid_let_reason = forbid_let_reason ;
}
2023-11-22 23:27:15 +00:00
ExprKind ::Assign ( ref lhs , _ , span ) = > {
let forbid_let_reason = self . forbid_let_reason ;
self . forbid_let_reason = Some ( OtherForbidden ) ;
let missing_let = self . missing_let ;
if let ExprKind ::Binary ( _ , _ , rhs ) = & lhs . kind
& & let ExprKind ::Path ( _ , _ )
| ExprKind ::Struct ( _ )
| ExprKind ::Call ( _ , _ )
| ExprKind ::Array ( _ ) = rhs . kind
{
self . missing_let =
Some ( errors ::MaybeMissingLet { span : rhs . span . shrink_to_lo ( ) } ) ;
}
let comparison = self . comparison ;
self . comparison = Some ( errors ::MaybeComparison { span : span . shrink_to_hi ( ) } ) ;
2024-07-17 11:23:35 +00:00
mut_visit ::walk_expr ( self , e ) ;
2023-11-22 23:27:15 +00:00
self . forbid_let_reason = forbid_let_reason ;
self . missing_let = missing_let ;
self . comparison = comparison ;
}
2023-09-08 10:14:36 +00:00
ExprKind ::Unary ( _ , _ )
| ExprKind ::Await ( _ , _ )
2024-10-02 16:35:37 -03:00
| ExprKind ::Use ( _ , _ )
2023-09-08 10:14:36 +00:00
| ExprKind ::AssignOp ( _ , _ , _ )
| ExprKind ::Range ( _ , _ , _ )
| ExprKind ::Try ( _ )
| ExprKind ::AddrOf ( _ , _ , _ )
| ExprKind ::Binary ( _ , _ , _ )
| ExprKind ::Field ( _ , _ )
| ExprKind ::Index ( _ , _ , _ )
| ExprKind ::Call ( _ , _ )
| ExprKind ::MethodCall ( _ )
| ExprKind ::Tup ( _ )
| ExprKind ::Paren ( _ ) = > {
let forbid_let_reason = self . forbid_let_reason ;
2023-09-13 15:00:31 +00:00
self . forbid_let_reason = Some ( OtherForbidden ) ;
2024-07-17 11:23:35 +00:00
mut_visit ::walk_expr ( self , e ) ;
2023-09-08 10:14:36 +00:00
self . forbid_let_reason = forbid_let_reason ;
}
2024-09-13 14:00:10 -04:00
ExprKind ::Cast ( ref mut op , _ )
| ExprKind ::Type ( ref mut op , _ )
| ExprKind ::UnsafeBinderCast ( _ , ref mut op , _ ) = > {
2023-09-08 10:14:36 +00:00
let forbid_let_reason = self . forbid_let_reason ;
2023-09-13 15:00:31 +00:00
self . forbid_let_reason = Some ( OtherForbidden ) ;
2023-09-08 10:14:36 +00:00
self . visit_expr ( op ) ;
self . forbid_let_reason = forbid_let_reason ;
}
2024-05-09 18:44:40 +10:00
ExprKind ::Let ( _ , _ , _ , Recovered ::Yes ( _ ) )
2023-09-08 10:14:36 +00:00
| ExprKind ::Array ( _ )
| ExprKind ::ConstBlock ( _ )
| ExprKind ::Lit ( _ )
| ExprKind ::If ( _ , _ , _ )
| ExprKind ::While ( _ , _ , _ )
2023-12-08 14:51:50 -08:00
| ExprKind ::ForLoop { .. }
2023-09-08 10:14:36 +00:00
| ExprKind ::Loop ( _ , _ , _ )
2024-02-17 12:43:54 -05:00
| ExprKind ::Match ( _ , _ , _ )
2023-09-08 10:14:36 +00:00
| ExprKind ::Closure ( _ )
| ExprKind ::Block ( _ , _ )
2024-06-27 14:56:57 -04:00
| ExprKind ::Gen ( _ , _ , _ , _ )
2023-09-08 10:14:36 +00:00
| ExprKind ::TryBlock ( _ )
| ExprKind ::Underscore
| ExprKind ::Path ( _ , _ )
| ExprKind ::Break ( _ , _ )
| ExprKind ::Continue ( _ )
| ExprKind ::Ret ( _ )
| ExprKind ::InlineAsm ( _ )
| ExprKind ::OffsetOf ( _ , _ )
| ExprKind ::MacCall ( _ )
| ExprKind ::Struct ( _ )
| ExprKind ::Repeat ( _ , _ )
| ExprKind ::Yield ( _ )
| ExprKind ::Yeet ( _ )
| ExprKind ::Become ( _ )
| ExprKind ::IncludedBytes ( _ )
| ExprKind ::FormatArgs ( _ )
2024-02-25 22:22:11 +01:00
| ExprKind ::Err ( _ )
2024-02-25 22:22:09 +01:00
| ExprKind ::Dummy = > {
2023-09-08 10:14:36 +00:00
// These would forbid any let expressions they contain already.
}
}
}
}