1 use super::attr
::DEFAULT_INNER_ATTR_FORBIDDEN
;
2 use super::diagnostics
::{AttemptLocalParseRecovery, Error}
;
3 use super::expr
::LhsExpr
;
4 use super::pat
::RecoverComma
;
5 use super::path
::PathStyle
;
6 use super::TrailingToken
;
8 AttrWrapper
, BlockMode
, FnParseMode
, ForceCollect
, Parser
, Restrictions
, SemiColonMode
,
10 use crate::maybe_whole
;
13 use rustc_ast
::ptr
::P
;
14 use rustc_ast
::token
::{self, Delimiter, TokenKind}
;
15 use rustc_ast
::util
::classify
;
16 use rustc_ast
::{AttrStyle, AttrVec, Attribute, LocalKind, MacCall, MacCallStmt, MacStmtStyle}
;
17 use rustc_ast
::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}
;
18 use rustc_ast
::{StmtKind, DUMMY_NODE_ID}
;
19 use rustc_errors
::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}
;
20 use rustc_span
::source_map
::{BytePos, Span}
;
21 use rustc_span
::symbol
::{kw, sym}
;
26 /// Parses a statement. This stops just before trailing semicolons on everything but items.
27 /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
28 // Public for rustfmt usage.
29 pub fn parse_stmt(&mut self, force_collect
: ForceCollect
) -> PResult
<'a
, Option
<Stmt
>> {
30 Ok(self.parse_stmt_without_recovery(false, force_collect
).unwrap_or_else(|mut e
| {
32 self.recover_stmt_(SemiColonMode
::Break
, BlockMode
::Ignore
);
37 /// If `force_capture` is true, forces collection of tokens regardless of whether
38 /// or not we have attributes
39 crate fn parse_stmt_without_recovery(
42 force_collect
: ForceCollect
,
43 ) -> PResult
<'a
, Option
<Stmt
>> {
44 let attrs
= self.parse_outer_attributes()?
;
45 let lo
= self.token
.span
;
47 // Don't use `maybe_whole` so that we have precise control
48 // over when we bump the parser
49 if let token
::Interpolated(nt
) = &self.token
.kind
&& let token
::NtStmt(stmt
) = &**nt
{
50 let mut stmt
= stmt
.clone();
52 stmt
.visit_attrs(|stmt_attrs
| {
53 attrs
.prepend_to_nt_inner(stmt_attrs
);
55 return Ok(Some(stmt
.into_inner()));
58 Ok(Some(if self.token
.is_keyword(kw
::Let
) {
59 self.parse_local_mk(lo
, attrs
, capture_semi
, force_collect
)?
60 } else if self.is_kw_followed_by_ident(kw
::Mut
) {
61 self.recover_stmt_local(lo
, attrs
, "missing keyword", "let mut")?
62 } else if self.is_kw_followed_by_ident(kw
::Auto
) {
63 self.bump(); // `auto`
64 let msg
= "write `let` instead of `auto` to introduce a new variable";
65 self.recover_stmt_local(lo
, attrs
, msg
, "let")?
66 } else if self.is_kw_followed_by_ident(sym
::var
) {
68 let msg
= "write `let` instead of `var` to introduce a new variable";
69 self.recover_stmt_local(lo
, attrs
, msg
, "let")?
70 } else if self.check_path() && !self.token
.is_qpath_start() && !self.is_path_start_item() {
71 // We have avoided contextual keywords like `union`, items with `crate` visibility,
72 // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
73 // that starts like a path (1 token), but it fact not a path.
74 // Also, we avoid stealing syntax from `parse_item_`.
75 if force_collect
== ForceCollect
::Yes
{
76 self.collect_tokens_no_attrs(|this
| this
.parse_stmt_path_start(lo
, attrs
))
78 self.parse_stmt_path_start(lo
, attrs
)
80 } else if let Some(item
) = self.parse_item_common(
84 FnParseMode { req_name: |_| true, req_body: true }
,
87 // FIXME: Bad copy of attrs
88 self.mk_stmt(lo
.to(item
.span
), StmtKind
::Item(P(item
)))
89 } else if self.eat(&token
::Semi
) {
90 // Do not attempt to parse an expression if we're done here.
91 self.error_outer_attrs(&attrs
.take_for_recovery());
92 self.mk_stmt(lo
, StmtKind
::Empty
)
93 } else if self.token
!= token
::CloseDelim(Delimiter
::Brace
) {
94 // Remainder are line-expr stmts.
95 let e
= if force_collect
== ForceCollect
::Yes
{
96 self.collect_tokens_no_attrs(|this
| {
97 this
.parse_expr_res(Restrictions
::STMT_EXPR
, Some(attrs
))
100 self.parse_expr_res(Restrictions
::STMT_EXPR
, Some(attrs
))
102 if matches
!(e
.kind
, ExprKind
::Assign(..)) && self.eat_keyword(kw
::Else
) {
103 let bl
= self.parse_block()?
;
104 // Destructuring assignment ... else.
105 // This is not allowed, but point it out in a nice way.
106 let mut err
= self.struct_span_err(
108 "<assignment> ... else { ... } is not allowed",
112 self.mk_stmt(lo
.to(e
.span
), StmtKind
::Expr(e
))
114 self.error_outer_attrs(&attrs
.take_for_recovery());
119 fn parse_stmt_path_start(&mut self, lo
: Span
, attrs
: AttrWrapper
) -> PResult
<'a
, Stmt
> {
120 let stmt
= self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
121 let path
= this
.parse_path(PathStyle
::Expr
)?
;
123 if this
.eat(&token
::Not
) {
124 let stmt_mac
= this
.parse_stmt_mac(lo
, attrs
.into(), path
)?
;
125 if this
.token
== token
::Semi
{
126 return Ok((stmt_mac
, TrailingToken
::Semi
));
128 return Ok((stmt_mac
, TrailingToken
::None
));
132 let expr
= if this
.eat(&token
::OpenDelim(Delimiter
::Brace
)) {
133 this
.parse_struct_expr(None
, path
, AttrVec
::new(), true)?
135 let hi
= this
.prev_token
.span
;
136 this
.mk_expr(lo
.to(hi
), ExprKind
::Path(None
, path
), AttrVec
::new())
139 let expr
= this
.with_res(Restrictions
::STMT_EXPR
, |this
| {
140 this
.parse_dot_or_call_expr_with(expr
, lo
, attrs
)
142 // `DUMMY_SP` will get overwritten later in this function
143 Ok((this
.mk_stmt(rustc_span
::DUMMY_SP
, StmtKind
::Expr(expr
)), TrailingToken
::None
))
146 if let StmtKind
::Expr(expr
) = stmt
.kind
{
147 // Perform this outside of the `collect_tokens_trailing_token` closure,
148 // since our outer attributes do not apply to this part of the expression
149 let expr
= self.with_res(Restrictions
::STMT_EXPR
, |this
| {
150 this
.parse_assoc_expr_with(0, LhsExpr
::AlreadyParsed(expr
))
152 Ok(self.mk_stmt(lo
.to(self.prev_token
.span
), StmtKind
::Expr(expr
)))
158 /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
159 /// At this point, the `!` token after the path has already been eaten.
160 fn parse_stmt_mac(&mut self, lo
: Span
, attrs
: AttrVec
, path
: ast
::Path
) -> PResult
<'a
, Stmt
> {
161 let args
= self.parse_mac_args()?
;
162 let delim
= args
.delim();
163 let hi
= self.prev_token
.span
;
165 let style
= match delim
{
166 Some(Delimiter
::Brace
) => MacStmtStyle
::Braces
,
167 Some(_
) => MacStmtStyle
::NoBraces
,
168 None
=> unreachable
!(),
171 let mac
= MacCall { path, args, prior_type_ascription: self.last_type_ascription }
;
173 let kind
= if (style
== MacStmtStyle
::Braces
174 && self.token
!= token
::Dot
175 && self.token
!= token
::Question
)
176 || self.token
== token
::Semi
177 || self.token
== token
::Eof
179 StmtKind
::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }
))
181 // Since none of the above applied, this is an expression statement macro.
182 let e
= self.mk_expr(lo
.to(hi
), ExprKind
::MacCall(mac
), AttrVec
::new());
183 let e
= self.maybe_recover_from_bad_qpath(e
, true)?
;
184 let e
= self.parse_dot_or_call_expr_with(e
, lo
, attrs
.into())?
;
185 let e
= self.parse_assoc_expr_with(0, LhsExpr
::AlreadyParsed(e
))?
;
188 Ok(self.mk_stmt(lo
.to(hi
), kind
))
191 /// Error on outer attributes in this context.
192 /// Also error if the previous token was a doc comment.
193 fn error_outer_attrs(&self, attrs
: &[Attribute
]) {
194 if let [.., last
] = attrs
{
195 if last
.is_doc_comment() {
196 self.span_err(last
.span
, Error
::UselessDocComment
).emit();
197 } else if attrs
.iter().any(|a
| a
.style
== AttrStyle
::Outer
) {
198 self.struct_span_err(last
.span
, "expected statement after outer attribute").emit();
203 fn recover_stmt_local(
209 ) -> PResult
<'a
, Stmt
> {
210 let stmt
= self.recover_local_after_let(lo
, attrs
)?
;
211 self.struct_span_err(lo
, "invalid variable declaration")
212 .span_suggestion(lo
, msg
, sugg
.to_string(), Applicability
::MachineApplicable
)
222 force_collect
: ForceCollect
,
223 ) -> PResult
<'a
, Stmt
> {
224 self.collect_tokens_trailing_token(attrs
, force_collect
, |this
, attrs
| {
225 this
.expect_keyword(kw
::Let
)?
;
226 let local
= this
.parse_local(attrs
.into())?
;
227 let trailing
= if capture_semi
&& this
.token
.kind
== token
::Semi
{
232 Ok((this
.mk_stmt(lo
.to(this
.prev_token
.span
), StmtKind
::Local(local
)), trailing
))
236 fn recover_local_after_let(&mut self, lo
: Span
, attrs
: AttrWrapper
) -> PResult
<'a
, Stmt
> {
237 self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
238 let local
= this
.parse_local(attrs
.into())?
;
239 // FIXME - maybe capture semicolon in recovery?
241 this
.mk_stmt(lo
.to(this
.prev_token
.span
), StmtKind
::Local(local
)),
247 /// Parses a local variable declaration.
248 fn parse_local(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Local
>> {
249 let lo
= self.prev_token
.span
;
250 let (pat
, colon
) = self.parse_pat_before_ty(None
, RecoverComma
::Yes
, "`let` bindings")?
;
252 let (err
, ty
) = if colon
{
253 // Save the state of the parser before parsing type normally, in case there is a `:`
254 // instead of an `=` typo.
255 let parser_snapshot_before_type
= self.clone();
256 let colon_sp
= self.prev_token
.span
;
257 match self.parse_ty() {
258 Ok(ty
) => (None
, Some(ty
)),
260 if let Ok(snip
) = self.span_to_snippet(pat
.span
) {
261 err
.span_label(pat
.span
, format
!("while parsing the type for `{}`", snip
));
263 let err
= if self.check(&token
::Eq
) {
267 // Rewind to before attempting to parse the type and continue parsing.
268 let parser_snapshot_after_type
=
269 mem
::replace(self, parser_snapshot_before_type
);
270 Some((parser_snapshot_after_type
, colon_sp
, err
))
278 let init
= match (self.parse_initializer(err
.is_some()), err
) {
279 (Ok(init
), None
) => {
280 // init parsed, ty parsed
283 (Ok(init
), Some((_
, colon_sp
, mut err
))) => {
284 // init parsed, ty error
285 // Could parse the type as if it were the initializer, it is likely there was a
286 // typo in the code: `:` instead of `=`. Add suggestion and emit the error.
287 err
.span_suggestion_short(
289 "use `=` if you meant to assign",
291 Applicability
::MachineApplicable
,
294 // As this was parsed successfully, continue as if the code has been fixed for the
295 // rest of the file. It will still fail due to the emitted error, but we avoid
299 (Err(init_err
), Some((snapshot
, _
, ty_err
))) => {
300 // init error, ty error
302 // Couldn't parse the type nor the initializer, only raise the type error and
303 // return to the parser state before parsing the type as the initializer.
304 // let x: <parse_error>;
308 (Err(err
), None
) => {
309 // init error, ty parsed
310 // Couldn't parse the initializer and we're not attempting to recover a failed
311 // parse of the type, return the error.
315 let kind
= match init
{
316 None
=> LocalKind
::Decl
,
318 if self.eat_keyword(kw
::Else
) {
319 if self.token
.is_keyword(kw
::If
) {
320 // `let...else if`. Emit the same error that `parse_block()` would,
321 // but explicitly point out that this pattern is not allowed.
322 let msg
= "conditional `else if` is not supported for `let...else`";
323 return Err(self.error_block_no_opening_brace_msg(msg
));
325 let els
= self.parse_block()?
;
326 self.check_let_else_init_bool_expr(&init
);
327 self.check_let_else_init_trailing_brace(&init
);
328 LocalKind
::InitElse(init
, els
)
330 LocalKind
::Init(init
)
334 let hi
= if self.token
== token
::Semi { self.token.span }
else { self.prev_token.span }
;
335 Ok(P(ast
::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None }
))
338 fn check_let_else_init_bool_expr(&self, init
: &ast
::Expr
) {
339 if let ast
::ExprKind
::Binary(op
, ..) = init
.kind
{
342 (init
.span
.shrink_to_lo(), "(".to_string()),
343 (init
.span
.shrink_to_hi(), ")".to_string()),
345 self.struct_span_err(
348 "a `{}` expression cannot be directly assigned in `let...else`",
352 .multipart_suggestion(
353 "wrap the expression in parentheses",
355 Applicability
::MachineApplicable
,
362 fn check_let_else_init_trailing_brace(&self, init
: &ast
::Expr
) {
363 if let Some(trailing
) = classify
::expr_trailing_brace(init
) {
364 let err_span
= trailing
.span
.with_lo(trailing
.span
.hi() - BytePos(1));
366 (trailing
.span
.shrink_to_lo(), "(".to_string()),
367 (trailing
.span
.shrink_to_hi(), ")".to_string()),
369 self.struct_span_err(
371 "right curly brace `}` before `else` in a `let...else` statement not allowed",
373 .multipart_suggestion(
374 "try wrapping the expression in parentheses",
376 Applicability
::MachineApplicable
,
382 /// Parses the RHS of a local variable declaration (e.g., `= 14;`).
383 fn parse_initializer(&mut self, eq_optional
: bool
) -> PResult
<'a
, Option
<P
<Expr
>>> {
384 let eq_consumed
= match self.token
.kind
{
385 token
::BinOpEq(..) => {
386 // Recover `let x <op>= 1` as `let x = 1`
387 self.struct_span_err(
389 "can't reassign to an uninitialized variable",
391 .span_suggestion_short(
393 "initialize the variable",
395 Applicability
::MaybeIncorrect
,
397 .help("if you meant to overwrite, remove the `let` binding")
402 _
=> self.eat(&token
::Eq
),
405 Ok(if eq_consumed
|| eq_optional { Some(self.parse_expr()?) }
else { None }
)
408 /// Parses a block. No inner attributes are allowed.
409 pub(super) fn parse_block(&mut self) -> PResult
<'a
, P
<Block
>> {
410 let (attrs
, block
) = self.parse_inner_attrs_and_block()?
;
411 if let [.., last
] = &*attrs
{
412 self.error_on_forbidden_inner_attr(last
.span
, DEFAULT_INNER_ATTR_FORBIDDEN
);
417 fn error_block_no_opening_brace_msg(
420 ) -> DiagnosticBuilder
<'a
, ErrorGuaranteed
> {
421 let sp
= self.token
.span
;
422 let mut e
= self.struct_span_err(sp
, msg
);
423 let do_not_suggest_help
= self.token
.is_keyword(kw
::In
) || self.token
== token
::Colon
;
425 // Check to see if the user has written something like
430 // which is valid in other languages, but not Rust.
431 match self.parse_stmt_without_recovery(false, ForceCollect
::No
) {
432 // If the next token is an open brace (e.g., `if a b {`), the place-
433 // inside-a-block suggestion would be more likely wrong than right.
435 if self.look_ahead(1, |t
| t
== &token
::OpenDelim(Delimiter
::Brace
))
436 || do_not_suggest_help
=> {}
437 // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836).
438 Ok(Some(Stmt { kind: StmtKind::Empty, .. }
)) => {}
440 let stmt_own_line
= self.sess
.source_map().is_line_before_span_empty(sp
);
441 let stmt_span
= if stmt_own_line
&& self.eat(&token
::Semi
) {
442 // Expand the span to include the semicolon.
443 stmt
.span
.with_hi(self.prev_token
.span
.hi())
447 e
.multipart_suggestion(
448 "try placing this code inside a block",
450 (stmt_span
.shrink_to_lo(), "{ ".to_string()),
451 (stmt_span
.shrink_to_hi(), " }".to_string()),
453 // Speculative; has been misleading in the past (#46836).
454 Applicability
::MaybeIncorrect
,
458 self.recover_stmt_(SemiColonMode
::Break
, BlockMode
::Ignore
);
463 e
.span_label(sp
, "expected `{`");
467 fn error_block_no_opening_brace
<T
>(&mut self) -> PResult
<'a
, T
> {
468 let tok
= super::token_descr(&self.token
);
469 let msg
= format
!("expected `{{`, found {}", tok
);
470 Err(self.error_block_no_opening_brace_msg(&msg
))
473 /// Parses a block. Inner attributes are allowed.
474 pub(super) fn parse_inner_attrs_and_block(
476 ) -> PResult
<'a
, (Vec
<Attribute
>, P
<Block
>)> {
477 self.parse_block_common(self.token
.span
, BlockCheckMode
::Default
)
480 /// Parses a block. Inner attributes are allowed.
481 pub(super) fn parse_block_common(
484 blk_mode
: BlockCheckMode
,
485 ) -> PResult
<'a
, (Vec
<Attribute
>, P
<Block
>)> {
486 maybe_whole
!(self, NtBlock
, |x
| (Vec
::new(), x
));
488 self.maybe_recover_unexpected_block_label();
489 if !self.eat(&token
::OpenDelim(Delimiter
::Brace
)) {
490 return self.error_block_no_opening_brace();
493 let attrs
= self.parse_inner_attributes()?
;
494 let tail
= match self.maybe_suggest_struct_literal(lo
, blk_mode
) {
496 None
=> self.parse_block_tail(lo
, blk_mode
, AttemptLocalParseRecovery
::Yes
)?
,
501 /// Parses the rest of a block expression or function body.
502 /// Precondition: already parsed the '{'.
503 crate fn parse_block_tail(
507 recover
: AttemptLocalParseRecovery
,
508 ) -> PResult
<'a
, P
<Block
>> {
509 let mut stmts
= vec
![];
510 while !self.eat(&token
::CloseDelim(Delimiter
::Brace
)) {
511 if self.token
== token
::Eof
{
514 let stmt
= match self.parse_full_stmt(recover
) {
515 Err(mut err
) if recover
.yes() => {
516 self.maybe_annotate_with_ascription(&mut err
, false);
518 self.recover_stmt_(SemiColonMode
::Ignore
, BlockMode
::Ignore
);
519 Some(self.mk_stmt_err(self.token
.span
))
522 Err(err
) => return Err(err
),
524 if let Some(stmt
) = stmt
{
527 // Found only `;` or `}`.
531 Ok(self.mk_block(stmts
, s
, lo
.to(self.prev_token
.span
)))
534 /// Parses a statement, including the trailing semicolon.
535 pub fn parse_full_stmt(
537 recover
: AttemptLocalParseRecovery
,
538 ) -> PResult
<'a
, Option
<Stmt
>> {
539 // Skip looking for a trailing semicolon when we have an interpolated statement.
540 maybe_whole
!(self, NtStmt
, |x
| Some(x
.into_inner()));
542 let Some(mut stmt
) = self.parse_stmt_without_recovery(true, ForceCollect
::No
)?
else {
546 let mut eat_semi
= true;
548 // Expression without semicolon.
549 StmtKind
::Expr(ref mut expr
)
550 if self.token
!= token
::Eof
&& classify
::expr_requires_semi_to_be_stmt(expr
) =>
552 // Just check for errors and recover; do not eat semicolon yet.
554 self.expect_one_of(&[], &[token
::Semi
, token
::CloseDelim(Delimiter
::Brace
)])
556 if let TokenKind
::DocComment(..) = self.token
.kind
{
557 if let Ok(snippet
) = self.span_to_snippet(self.token
.span
) {
558 let sp
= self.token
.span
;
559 let marker
= &snippet
[..3];
560 let (comment_marker
, doc_comment_marker
) = marker
.split_at(2);
563 sp
.with_hi(sp
.lo() + BytePos(marker
.len() as u32)),
565 "add a space before `{}` to use a regular comment",
568 format
!("{} {}", comment_marker
, doc_comment_marker
),
569 Applicability
::MaybeIncorrect
,
574 self.check_mistyped_turbofish_with_multiple_type_params(e
, expr
)
582 // Don't complain about type errors in body tail after parse error (#57383).
583 let sp
= expr
.span
.to(self.prev_token
.span
);
584 *expr
= self.mk_expr_err(sp
);
587 StmtKind
::Expr(_
) | StmtKind
::MacCall(_
) => {}
588 StmtKind
::Local(ref mut local
) if let Err(e
) = self.expect_semi() => {
589 // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
590 match &mut local
.kind
{
591 LocalKind
::Init(expr
) | LocalKind
::InitElse(expr
, _
) => {
592 self.check_mistyped_turbofish_with_multiple_type_params(e
, expr
)?
;
593 // We found `foo<bar, baz>`, have we fully recovered?
596 LocalKind
::Decl
=> return Err(e
),
600 StmtKind
::Empty
| StmtKind
::Item(_
) | StmtKind
::Local(_
) | StmtKind
::Semi(_
) => eat_semi
= false,
603 if eat_semi
&& self.eat(&token
::Semi
) {
604 stmt
= stmt
.add_trailing_semicolon();
606 stmt
.span
= stmt
.span
.to(self.prev_token
.span
);
610 pub(super) fn mk_block(&self, stmts
: Vec
<Stmt
>, rules
: BlockCheckMode
, span
: Span
) -> P
<Block
> {
617 could_be_bare_literal
: false,
621 pub(super) fn mk_stmt(&self, span
: Span
, kind
: StmtKind
) -> Stmt
{
622 Stmt { id: DUMMY_NODE_ID, kind, span }
625 pub(super) fn mk_stmt_err(&self, span
: Span
) -> Stmt
{
626 self.mk_stmt(span
, StmtKind
::Expr(self.mk_expr_err(span
)))
629 pub(super) fn mk_block_err(&self, span
: Span
) -> P
<Block
> {
630 self.mk_block(vec
![self.mk_stmt_err(span
)], BlockCheckMode
::Default
, span
)