1 use super::attr
::DEFAULT_INNER_ATTR_FORBIDDEN
;
2 use super::diagnostics
::Error
;
3 use super::expr
::LhsExpr
;
4 use super::pat
::GateOr
;
5 use super::path
::PathStyle
;
6 use super::{BlockMode, Parser, Restrictions, SemiColonMode}
;
7 use crate::maybe_whole
;
10 use rustc_ast
::ptr
::P
;
11 use rustc_ast
::token
::{self, TokenKind}
;
12 use rustc_ast
::util
::classify
;
13 use rustc_ast
::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle}
;
14 use rustc_ast
::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID}
;
15 use rustc_errors
::{Applicability, PResult}
;
16 use rustc_span
::source_map
::{BytePos, Span}
;
17 use rustc_span
::symbol
::{kw, sym}
;
22 /// Parses a statement. This stops just before trailing semicolons on everything but items.
23 /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
24 // Public for rustfmt usage.
25 pub fn parse_stmt(&mut self) -> PResult
<'a
, Option
<Stmt
>> {
26 Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e
| {
28 self.recover_stmt_(SemiColonMode
::Break
, BlockMode
::Ignore
);
33 fn parse_stmt_without_recovery(&mut self) -> PResult
<'a
, Option
<Stmt
>> {
34 maybe_whole
!(self, NtStmt
, |x
| Some(x
));
36 let attrs
= self.parse_outer_attributes()?
;
37 let lo
= self.token
.span
;
39 let stmt
= if self.eat_keyword(kw
::Let
) {
40 self.parse_local_mk(lo
, attrs
.into())?
41 } else if self.is_kw_followed_by_ident(kw
::Mut
) {
42 self.recover_stmt_local(lo
, attrs
.into(), "missing keyword", "let mut")?
43 } else if self.is_kw_followed_by_ident(kw
::Auto
) {
44 self.bump(); // `auto`
45 let msg
= "write `let` instead of `auto` to introduce a new variable";
46 self.recover_stmt_local(lo
, attrs
.into(), msg
, "let")?
47 } else if self.is_kw_followed_by_ident(sym
::var
) {
49 let msg
= "write `let` instead of `var` to introduce a new variable";
50 self.recover_stmt_local(lo
, attrs
.into(), msg
, "let")?
51 } else if self.check_path() && !self.token
.is_qpath_start() && !self.is_path_start_item() {
52 // We have avoided contextual keywords like `union`, items with `crate` visibility,
53 // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
54 // that starts like a path (1 token), but it fact not a path.
55 // Also, we avoid stealing syntax from `parse_item_`.
56 self.parse_stmt_path_start(lo
, attrs
)?
57 } else if let Some(item
) = self.parse_item_common(attrs
.clone(), false, true, |_
| true)?
{
58 // FIXME: Bad copy of attrs
59 self.mk_stmt(lo
.to(item
.span
), StmtKind
::Item(P(item
)))
60 } else if self.eat(&token
::Semi
) {
61 // Do not attempt to parse an expression if we're done here.
62 self.error_outer_attrs(&attrs
);
63 self.mk_stmt(lo
, StmtKind
::Empty
)
64 } else if self.token
!= token
::CloseDelim(token
::Brace
) {
65 // Remainder are line-expr stmts.
66 let e
= self.parse_expr_res(Restrictions
::STMT_EXPR
, Some(attrs
.into()))?
;
67 self.mk_stmt(lo
.to(e
.span
), StmtKind
::Expr(e
))
69 self.error_outer_attrs(&attrs
);
75 fn parse_stmt_path_start(&mut self, lo
: Span
, attrs
: Vec
<Attribute
>) -> PResult
<'a
, Stmt
> {
76 let path
= self.parse_path(PathStyle
::Expr
)?
;
78 if self.eat(&token
::Not
) {
79 return self.parse_stmt_mac(lo
, attrs
.into(), path
);
82 let expr
= if self.check(&token
::OpenDelim(token
::Brace
)) {
83 self.parse_struct_expr(path
, AttrVec
::new())?
85 let hi
= self.prev_token
.span
;
86 self.mk_expr(lo
.to(hi
), ExprKind
::Path(None
, path
), AttrVec
::new())
89 let expr
= self.with_res(Restrictions
::STMT_EXPR
, |this
| {
90 let expr
= this
.parse_dot_or_call_expr_with(expr
, lo
, attrs
.into())?
;
91 this
.parse_assoc_expr_with(0, LhsExpr
::AlreadyParsed(expr
))
93 Ok(self.mk_stmt(lo
.to(self.prev_token
.span
), StmtKind
::Expr(expr
)))
96 /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
97 /// At this point, the `!` token after the path has already been eaten.
98 fn parse_stmt_mac(&mut self, lo
: Span
, attrs
: AttrVec
, path
: ast
::Path
) -> PResult
<'a
, Stmt
> {
99 let args
= self.parse_mac_args()?
;
100 let delim
= args
.delim();
101 let hi
= self.prev_token
.span
;
104 if delim
== token
::Brace { MacStmtStyle::Braces }
else { MacStmtStyle::NoBraces }
;
106 let mac
= MacCall { path, args, prior_type_ascription: self.last_type_ascription }
;
108 let kind
= if delim
== token
::Brace
|| self.token
== token
::Semi
|| self.token
== token
::Eof
110 StmtKind
::MacCall(P(MacCallStmt { mac, style, attrs }
))
112 // Since none of the above applied, this is an expression statement macro.
113 let e
= self.mk_expr(lo
.to(hi
), ExprKind
::MacCall(mac
), AttrVec
::new());
114 let e
= self.maybe_recover_from_bad_qpath(e
, true)?
;
115 let e
= self.parse_dot_or_call_expr_with(e
, lo
, attrs
)?
;
116 let e
= self.parse_assoc_expr_with(0, LhsExpr
::AlreadyParsed(e
))?
;
119 Ok(self.mk_stmt(lo
.to(hi
), kind
))
122 /// Error on outer attributes in this context.
123 /// Also error if the previous token was a doc comment.
124 fn error_outer_attrs(&self, attrs
: &[Attribute
]) {
125 if let [.., last
] = attrs
{
126 if last
.is_doc_comment() {
127 self.span_fatal_err(last
.span
, Error
::UselessDocComment
).emit();
128 } else if attrs
.iter().any(|a
| a
.style
== AttrStyle
::Outer
) {
129 self.struct_span_err(last
.span
, "expected statement after outer attribute").emit();
134 fn recover_stmt_local(
140 ) -> PResult
<'a
, Stmt
> {
141 let stmt
= self.parse_local_mk(lo
, attrs
)?
;
142 self.struct_span_err(lo
, "invalid variable declaration")
143 .span_suggestion(lo
, msg
, sugg
.to_string(), Applicability
::MachineApplicable
)
148 fn parse_local_mk(&mut self, lo
: Span
, attrs
: AttrVec
) -> PResult
<'a
, Stmt
> {
149 let local
= self.parse_local(attrs
)?
;
150 Ok(self.mk_stmt(lo
.to(self.prev_token
.span
), StmtKind
::Local(local
)))
153 /// Parses a local variable declaration.
154 fn parse_local(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Local
>> {
155 let lo
= self.prev_token
.span
;
156 let pat
= self.parse_top_pat(GateOr
::Yes
)?
;
158 let (err
, ty
) = if self.eat(&token
::Colon
) {
159 // Save the state of the parser before parsing type normally, in case there is a `:`
160 // instead of an `=` typo.
161 let parser_snapshot_before_type
= self.clone();
162 let colon_sp
= self.prev_token
.span
;
163 match self.parse_ty() {
164 Ok(ty
) => (None
, Some(ty
)),
166 if let Ok(snip
) = self.span_to_snippet(pat
.span
) {
167 err
.span_label(pat
.span
, format
!("while parsing the type for `{}`", snip
));
169 let err
= if self.check(&token
::Eq
) {
173 // Rewind to before attempting to parse the type and continue parsing.
174 let parser_snapshot_after_type
=
175 mem
::replace(self, parser_snapshot_before_type
);
176 Some((parser_snapshot_after_type
, colon_sp
, err
))
184 let init
= match (self.parse_initializer(err
.is_some()), err
) {
185 (Ok(init
), None
) => {
186 // init parsed, ty parsed
189 (Ok(init
), Some((_
, colon_sp
, mut err
))) => {
190 // init parsed, ty error
191 // Could parse the type as if it were the initializer, it is likely there was a
192 // typo in the code: `:` instead of `=`. Add suggestion and emit the error.
193 err
.span_suggestion_short(
195 "use `=` if you meant to assign",
197 Applicability
::MachineApplicable
,
200 // As this was parsed successfully, continue as if the code has been fixed for the
201 // rest of the file. It will still fail due to the emitted error, but we avoid
205 (Err(mut init_err
), Some((snapshot
, _
, ty_err
))) => {
206 // init error, ty error
208 // Couldn't parse the type nor the initializer, only raise the type error and
209 // return to the parser state before parsing the type as the initializer.
210 // let x: <parse_error>;
214 (Err(err
), None
) => {
215 // init error, ty parsed
216 // Couldn't parse the initializer and we're not attempting to recover a failed
217 // parse of the type, return the error.
221 let hi
= if self.token
== token
::Semi { self.token.span }
else { self.prev_token.span }
;
222 Ok(P(ast
::Local { ty, pat, init, id: DUMMY_NODE_ID, span: lo.to(hi), attrs }
))
225 /// Parses the RHS of a local variable declaration (e.g., '= 14;').
226 fn parse_initializer(&mut self, eq_optional
: bool
) -> PResult
<'a
, Option
<P
<Expr
>>> {
227 let eq_consumed
= match self.token
.kind
{
228 token
::BinOpEq(..) => {
229 // Recover `let x <op>= 1` as `let x = 1`
230 self.struct_span_err(
232 "can't reassign to an uninitialized variable",
234 .span_suggestion_short(
236 "initialize the variable",
238 Applicability
::MaybeIncorrect
,
244 _
=> self.eat(&token
::Eq
),
247 Ok(if eq_consumed
|| eq_optional { Some(self.parse_expr()?) }
else { None }
)
250 /// Parses a block. No inner attributes are allowed.
251 pub(super) fn parse_block(&mut self) -> PResult
<'a
, P
<Block
>> {
252 let (attrs
, block
) = self.parse_inner_attrs_and_block()?
;
253 if let [.., last
] = &*attrs
{
254 self.error_on_forbidden_inner_attr(last
.span
, DEFAULT_INNER_ATTR_FORBIDDEN
);
259 fn error_block_no_opening_brace
<T
>(&mut self) -> PResult
<'a
, T
> {
260 let sp
= self.token
.span
;
261 let tok
= super::token_descr(&self.token
);
262 let mut e
= self.struct_span_err(sp
, &format
!("expected `{{`, found {}", tok
));
263 let do_not_suggest_help
= self.token
.is_keyword(kw
::In
) || self.token
== token
::Colon
;
265 // Check to see if the user has written something like
270 // which is valid in other languages, but not Rust.
271 match self.parse_stmt_without_recovery() {
272 // If the next token is an open brace (e.g., `if a b {`), the place-
273 // inside-a-block suggestion would be more likely wrong than right.
275 if self.look_ahead(1, |t
| t
== &token
::OpenDelim(token
::Brace
))
276 || do_not_suggest_help
=> {}
278 let stmt_own_line
= self.sess
.source_map().is_line_before_span_empty(sp
);
279 let stmt_span
= if stmt_own_line
&& self.eat(&token
::Semi
) {
280 // Expand the span to include the semicolon.
281 stmt
.span
.with_hi(self.prev_token
.span
.hi())
285 if let Ok(snippet
) = self.span_to_snippet(stmt_span
) {
288 "try placing this code inside a block",
289 format
!("{{ {} }}", snippet
),
290 // Speculative; has been misleading in the past (#46836).
291 Applicability
::MaybeIncorrect
,
296 self.recover_stmt_(SemiColonMode
::Break
, BlockMode
::Ignore
);
301 e
.span_label(sp
, "expected `{`");
305 /// Parses a block. Inner attributes are allowed.
306 pub(super) fn parse_inner_attrs_and_block(
308 ) -> PResult
<'a
, (Vec
<Attribute
>, P
<Block
>)> {
309 self.parse_block_common(self.token
.span
, BlockCheckMode
::Default
)
312 /// Parses a block. Inner attributes are allowed.
313 pub(super) fn parse_block_common(
316 blk_mode
: BlockCheckMode
,
317 ) -> PResult
<'a
, (Vec
<Attribute
>, P
<Block
>)> {
318 maybe_whole
!(self, NtBlock
, |x
| (Vec
::new(), x
));
320 if !self.eat(&token
::OpenDelim(token
::Brace
)) {
321 return self.error_block_no_opening_brace();
324 Ok((self.parse_inner_attributes()?
, self.parse_block_tail(lo
, blk_mode
)?
))
327 /// Parses the rest of a block expression or function body.
328 /// Precondition: already parsed the '{'.
329 fn parse_block_tail(&mut self, lo
: Span
, s
: BlockCheckMode
) -> PResult
<'a
, P
<Block
>> {
330 let mut stmts
= vec
![];
331 while !self.eat(&token
::CloseDelim(token
::Brace
)) {
332 if self.token
== token
::Eof
{
335 let stmt
= match self.parse_full_stmt() {
337 self.maybe_annotate_with_ascription(&mut err
, false);
339 self.recover_stmt_(SemiColonMode
::Ignore
, BlockMode
::Ignore
);
340 Some(self.mk_stmt_err(self.token
.span
))
344 if let Some(stmt
) = stmt
{
347 // Found only `;` or `}`.
351 Ok(self.mk_block(stmts
, s
, lo
.to(self.prev_token
.span
)))
354 /// Parses a statement, including the trailing semicolon.
355 pub fn parse_full_stmt(&mut self) -> PResult
<'a
, Option
<Stmt
>> {
356 // Skip looking for a trailing semicolon when we have an interpolated statement.
357 maybe_whole
!(self, NtStmt
, |x
| Some(x
));
359 let mut stmt
= match self.parse_stmt_without_recovery()?
{
361 None
=> return Ok(None
),
364 let mut eat_semi
= true;
366 // Expression without semicolon.
367 StmtKind
::Expr(ref mut expr
)
368 if self.token
!= token
::Eof
&& classify
::expr_requires_semi_to_be_stmt(expr
) =>
370 // Just check for errors and recover; do not eat semicolon yet.
372 self.expect_one_of(&[], &[token
::Semi
, token
::CloseDelim(token
::Brace
)])
374 if let TokenKind
::DocComment(..) = self.token
.kind
{
375 if let Ok(snippet
) = self.span_to_snippet(self.token
.span
) {
376 let sp
= self.token
.span
;
377 let marker
= &snippet
[..3];
378 let (comment_marker
, doc_comment_marker
) = marker
.split_at(2);
381 sp
.with_hi(sp
.lo() + BytePos(marker
.len() as u32)),
383 "add a space before `{}` to use a regular comment",
386 format
!("{} {}", comment_marker
, doc_comment_marker
),
387 Applicability
::MaybeIncorrect
,
392 self.check_mistyped_turbofish_with_multiple_type_params(e
, expr
)
397 // Don't complain about type errors in body tail after parse error (#57383).
398 let sp
= expr
.span
.to(self.prev_token
.span
);
399 *expr
= self.mk_expr_err(sp
);
402 StmtKind
::Local(ref mut local
) => {
403 if let Err(e
) = self.expect_semi() {
404 // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
405 match &mut local
.init
{
406 Some(ref mut expr
) => {
407 self.check_mistyped_turbofish_with_multiple_type_params(e
, expr
)?
;
408 // We found `foo<bar, baz>`, have we fully recovered?
411 None
=> return Err(e
),
416 StmtKind
::Empty
=> eat_semi
= false,
420 if eat_semi
&& self.eat(&token
::Semi
) {
421 stmt
= stmt
.add_trailing_semicolon();
423 stmt
.span
= stmt
.span
.to(self.prev_token
.span
);
427 pub(super) fn mk_block(&self, stmts
: Vec
<Stmt
>, rules
: BlockCheckMode
, span
: Span
) -> P
<Block
> {
428 P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None }
)
431 pub(super) fn mk_stmt(&self, span
: Span
, kind
: StmtKind
) -> Stmt
{
432 Stmt { id: DUMMY_NODE_ID, kind, span, tokens: None }
435 fn mk_stmt_err(&self, span
: Span
) -> Stmt
{
436 self.mk_stmt(span
, StmtKind
::Expr(self.mk_expr_err(span
)))
439 pub(super) fn mk_block_err(&self, span
: Span
) -> P
<Block
> {
440 self.mk_block(vec
![self.mk_stmt_err(span
)], BlockCheckMode
::Default
, span
)