1 use super::attr
::InnerAttrForbiddenReason
;
2 use super::diagnostics
::AttemptLocalParseRecovery
;
3 use super::expr
::LhsExpr
;
4 use super::pat
::{PatternLocation, RecoverComma}
;
5 use super::path
::PathStyle
;
6 use super::TrailingToken
;
8 AttrWrapper
, BlockMode
, FnParseMode
, ForceCollect
, Parser
, Restrictions
, SemiColonMode
,
11 use crate::maybe_whole
;
14 use rustc_ast
::ptr
::P
;
15 use rustc_ast
::token
::{self, Delimiter, TokenKind}
;
16 use rustc_ast
::util
::classify
;
17 use rustc_ast
::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle}
;
18 use rustc_ast
::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}
;
19 use rustc_ast
::{StmtKind, DUMMY_NODE_ID}
;
20 use rustc_errors
::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}
;
21 use rustc_span
::source_map
::{BytePos, Span}
;
22 use rustc_span
::symbol
::{kw, sym}
;
24 use thin_vec
::{thin_vec, ThinVec}
;
27 /// Parses a statement. This stops just before trailing semicolons on everything but items.
28 /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
29 // Public for rustfmt usage.
30 pub fn parse_stmt(&mut self, force_collect
: ForceCollect
) -> PResult
<'a
, Option
<Stmt
>> {
31 Ok(self.parse_stmt_without_recovery(false, force_collect
).unwrap_or_else(|mut e
| {
33 self.recover_stmt_(SemiColonMode
::Break
, BlockMode
::Ignore
);
38 /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether
39 /// or not we have attributes
40 pub(crate) fn parse_stmt_without_recovery(
43 force_collect
: ForceCollect
,
44 ) -> PResult
<'a
, Option
<Stmt
>> {
45 let attrs
= self.parse_outer_attributes()?
;
46 let lo
= self.token
.span
;
48 // Don't use `maybe_whole` so that we have precise control
49 // over when we bump the parser
50 if let token
::Interpolated(nt
) = &self.token
.kind
&& let token
::NtStmt(stmt
) = &**nt
{
51 let mut stmt
= stmt
.clone();
53 stmt
.visit_attrs(|stmt_attrs
| {
54 attrs
.prepend_to_nt_inner(stmt_attrs
);
56 return Ok(Some(stmt
.into_inner()));
59 if self.token
.is_keyword(kw
::Mut
) && self.is_keyword_ahead(1, &[kw
::Let
]) {
61 let mut_let_span
= lo
.to(self.token
.span
);
62 self.sess
.emit_err(errors
::InvalidVariableDeclaration
{
64 sub
: errors
::InvalidVariableDeclarationSub
::SwitchMutLetOrder(mut_let_span
),
68 Ok(Some(if self.token
.is_keyword(kw
::Let
) {
69 self.parse_local_mk(lo
, attrs
, capture_semi
, force_collect
)?
70 } else if self.is_kw_followed_by_ident(kw
::Mut
) && self.may_recover() {
71 self.recover_stmt_local_after_let(
74 errors
::InvalidVariableDeclarationSub
::MissingLet
,
76 } else if self.is_kw_followed_by_ident(kw
::Auto
) && self.may_recover() {
77 self.bump(); // `auto`
78 self.recover_stmt_local_after_let(
81 errors
::InvalidVariableDeclarationSub
::UseLetNotAuto
,
83 } else if self.is_kw_followed_by_ident(sym
::var
) && self.may_recover() {
85 self.recover_stmt_local_after_let(
88 errors
::InvalidVariableDeclarationSub
::UseLetNotVar
,
90 } else if self.check_path() && !self.token
.is_qpath_start() && !self.is_path_start_item() {
91 // We have avoided contextual keywords like `union`, items with `crate` visibility,
92 // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
93 // that starts like a path (1 token), but it fact not a path.
94 // Also, we avoid stealing syntax from `parse_item_`.
96 ForceCollect
::Yes
=> {
97 self.collect_tokens_no_attrs(|this
| this
.parse_stmt_path_start(lo
, attrs
))?
99 ForceCollect
::No
=> self.parse_stmt_path_start(lo
, attrs
)?
,
101 } else if let Some(item
) = self.parse_item_common(
105 FnParseMode { req_name: |_| true, req_body: true }
,
108 // FIXME: Bad copy of attrs
109 self.mk_stmt(lo
.to(item
.span
), StmtKind
::Item(P(item
)))
110 } else if self.eat(&token
::Semi
) {
111 // Do not attempt to parse an expression if we're done here.
112 self.error_outer_attrs(attrs
);
113 self.mk_stmt(lo
, StmtKind
::Empty
)
114 } else if self.token
!= token
::CloseDelim(Delimiter
::Brace
) {
115 // Remainder are line-expr stmts.
116 let e
= match force_collect
{
117 ForceCollect
::Yes
=> self.collect_tokens_no_attrs(|this
| {
118 this
.parse_expr_res(Restrictions
::STMT_EXPR
, Some(attrs
))
120 ForceCollect
::No
=> self.parse_expr_res(Restrictions
::STMT_EXPR
, Some(attrs
))?
,
122 if matches
!(e
.kind
, ExprKind
::Assign(..)) && self.eat_keyword(kw
::Else
) {
123 let bl
= self.parse_block()?
;
124 // Destructuring assignment ... else.
125 // This is not allowed, but point it out in a nice way.
126 self.sess
.emit_err(errors
::AssignmentElseNotAllowed { span: e.span.to(bl.span) }
);
128 self.mk_stmt(lo
.to(e
.span
), StmtKind
::Expr(e
))
130 self.error_outer_attrs(attrs
);
135 fn parse_stmt_path_start(&mut self, lo
: Span
, attrs
: AttrWrapper
) -> PResult
<'a
, Stmt
> {
136 let stmt
= self.collect_tokens_trailing_token(attrs
, ForceCollect
::No
, |this
, attrs
| {
137 let path
= this
.parse_path(PathStyle
::Expr
)?
;
139 if this
.eat(&token
::Not
) {
140 let stmt_mac
= this
.parse_stmt_mac(lo
, attrs
, path
)?
;
141 if this
.token
== token
::Semi
{
142 return Ok((stmt_mac
, TrailingToken
::Semi
));
144 return Ok((stmt_mac
, TrailingToken
::None
));
148 let expr
= if this
.eat(&token
::OpenDelim(Delimiter
::Brace
)) {
149 this
.parse_expr_struct(None
, path
, true)?
151 let hi
= this
.prev_token
.span
;
152 this
.mk_expr(lo
.to(hi
), ExprKind
::Path(None
, path
))
155 let expr
= this
.with_res(Restrictions
::STMT_EXPR
, |this
| {
156 this
.parse_expr_dot_or_call_with(expr
, lo
, attrs
)
158 // `DUMMY_SP` will get overwritten later in this function
159 Ok((this
.mk_stmt(rustc_span
::DUMMY_SP
, StmtKind
::Expr(expr
)), TrailingToken
::None
))
162 if let StmtKind
::Expr(expr
) = stmt
.kind
{
163 // Perform this outside of the `collect_tokens_trailing_token` closure,
164 // since our outer attributes do not apply to this part of the expression
165 let expr
= self.with_res(Restrictions
::STMT_EXPR
, |this
| {
166 this
.parse_expr_assoc_with(
168 LhsExpr
::AlreadyParsed { expr, starts_statement: true }
,
171 Ok(self.mk_stmt(lo
.to(self.prev_token
.span
), StmtKind
::Expr(expr
)))
177 /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
178 /// At this point, the `!` token after the path has already been eaten.
179 fn parse_stmt_mac(&mut self, lo
: Span
, attrs
: AttrVec
, path
: ast
::Path
) -> PResult
<'a
, Stmt
> {
180 let args
= self.parse_delim_args()?
;
181 let delim
= args
.delim
.to_token();
182 let hi
= self.prev_token
.span
;
184 let style
= match delim
{
185 Delimiter
::Brace
=> MacStmtStyle
::Braces
,
186 _
=> MacStmtStyle
::NoBraces
,
189 let mac
= P(MacCall { path, args, prior_type_ascription: self.last_type_ascription }
);
191 let kind
= if (style
== MacStmtStyle
::Braces
192 && self.token
!= token
::Dot
193 && self.token
!= token
::Question
)
194 || self.token
== token
::Semi
195 || self.token
== token
::Eof
197 StmtKind
::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }
))
199 // Since none of the above applied, this is an expression statement macro.
200 let e
= self.mk_expr(lo
.to(hi
), ExprKind
::MacCall(mac
));
201 let e
= self.maybe_recover_from_bad_qpath(e
)?
;
202 let e
= self.parse_expr_dot_or_call_with(e
, lo
, attrs
)?
;
203 let e
= self.parse_expr_assoc_with(
205 LhsExpr
::AlreadyParsed { expr: e, starts_statement: false }
,
209 Ok(self.mk_stmt(lo
.to(hi
), kind
))
212 /// Error on outer attributes in this context.
213 /// Also error if the previous token was a doc comment.
214 fn error_outer_attrs(&self, attrs
: AttrWrapper
) {
216 && let attrs
= attrs
.take_for_recovery(self.sess
)
217 && let attrs @
[.., last
] = &*attrs
{
218 if last
.is_doc_comment() {
219 self.sess
.emit_err(errors
::DocCommentDoesNotDocumentAnything
{
223 } else if attrs
.iter().any(|a
| a
.style
== AttrStyle
::Outer
) {
224 self.sess
.emit_err(errors
::ExpectedStatementAfterOuterAttr { span: last.span }
);
229 fn recover_stmt_local_after_let(
233 subdiagnostic
: fn(Span
) -> errors
::InvalidVariableDeclarationSub
,
234 ) -> PResult
<'a
, Stmt
> {
236 self.collect_tokens_trailing_token(attrs
, ForceCollect
::Yes
, |this
, attrs
| {
237 let local
= this
.parse_local(attrs
)?
;
238 // FIXME - maybe capture semicolon in recovery?
240 this
.mk_stmt(lo
.to(this
.prev_token
.span
), StmtKind
::Local(local
)),
244 self.sess
.emit_err(errors
::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) }
);
253 force_collect
: ForceCollect
,
254 ) -> PResult
<'a
, Stmt
> {
255 self.collect_tokens_trailing_token(attrs
, force_collect
, |this
, attrs
| {
256 this
.expect_keyword(kw
::Let
)?
;
257 let local
= this
.parse_local(attrs
)?
;
258 let trailing
= if capture_semi
&& this
.token
.kind
== token
::Semi
{
263 Ok((this
.mk_stmt(lo
.to(this
.prev_token
.span
), StmtKind
::Local(local
)), trailing
))
267 /// Parses a local variable declaration.
268 fn parse_local(&mut self, attrs
: AttrVec
) -> PResult
<'a
, P
<Local
>> {
269 let lo
= self.prev_token
.span
;
271 if self.token
.is_keyword(kw
::Const
) && self.look_ahead(1, |t
| t
.is_ident()) {
272 self.sess
.emit_err(errors
::ConstLetMutuallyExclusive { span: lo.to(self.token.span) }
);
276 self.report_invalid_identifier_error()?
;
278 self.parse_pat_before_ty(None
, RecoverComma
::Yes
, PatternLocation
::LetBinding
)?
;
280 let (err
, ty
) = if colon
{
281 // Save the state of the parser before parsing type normally, in case there is a `:`
282 // instead of an `=` typo.
283 let parser_snapshot_before_type
= self.clone();
284 let colon_sp
= self.prev_token
.span
;
285 match self.parse_ty() {
286 Ok(ty
) => (None
, Some(ty
)),
288 if let Ok(snip
) = self.span_to_snippet(pat
.span
) {
289 err
.span_label(pat
.span
, format
!("while parsing the type for `{}`", snip
));
291 // we use noexpect here because we don't actually expect Eq to be here
292 // but we are still checking for it in order to be able to handle it if
294 let err
= if self.check_noexpect(&token
::Eq
) {
298 // Rewind to before attempting to parse the type and continue parsing.
299 let parser_snapshot_after_type
=
300 mem
::replace(self, parser_snapshot_before_type
);
301 Some((parser_snapshot_after_type
, colon_sp
, err
))
309 let init
= match (self.parse_initializer(err
.is_some()), err
) {
310 (Ok(init
), None
) => {
311 // init parsed, ty parsed
314 (Ok(init
), Some((_
, colon_sp
, mut err
))) => {
315 // init parsed, ty error
316 // Could parse the type as if it were the initializer, it is likely there was a
317 // typo in the code: `:` instead of `=`. Add suggestion and emit the error.
318 err
.span_suggestion_short(
320 "use `=` if you meant to assign",
322 Applicability
::MachineApplicable
,
325 // As this was parsed successfully, continue as if the code has been fixed for the
326 // rest of the file. It will still fail due to the emitted error, but we avoid
330 (Err(init_err
), Some((snapshot
, _
, ty_err
))) => {
331 // init error, ty error
333 // Couldn't parse the type nor the initializer, only raise the type error and
334 // return to the parser state before parsing the type as the initializer.
335 // let x: <parse_error>;
339 (Err(err
), None
) => {
340 // init error, ty parsed
341 // Couldn't parse the initializer and we're not attempting to recover a failed
342 // parse of the type, return the error.
346 let kind
= match init
{
347 None
=> LocalKind
::Decl
,
349 if self.eat_keyword(kw
::Else
) {
350 if self.token
.is_keyword(kw
::If
) {
351 // `let...else if`. Emit the same error that `parse_block()` would,
352 // but explicitly point out that this pattern is not allowed.
353 let msg
= "conditional `else if` is not supported for `let...else`";
354 return Err(self.error_block_no_opening_brace_msg(msg
));
356 let els
= self.parse_block()?
;
357 self.check_let_else_init_bool_expr(&init
);
358 self.check_let_else_init_trailing_brace(&init
);
359 LocalKind
::InitElse(init
, els
)
361 LocalKind
::Init(init
)
365 let hi
= if self.token
== token
::Semi { self.token.span }
else { self.prev_token.span }
;
366 Ok(P(ast
::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None }
))
369 /// report error for `let 1x = 123`
370 pub fn report_invalid_identifier_error(&mut self) -> PResult
<'a
, ()> {
371 if let token
::Literal(lit
) = self.token
.uninterpolate().kind
&&
372 rustc_ast
::MetaItemLit
::from_token(&self.token
).is_none() &&
373 (lit
.kind
== token
::LitKind
::Integer
|| lit
.kind
== token
::LitKind
::Float
) &&
374 self.look_ahead(1, |t
| matches
!(t
.kind
, token
::Eq
) || matches
!(t
.kind
, token
::Colon
) ) {
375 return Err(self.sess
.create_err(errors
::InvalidIdentiferStartsWithNumber { span: self.token.span }
));
380 fn check_let_else_init_bool_expr(&self, init
: &ast
::Expr
) {
381 if let ast
::ExprKind
::Binary(op
, ..) = init
.kind
{
383 self.sess
.emit_err(errors
::InvalidExpressionInLetElse
{
385 operator
: op
.node
.to_string(),
386 sugg
: errors
::WrapExpressionInParentheses
{
387 left
: init
.span
.shrink_to_lo(),
388 right
: init
.span
.shrink_to_hi(),
395 fn check_let_else_init_trailing_brace(&self, init
: &ast
::Expr
) {
396 if let Some(trailing
) = classify
::expr_trailing_brace(init
) {
397 self.sess
.emit_err(errors
::InvalidCurlyInLetElse
{
398 span
: trailing
.span
.with_lo(trailing
.span
.hi() - BytePos(1)),
399 sugg
: errors
::WrapExpressionInParentheses
{
400 left
: trailing
.span
.shrink_to_lo(),
401 right
: trailing
.span
.shrink_to_hi(),
407 /// Parses the RHS of a local variable declaration (e.g., `= 14;`).
408 fn parse_initializer(&mut self, eq_optional
: bool
) -> PResult
<'a
, Option
<P
<Expr
>>> {
409 let eq_consumed
= match self.token
.kind
{
410 token
::BinOpEq(..) => {
411 // Recover `let x <op>= 1` as `let x = 1`
413 .emit_err(errors
::CompoundAssignmentExpressionInLet { span: self.token.span }
);
417 _
=> self.eat(&token
::Eq
),
420 Ok(if eq_consumed
|| eq_optional { Some(self.parse_expr()?) }
else { None }
)
423 /// Parses a block. No inner attributes are allowed.
424 pub(super) fn parse_block(&mut self) -> PResult
<'a
, P
<Block
>> {
425 let (attrs
, block
) = self.parse_inner_attrs_and_block()?
;
426 if let [.., last
] = &*attrs
{
427 self.error_on_forbidden_inner_attr(
429 super::attr
::InnerAttrPolicy
::Forbidden(Some(
430 InnerAttrForbiddenReason
::InCodeBlock
,
437 fn error_block_no_opening_brace_msg(
440 ) -> DiagnosticBuilder
<'a
, ErrorGuaranteed
> {
441 let sp
= self.token
.span
;
442 let mut e
= self.struct_span_err(sp
, msg
);
443 let do_not_suggest_help
= self.token
.is_keyword(kw
::In
) || self.token
== token
::Colon
;
445 // Check to see if the user has written something like
450 // which is valid in other languages, but not Rust.
451 match self.parse_stmt_without_recovery(false, ForceCollect
::No
) {
452 // If the next token is an open brace, e.g., we have:
454 // if expr other_expr {
455 // ^ ^ ^- lookahead(1) is a brace
456 // | |- current token is not "else"
457 // |- (statement we just parsed)
459 // the place-inside-a-block suggestion would be more likely wrong than right.
461 // FIXME(compiler-errors): this should probably parse an arbitrary expr and not
462 // just lookahead one token, so we can see if there's a brace after _that_,
463 // since we want to protect against:
464 // `if 1 1 + 1 {` being suggested as `if { 1 } 1 + 1 {`
467 if (!self.token
.is_keyword(kw
::Else
)
468 && self.look_ahead(1, |t
| t
== &token
::OpenDelim(Delimiter
::Brace
)))
469 || do_not_suggest_help
=> {}
470 // Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836).
471 Ok(Some(Stmt { kind: StmtKind::Empty, .. }
)) => {}
473 let stmt_own_line
= self.sess
.source_map().is_line_before_span_empty(sp
);
474 let stmt_span
= if stmt_own_line
&& self.eat(&token
::Semi
) {
475 // Expand the span to include the semicolon.
476 stmt
.span
.with_hi(self.prev_token
.span
.hi())
480 e
.multipart_suggestion(
481 "try placing this code inside a block",
483 (stmt_span
.shrink_to_lo(), "{ ".to_string()),
484 (stmt_span
.shrink_to_hi(), " }".to_string()),
486 // Speculative; has been misleading in the past (#46836).
487 Applicability
::MaybeIncorrect
,
491 self.recover_stmt_(SemiColonMode
::Break
, BlockMode
::Ignore
);
496 e
.span_label(sp
, "expected `{`");
500 fn error_block_no_opening_brace
<T
>(&mut self) -> PResult
<'a
, T
> {
501 let tok
= super::token_descr(&self.token
);
502 let msg
= format
!("expected `{{`, found {}", tok
);
503 Err(self.error_block_no_opening_brace_msg(&msg
))
506 /// Parses a block. Inner attributes are allowed.
507 pub(super) fn parse_inner_attrs_and_block(&mut self) -> PResult
<'a
, (AttrVec
, P
<Block
>)> {
508 self.parse_block_common(self.token
.span
, BlockCheckMode
::Default
, true)
511 /// Parses a block. Inner attributes are allowed.
512 pub(super) fn parse_block_common(
515 blk_mode
: BlockCheckMode
,
516 can_be_struct_literal
: bool
,
517 ) -> PResult
<'a
, (AttrVec
, P
<Block
>)> {
518 maybe_whole
!(self, NtBlock
, |x
| (AttrVec
::new(), x
));
520 let maybe_ident
= self.prev_token
.clone();
521 self.maybe_recover_unexpected_block_label();
522 if !self.eat(&token
::OpenDelim(Delimiter
::Brace
)) {
523 return self.error_block_no_opening_brace();
526 let attrs
= self.parse_inner_attributes()?
;
527 let tail
= match self.maybe_suggest_struct_literal(
531 can_be_struct_literal
,
534 None
=> self.parse_block_tail(lo
, blk_mode
, AttemptLocalParseRecovery
::Yes
)?
,
539 /// Parses the rest of a block expression or function body.
540 /// Precondition: already parsed the '{'.
541 pub(crate) fn parse_block_tail(
545 recover
: AttemptLocalParseRecovery
,
546 ) -> PResult
<'a
, P
<Block
>> {
547 let mut stmts
= ThinVec
::new();
548 let mut snapshot
= None
;
549 while !self.eat(&token
::CloseDelim(Delimiter
::Brace
)) {
550 if self.token
== token
::Eof
{
553 if self.is_diff_marker(&TokenKind
::BinOp(token
::Shl
), &TokenKind
::Lt
) {
554 // Account for `<<<<<<<` diff markers. We can't proactively error here because
555 // that can be a valid path start, so we snapshot and reparse only we've
556 // encountered another parse error.
557 snapshot
= Some(self.create_snapshot_for_diagnostic());
559 let stmt
= match self.parse_full_stmt(recover
) {
560 Err(mut err
) if recover
.yes() => {
561 self.maybe_annotate_with_ascription(&mut err
, false);
562 if let Some(ref mut snapshot
) = snapshot
{
563 snapshot
.recover_diff_marker();
566 self.recover_stmt_(SemiColonMode
::Ignore
, BlockMode
::Ignore
);
567 Some(self.mk_stmt_err(self.token
.span
))
570 Err(err
) => return Err(err
),
572 if let Some(stmt
) = stmt
{
575 // Found only `;` or `}`.
579 Ok(self.mk_block(stmts
, s
, lo
.to(self.prev_token
.span
)))
582 /// Parses a statement, including the trailing semicolon.
583 pub fn parse_full_stmt(
585 recover
: AttemptLocalParseRecovery
,
586 ) -> PResult
<'a
, Option
<Stmt
>> {
587 // Skip looking for a trailing semicolon when we have an interpolated statement.
588 maybe_whole
!(self, NtStmt
, |x
| Some(x
.into_inner()));
590 let Some(mut stmt
) = self.parse_stmt_without_recovery(true, ForceCollect
::No
)?
else {
594 let mut eat_semi
= true;
595 match &mut stmt
.kind
{
596 // Expression without semicolon.
598 if self.token
!= token
::Eof
&& classify
::expr_requires_semi_to_be_stmt(expr
) => {
599 // Just check for errors and recover; do not eat semicolon yet.
600 // `expect_one_of` returns PResult<'a, bool /* recovered */>
601 let replace_with_err
=
602 match self.expect_one_of(&[], &[token
::Semi
, token
::CloseDelim(Delimiter
::Brace
)]) {
603 // Recover from parser, skip type error to avoid extra errors.
606 if let TokenKind
::DocComment(..) = self.token
.kind
&&
607 let Ok(snippet
) = self.span_to_snippet(self.token
.span
) {
608 let sp
= self.token
.span
;
609 let marker
= &snippet
[..3];
610 let (comment_marker
, doc_comment_marker
) = marker
.split_at(2);
613 sp
.with_hi(sp
.lo() + BytePos(marker
.len() as u32)),
615 "add a space before `{}` to use a regular comment",
618 format
!("{} {}", comment_marker
, doc_comment_marker
),
619 Applicability
::MaybeIncorrect
,
624 self.check_mistyped_turbofish_with_multiple_type_params(e
, expr
)
636 if replace_with_err
{
637 // We already emitted an error, so don't emit another type error
638 let sp
= expr
.span
.to(self.prev_token
.span
);
639 *expr
= self.mk_expr_err(sp
);
642 StmtKind
::Expr(_
) | StmtKind
::MacCall(_
) => {}
643 StmtKind
::Local(local
) if let Err(e
) = self.expect_semi() => {
644 // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
645 match &mut local
.kind
{
646 LocalKind
::Init(expr
) | LocalKind
::InitElse(expr
, _
) => {
647 self.check_mistyped_turbofish_with_multiple_type_params(e
, expr
)?
;
648 // We found `foo<bar, baz>`, have we fully recovered?
651 LocalKind
::Decl
=> return Err(e
),
655 StmtKind
::Empty
| StmtKind
::Item(_
) | StmtKind
::Local(_
) | StmtKind
::Semi(_
) => eat_semi
= false,
658 if eat_semi
&& self.eat(&token
::Semi
) {
659 stmt
= stmt
.add_trailing_semicolon();
661 stmt
.span
= stmt
.span
.to(self.prev_token
.span
);
665 pub(super) fn mk_block(
667 stmts
: ThinVec
<Stmt
>,
668 rules
: BlockCheckMode
,
677 could_be_bare_literal
: false,
681 pub(super) fn mk_stmt(&self, span
: Span
, kind
: StmtKind
) -> Stmt
{
682 Stmt { id: DUMMY_NODE_ID, kind, span }
685 pub(super) fn mk_stmt_err(&self, span
: Span
) -> Stmt
{
686 self.mk_stmt(span
, StmtKind
::Expr(self.mk_expr_err(span
)))
689 pub(super) fn mk_block_err(&self, span
: Span
) -> P
<Block
> {
690 self.mk_block(thin_vec
![self.mk_stmt_err(span
)], BlockCheckMode
::Default
, span
)