1use std::borrow::Cow;
2use std::mem;
3use std::ops::Bound;
4
5use ast::Label;
6use rustc_ast as ast;
7use rustc_ast::ptr::P;
8use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind};
9use rustc_ast::util::classify::{self, TrailingBrace};
10use rustc_ast::{
11 AttrStyle, AttrVec, Block, BlockCheckMode, DUMMY_NODE_ID, Expr, ExprKind, HasAttrs, Local,
12 LocalKind, MacCall, MacCallStmt, MacStmtStyle, Recovered, Stmt, StmtKind,
13};
14use rustc_errors::{Applicability, Diag, PResult};
15use rustc_span::{BytePos, ErrorGuaranteed, Ident, Span, kw, sym};
16use thin_vec::{ThinVec, thin_vec};
17
18use super::attr::InnerAttrForbiddenReason;
19use super::diagnostics::AttemptLocalParseRecovery;
20use super::pat::{PatternLocation, RecoverComma};
21use super::path::PathStyle;
22use super::{
23 AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
24 Trailing, UsePreAttrPos,
25};
26use crate::errors::{self, MalformedLoopLabel};
27use crate::exp;
28
29impl<'a> Parser<'a> {
30 pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> {
37 Ok(self.parse_stmt_without_recovery(false, force_collect, false).unwrap_or_else(|e| {
38 e.emit();
39 self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
40 None
41 }))
42 }
43
44 pub fn parse_stmt_without_recovery(
48 &mut self,
49 capture_semi: bool,
50 force_collect: ForceCollect,
51 force_full_expr: bool,
52 ) -> PResult<'a, Option<Stmt>> {
53 let pre_attr_pos = self.collect_pos();
54 let attrs = self.parse_outer_attributes()?;
55 let lo = self.token.span;
56
57 if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| {
58 this.parse_stmt_without_recovery(false, ForceCollect::Yes, false)
59 }) {
60 let mut stmt = stmt.expect("an actual statement");
61 stmt.visit_attrs(|stmt_attrs| {
62 attrs.prepend_to_nt_inner(stmt_attrs);
63 });
64 return Ok(Some(stmt));
65 }
66
67 if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
68 self.bump();
69 let mut_let_span = lo.to(self.token.span);
70 self.dcx().emit_err(errors::InvalidVariableDeclaration {
71 span: mut_let_span,
72 sub: errors::InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span),
73 });
74 }
75
76 let stmt = if self.token.is_keyword(kw::Super) && self.is_keyword_ahead(1, &[kw::Let]) {
77 self.collect_tokens(None, attrs, force_collect, |this, attrs| {
78 let super_span = this.token.span;
79 this.expect_keyword(exp!(Super))?;
80 this.expect_keyword(exp!(Let))?;
81 this.psess.gated_spans.gate(sym::super_let, super_span);
82 let local = this.parse_local(Some(super_span), attrs)?;
83 let trailing = Trailing::from(capture_semi && this.token == token::Semi);
84 Ok((
85 this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
86 trailing,
87 UsePreAttrPos::No,
88 ))
89 })?
90 } else if self.token.is_keyword(kw::Let) {
91 self.collect_tokens(None, attrs, force_collect, |this, attrs| {
92 this.expect_keyword(exp!(Let))?;
93 let local = this.parse_local(None, attrs)?;
94 let trailing = Trailing::from(capture_semi && this.token == token::Semi);
95 Ok((
96 this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
97 trailing,
98 UsePreAttrPos::No,
99 ))
100 })?
101 } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
102 self.recover_stmt_local_after_let(
103 lo,
104 attrs,
105 errors::InvalidVariableDeclarationSub::MissingLet,
106 force_collect,
107 )?
108 } else if self.is_kw_followed_by_ident(kw::Auto) && self.may_recover() {
109 self.bump(); self.recover_stmt_local_after_let(
111 lo,
112 attrs,
113 errors::InvalidVariableDeclarationSub::UseLetNotAuto,
114 force_collect,
115 )?
116 } else if self.is_kw_followed_by_ident(sym::var) && self.may_recover() {
117 self.bump(); self.recover_stmt_local_after_let(
119 lo,
120 attrs,
121 errors::InvalidVariableDeclarationSub::UseLetNotVar,
122 force_collect,
123 )?
124 } else if self.check_path()
125 && !self.token.is_qpath_start()
126 && !self.is_path_start_item()
127 && !self.is_builtin()
128 {
129 let stmt = self.collect_tokens(
139 Some(pre_attr_pos),
140 AttrWrapper::empty(),
141 force_collect,
142 |this, _empty_attrs| {
143 Ok((this.parse_stmt_path_start(lo, attrs)?, Trailing::No, UsePreAttrPos::Yes))
144 },
145 );
146 match stmt {
147 Ok(stmt) => stmt,
148 Err(mut err) => {
149 self.suggest_add_missing_let_for_stmt(&mut err);
150 return Err(err);
151 }
152 }
153 } else if let Some(item) = self.parse_item_common(
154 attrs.clone(), false,
156 true,
157 FnParseMode { req_name: |_| true, req_body: true },
158 force_collect,
159 )? {
160 self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
161 } else if self.eat(exp!(Semi)) {
162 self.error_outer_attrs(attrs);
164 self.mk_stmt(lo, StmtKind::Empty)
165 } else if self.token != token::CloseBrace {
166 let restrictions =
169 if force_full_expr { Restrictions::empty() } else { Restrictions::STMT_EXPR };
170 let e = self.collect_tokens(
171 Some(pre_attr_pos),
172 AttrWrapper::empty(),
173 force_collect,
174 |this, _empty_attrs| {
175 let (expr, _) = this.parse_expr_res(restrictions, attrs)?;
176 Ok((expr, Trailing::No, UsePreAttrPos::Yes))
177 },
178 )?;
179 if matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(exp!(Else)) {
180 let bl = self.parse_block()?;
181 self.dcx().emit_err(errors::AssignmentElseNotAllowed { span: e.span.to(bl.span) });
184 }
185 self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
186 } else {
187 self.error_outer_attrs(attrs);
188 return Ok(None);
189 };
190
191 self.maybe_augment_stashed_expr_in_pats_with_suggestions(&stmt);
192 Ok(Some(stmt))
193 }
194
195 fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
196 let stmt = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
197 let path = this.parse_path(PathStyle::Expr)?;
198
199 if this.eat(exp!(Bang)) {
200 let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?;
201 return Ok((
202 stmt_mac,
203 Trailing::from(this.token == token::Semi),
204 UsePreAttrPos::No,
205 ));
206 }
207
208 let expr = if this.eat(exp!(OpenBrace)) {
209 this.parse_expr_struct(None, path, true)?
210 } else {
211 let hi = this.prev_token.span;
212 this.mk_expr(lo.to(hi), ExprKind::Path(None, path))
213 };
214
215 let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
216 this.parse_expr_dot_or_call_with(attrs, expr, lo)
217 })?;
218 Ok((
220 this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)),
221 Trailing::No,
222 UsePreAttrPos::No,
223 ))
224 })?;
225
226 if let StmtKind::Expr(expr) = stmt.kind {
227 let (expr, _) = self.with_res(Restrictions::STMT_EXPR, |this| {
230 this.parse_expr_assoc_rest_with(Bound::Unbounded, true, expr)
231 })?;
232 Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
233 } else {
234 Ok(stmt)
235 }
236 }
237
238 fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> {
241 let args = self.parse_delim_args()?;
242 let hi = self.prev_token.span;
243
244 let style = match args.delim {
245 Delimiter::Brace => MacStmtStyle::Braces,
246 _ => MacStmtStyle::NoBraces,
247 };
248
249 let mac = P(MacCall { path, args });
250
251 let kind = if (style == MacStmtStyle::Braces
252 && !matches!(self.token.kind, token::Dot | token::Question))
253 || matches!(
254 self.token.kind,
255 token::Semi
256 | token::Eof
257 | token::CloseInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Stmt))
258 ) {
259 StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
260 } else {
261 let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
263 let e = self.maybe_recover_from_bad_qpath(e)?;
264 let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
265 let (e, _) = self.parse_expr_assoc_rest_with(Bound::Unbounded, false, e)?;
266 StmtKind::Expr(e)
267 };
268 Ok(self.mk_stmt(lo.to(hi), kind))
269 }
270
271 fn error_outer_attrs(&self, attrs: AttrWrapper) {
274 if !attrs.is_empty()
275 && let attrs @ [.., last] = &*attrs.take_for_recovery(self.psess)
276 {
277 if last.is_doc_comment() {
278 self.dcx().emit_err(errors::DocCommentDoesNotDocumentAnything {
279 span: last.span,
280 missing_comma: None,
281 });
282 } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
283 self.dcx().emit_err(errors::ExpectedStatementAfterOuterAttr { span: last.span });
284 }
285 }
286 }
287
288 fn recover_stmt_local_after_let(
289 &mut self,
290 lo: Span,
291 attrs: AttrWrapper,
292 subdiagnostic: fn(Span) -> errors::InvalidVariableDeclarationSub,
293 force_collect: ForceCollect,
294 ) -> PResult<'a, Stmt> {
295 let stmt = self.collect_tokens(None, attrs, force_collect, |this, attrs| {
296 let local = this.parse_local(None, attrs)?;
297 Ok((
299 this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
300 Trailing::No,
301 UsePreAttrPos::No,
302 ))
303 })?;
304 self.dcx()
305 .emit_err(errors::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
306 Ok(stmt)
307 }
308
309 fn parse_local(&mut self, super_: Option<Span>, attrs: AttrVec) -> PResult<'a, P<Local>> {
311 let lo = super_.unwrap_or(self.prev_token.span);
312
313 if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
314 self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
315 self.bump();
316 }
317
318 let (pat, colon) =
319 self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?;
320
321 let (err, ty, colon_sp) = if colon {
322 let parser_snapshot_before_type = self.clone();
325 let colon_sp = self.prev_token.span;
326 match self.parse_ty() {
327 Ok(ty) => (None, Some(ty), Some(colon_sp)),
328 Err(mut err) => {
329 err.span_label(
330 colon_sp,
331 format!(
332 "while parsing the type for {}",
333 pat.descr()
334 .map_or_else(|| "the binding".to_string(), |n| format!("`{n}`"))
335 ),
336 );
337 let err = if self.check_noexpect(&token::Eq) {
341 err.emit();
342 None
343 } else {
344 let parser_snapshot_after_type =
346 mem::replace(self, parser_snapshot_before_type);
347 Some((parser_snapshot_after_type, colon_sp, err))
348 };
349 (err, None, Some(colon_sp))
350 }
351 }
352 } else {
353 (None, None, None)
354 };
355 let init = match (self.parse_initializer(err.is_some()), err) {
356 (Ok(init), None) => {
357 init
359 }
360 (Ok(init), Some((_, colon_sp, mut err))) => {
361 err.span_suggestion_short(
365 colon_sp,
366 "use `=` if you meant to assign",
367 " =",
368 Applicability::MachineApplicable,
369 );
370 err.emit();
371 init
375 }
376 (Err(init_err), Some((snapshot, _, ty_err))) => {
377 init_err.cancel();
379 *self = snapshot;
383 return Err(ty_err);
384 }
385 (Err(err), None) => {
386 return Err(err);
390 }
391 };
392 let kind = match init {
393 None => LocalKind::Decl,
394 Some(init) => {
395 if self.eat_keyword(exp!(Else)) {
396 if self.token.is_keyword(kw::If) {
397 let msg = "conditional `else if` is not supported for `let...else`";
400 return Err(self.error_block_no_opening_brace_msg(Cow::from(msg)));
401 }
402 let els = self.parse_block()?;
403 self.check_let_else_init_bool_expr(&init);
404 self.check_let_else_init_trailing_brace(&init);
405 LocalKind::InitElse(init, els)
406 } else {
407 LocalKind::Init(init)
408 }
409 }
410 };
411 let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span };
412 Ok(P(ast::Local {
413 super_,
414 ty,
415 pat,
416 kind,
417 id: DUMMY_NODE_ID,
418 span: lo.to(hi),
419 colon_sp,
420 attrs,
421 tokens: None,
422 }))
423 }
424
425 fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
426 if let ast::ExprKind::Binary(op, ..) = init.kind {
427 if op.node.is_lazy() {
428 self.dcx().emit_err(errors::InvalidExpressionInLetElse {
429 span: init.span,
430 operator: op.node.as_str(),
431 sugg: errors::WrapInParentheses::Expression {
432 left: init.span.shrink_to_lo(),
433 right: init.span.shrink_to_hi(),
434 },
435 });
436 }
437 }
438 }
439
440 fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
441 if let Some(trailing) = classify::expr_trailing_brace(init) {
442 let (span, sugg) = match trailing {
443 TrailingBrace::MacCall(mac) => (
444 mac.span(),
445 errors::WrapInParentheses::MacroArgs {
446 left: mac.args.dspan.open,
447 right: mac.args.dspan.close,
448 },
449 ),
450 TrailingBrace::Expr(expr) => (
451 expr.span,
452 errors::WrapInParentheses::Expression {
453 left: expr.span.shrink_to_lo(),
454 right: expr.span.shrink_to_hi(),
455 },
456 ),
457 };
458 self.dcx().emit_err(errors::InvalidCurlyInLetElse {
459 span: span.with_lo(span.hi() - BytePos(1)),
460 sugg,
461 });
462 }
463 }
464
465 fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>> {
467 let eq_consumed = match self.token.kind {
468 token::PlusEq
469 | token::MinusEq
470 | token::StarEq
471 | token::SlashEq
472 | token::PercentEq
473 | token::CaretEq
474 | token::AndEq
475 | token::OrEq
476 | token::ShlEq
477 | token::ShrEq => {
478 let extra_op_span = self.psess.source_map().start_point(self.token.span);
483 self.dcx().emit_err(errors::CompoundAssignmentExpressionInLet {
484 span: self.token.span,
485 suggestion: extra_op_span,
486 });
487 self.bump();
488 true
489 }
490 _ => self.eat(exp!(Eq)),
491 };
492
493 Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None })
494 }
495
496 pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
498 let (attrs, block) = self.parse_inner_attrs_and_block(None)?;
499 if let [.., last] = &*attrs {
500 let suggest_to_outer = match &last.kind {
501 ast::AttrKind::Normal(attr) => attr.item.is_valid_for_outer_style(),
502 _ => false,
503 };
504 self.error_on_forbidden_inner_attr(
505 last.span,
506 super::attr::InnerAttrPolicy::Forbidden(Some(
507 InnerAttrForbiddenReason::InCodeBlock,
508 )),
509 suggest_to_outer,
510 );
511 }
512 Ok(block)
513 }
514
515 fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> {
516 let prev = self.prev_token.span;
517 let sp = self.token.span;
518 let mut e = self.dcx().struct_span_err(sp, msg);
519 self.label_expected_raw_ref(&mut e);
520
521 let do_not_suggest_help = self.token.is_keyword(kw::In)
522 || self.token == token::Colon
523 || self.prev_token.is_keyword(kw::Raw);
524
525 match self.parse_stmt_without_recovery(false, ForceCollect::No, false) {
532 Ok(Some(_))
547 if (!self.token.is_keyword(kw::Else)
548 && self.look_ahead(1, |t| t == &token::OpenBrace))
549 || do_not_suggest_help => {}
550 Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {}
552 Ok(Some(stmt)) => {
553 let stmt_own_line = self.psess.source_map().is_line_before_span_empty(sp);
554 let stmt_span = if stmt_own_line && self.eat(exp!(Semi)) {
555 stmt.span.with_hi(self.prev_token.span.hi())
557 } else {
558 stmt.span
559 };
560 self.suggest_fixes_misparsed_for_loop_head(
561 &mut e,
562 prev.between(sp),
563 stmt_span,
564 &stmt.kind,
565 );
566 }
567 Err(e) => {
568 self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
569 e.cancel();
570 }
571 _ => {}
572 }
573 e.span_label(sp, "expected `{`");
574 e
575 }
576
577 fn suggest_fixes_misparsed_for_loop_head(
578 &self,
579 e: &mut Diag<'_>,
580 between: Span,
581 stmt_span: Span,
582 stmt_kind: &StmtKind,
583 ) {
584 match (&self.token.kind, &stmt_kind) {
585 (token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Call(..) = expr.kind => {
586 e.span_suggestion_verbose(
588 between,
589 "you might have meant to write a method call",
590 ".".to_string(),
591 Applicability::MaybeIncorrect,
592 );
593 }
594 (token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Field(..) = expr.kind => {
595 e.span_suggestion_verbose(
597 between,
598 "you might have meant to write a field access",
599 ".".to_string(),
600 Applicability::MaybeIncorrect,
601 );
602 }
603 (token::CloseBrace, StmtKind::Expr(expr))
604 if let ExprKind::Struct(expr) = &expr.kind
605 && let None = expr.qself
606 && expr.path.segments.len() == 1 =>
607 {
608 e.span_suggestion_verbose(
612 between,
613 "you might have meant to write a field access",
614 ".".to_string(),
615 Applicability::MaybeIncorrect,
616 );
617 }
618 (token::OpenBrace, StmtKind::Expr(expr))
619 if let ExprKind::Lit(lit) = expr.kind
620 && let None = lit.suffix
621 && let token::LitKind::Integer | token::LitKind::Float = lit.kind =>
622 {
623 e.span_suggestion_verbose(
626 between,
627 format!("you might have meant to write a field access"),
628 ".".to_string(),
629 Applicability::MaybeIncorrect,
630 );
631 }
632 (token::OpenBrace, StmtKind::Expr(expr))
633 if let ExprKind::Loop(..)
634 | ExprKind::If(..)
635 | ExprKind::While(..)
636 | ExprKind::Match(..)
637 | ExprKind::ForLoop { .. }
638 | ExprKind::TryBlock(..)
639 | ExprKind::Ret(..)
640 | ExprKind::Closure(..)
641 | ExprKind::Struct(..)
642 | ExprKind::Try(..) = expr.kind =>
643 {
644 e.multipart_suggestion(
646 "you might have meant to write this as part of a block",
647 vec![
648 (stmt_span.shrink_to_lo(), "{ ".to_string()),
649 (stmt_span.shrink_to_hi(), " }".to_string()),
650 ],
651 Applicability::MaybeIncorrect,
653 );
654 }
655 (token::OpenBrace, _) => {}
656 (_, _) => {
657 e.multipart_suggestion(
658 "you might have meant to write this as part of a block",
659 vec![
660 (stmt_span.shrink_to_lo(), "{ ".to_string()),
661 (stmt_span.shrink_to_hi(), " }".to_string()),
662 ],
663 Applicability::MaybeIncorrect,
665 );
666 }
667 }
668 }
669
670 fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
671 let tok = super::token_descr(&self.token);
672 let msg = format!("expected `{{`, found {tok}");
673 Err(self.error_block_no_opening_brace_msg(Cow::from(msg)))
674 }
675
676 pub(super) fn parse_inner_attrs_and_block(
681 &mut self,
682 loop_header: Option<Span>,
683 ) -> PResult<'a, (AttrVec, P<Block>)> {
684 self.parse_block_common(self.token.span, BlockCheckMode::Default, loop_header)
685 }
686
687 pub(super) fn parse_block_common(
692 &mut self,
693 lo: Span,
694 blk_mode: BlockCheckMode,
695 loop_header: Option<Span>,
696 ) -> PResult<'a, (AttrVec, P<Block>)> {
697 if let Some(block) = self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) {
698 return Ok((AttrVec::new(), block));
699 }
700
701 let maybe_ident = self.prev_token;
702 self.maybe_recover_unexpected_block_label(loop_header);
703 if !self.eat(exp!(OpenBrace)) {
704 return self.error_block_no_opening_brace();
705 }
706
707 let attrs = self.parse_inner_attributes()?;
708 let tail = match self.maybe_suggest_struct_literal(lo, blk_mode, maybe_ident) {
709 Some(tail) => tail?,
710 None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?,
711 };
712 Ok((attrs, tail))
713 }
714
715 pub(crate) fn parse_block_tail(
718 &mut self,
719 lo: Span,
720 s: BlockCheckMode,
721 recover: AttemptLocalParseRecovery,
722 ) -> PResult<'a, P<Block>> {
723 let mut stmts = ThinVec::new();
724 let mut snapshot = None;
725 while !self.eat(exp!(CloseBrace)) {
726 if self.token == token::Eof {
727 break;
728 }
729 if self.is_vcs_conflict_marker(&TokenKind::Shl, &TokenKind::Lt) {
730 snapshot = Some(self.create_snapshot_for_diagnostic());
734 }
735 let stmt = match self.parse_full_stmt(recover) {
736 Err(mut err) if recover.yes() => {
737 if let Some(ref mut snapshot) = snapshot {
738 snapshot.recover_vcs_conflict_marker();
739 }
740 if self.token == token::Colon {
741 if self.prev_token.is_integer_lit()
745 && self.may_recover()
746 && self.look_ahead(1, |token| token.is_integer_lit())
747 {
748 err.span_suggestion_verbose(
751 self.token.span,
752 "you might have meant a range expression",
753 "..",
754 Applicability::MaybeIncorrect,
755 );
756 } else {
757 self.bump();
760 if self.token.span.lo() == self.prev_token.span.hi() {
761 err.span_suggestion_verbose(
762 self.prev_token.span,
763 "maybe write a path separator here",
764 "::",
765 Applicability::MaybeIncorrect,
766 );
767 }
768 }
769 }
770
771 let guar = err.emit();
772 self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
773 Some(self.mk_stmt_err(self.token.span, guar))
774 }
775 Ok(stmt) => stmt,
776 Err(err) => return Err(err),
777 };
778 if let Some(stmt) = stmt {
779 stmts.push(stmt);
780 } else {
781 continue;
783 };
784 }
785 Ok(self.mk_block(stmts, s, lo.to(self.prev_token.span)))
786 }
787
788 fn recover_missing_dot(&mut self, err: &mut Diag<'_>) {
789 let Some((ident, _)) = self.token.ident() else {
790 return;
791 };
792 if let Some(c) = ident.name.as_str().chars().next()
793 && c.is_uppercase()
794 {
795 return;
796 }
797 if self.token.is_reserved_ident() && !self.token.is_ident_named(kw::Await) {
798 return;
799 }
800 if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) {
801 } else if !self.prev_token.is_reserved_ident() && self.prev_token.is_ident() {
803 } else if self.prev_token.kind == token::Question {
805 } else if self.prev_token.kind == token::CloseParen {
807 } else {
809 return;
810 }
811 if self.token.span == self.prev_token.span {
812 return;
814 }
815 if self.look_ahead(1, |t| [token::Semi, token::Question, token::Dot].contains(&t.kind)) {
816 err.span_suggestion_verbose(
817 self.prev_token.span.between(self.token.span),
818 "you might have meant to write a field access",
819 ".".to_string(),
820 Applicability::MaybeIncorrect,
821 );
822 }
823 if self.look_ahead(1, |t| t.kind == token::OpenParen) {
824 err.span_suggestion_verbose(
825 self.prev_token.span.between(self.token.span),
826 "you might have meant to write a method call",
827 ".".to_string(),
828 Applicability::MaybeIncorrect,
829 );
830 }
831 }
832
833 pub fn parse_full_stmt(
835 &mut self,
836 recover: AttemptLocalParseRecovery,
837 ) -> PResult<'a, Option<Stmt>> {
838 if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| {
840 this.parse_stmt_without_recovery(false, ForceCollect::No, true)
849 }) {
850 let stmt = stmt.expect("an actual statement");
851 return Ok(Some(stmt));
852 }
853
854 let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No, false)?
855 else {
856 return Ok(None);
857 };
858
859 let mut eat_semi = true;
860 let mut add_semi_to_stmt = false;
861
862 match &mut stmt.kind {
863 StmtKind::Expr(expr)
865 if classify::expr_requires_semi_to_be_stmt(expr)
866 && !expr.attrs.is_empty()
867 && !matches!(self.token.kind, token::Eof | token::Semi | token::CloseBrace) =>
868 {
869 let guar = self.attr_on_non_tail_expr(&expr);
871 let sp = expr.span.to(self.prev_token.span);
873 *expr = self.mk_expr_err(sp, guar);
874 }
875
876 StmtKind::Expr(expr)
878 if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
879 {
880 let expect_result = self.expect_one_of(&[], &[exp!(Semi), exp!(CloseBrace)]);
883
884 let replace_with_err = 'break_recover: {
887 match expect_result {
888 Ok(Recovered::No) => None,
889 Ok(Recovered::Yes(guar)) => {
890 Some(guar)
892 }
893 Err(e) => {
894 if self.recover_colon_as_semi() {
895 e.delay_as_bug();
897 add_semi_to_stmt = true;
898 eat_semi = false;
899
900 break 'break_recover None;
901 }
902
903 match &expr.kind {
904 ExprKind::Path(None, ast::Path { segments, .. })
905 if let [segment] = segments.as_slice() =>
906 {
907 if self.token == token::Colon
908 && self.look_ahead(1, |token| {
909 token.is_metavar_block()
910 || matches!(
911 token.kind,
912 token::Ident(
913 kw::For | kw::Loop | kw::While,
914 token::IdentIsRaw::No
915 ) | token::OpenBrace
916 )
917 })
918 {
919 let snapshot = self.create_snapshot_for_diagnostic();
920 let label = Label {
921 ident: Ident::from_str_and_span(
922 &format!("'{}", segment.ident),
923 segment.ident.span,
924 ),
925 };
926 match self.parse_expr_labeled(label, false) {
927 Ok(labeled_expr) => {
928 e.cancel();
929 self.dcx().emit_err(MalformedLoopLabel {
930 span: label.ident.span,
931 suggestion: label.ident.span.shrink_to_lo(),
932 });
933 *expr = labeled_expr;
934 break 'break_recover None;
935 }
936 Err(err) => {
937 err.cancel();
938 self.restore_snapshot(snapshot);
939 }
940 }
941 }
942 }
943 _ => {}
944 }
945
946 let res =
947 self.check_mistyped_turbofish_with_multiple_type_params(e, expr);
948
949 Some(if recover.no() {
950 res?
951 } else {
952 res.unwrap_or_else(|mut e| {
953 self.recover_missing_dot(&mut e);
954 let guar = e.emit();
955 self.recover_stmt();
956 guar
957 })
958 })
959 }
960 }
961 };
962
963 if let Some(guar) = replace_with_err {
964 let sp = expr.span.to(self.prev_token.span);
966 *expr = self.mk_expr_err(sp, guar);
967 }
968 }
969 StmtKind::Expr(_) | StmtKind::MacCall(_) => {}
970 StmtKind::Let(local) if let Err(mut e) = self.expect_semi() => {
971 match &mut local.kind {
973 LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => {
974 self.check_mistyped_turbofish_with_multiple_type_params(e, expr).map_err(
975 |mut e| {
976 self.recover_missing_dot(&mut e);
977 e
978 },
979 )?;
980 self.expect_semi()?;
982 }
983 LocalKind::Decl => {
984 if let Some(colon_sp) = local.colon_sp {
985 e.span_label(
986 colon_sp,
987 format!(
988 "while parsing the type for {}",
989 local.pat.descr().map_or_else(
990 || "the binding".to_string(),
991 |n| format!("`{n}`")
992 )
993 ),
994 );
995 let suggest_eq = if self.token == token::Dot
996 && let _ = self.bump()
997 && let mut snapshot = self.create_snapshot_for_diagnostic()
998 && let Ok(_) = snapshot
999 .parse_dot_suffix_expr(
1000 colon_sp,
1001 self.mk_expr_err(
1002 colon_sp,
1003 self.dcx()
1004 .delayed_bug("error during `:` -> `=` recovery"),
1005 ),
1006 )
1007 .map_err(Diag::cancel)
1008 {
1009 true
1010 } else if let Some(op) = self.check_assoc_op()
1011 && op.node.can_continue_expr_unambiguously()
1012 {
1013 true
1014 } else {
1015 false
1016 };
1017 if suggest_eq {
1018 e.span_suggestion_short(
1019 colon_sp,
1020 "use `=` if you meant to assign",
1021 "=",
1022 Applicability::MaybeIncorrect,
1023 );
1024 }
1025 }
1026 return Err(e);
1027 }
1028 }
1029 eat_semi = false;
1030 }
1031 StmtKind::Empty | StmtKind::Item(_) | StmtKind::Let(_) | StmtKind::Semi(_) => {
1032 eat_semi = false
1033 }
1034 }
1035
1036 if add_semi_to_stmt || (eat_semi && self.eat(exp!(Semi))) {
1037 stmt = stmt.add_trailing_semicolon();
1038 }
1039
1040 stmt.span = stmt.span.to(self.prev_token.span);
1041 Ok(Some(stmt))
1042 }
1043
1044 pub(super) fn mk_block(
1045 &self,
1046 stmts: ThinVec<Stmt>,
1047 rules: BlockCheckMode,
1048 span: Span,
1049 ) -> P<Block> {
1050 P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None })
1051 }
1052
1053 pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
1054 Stmt { id: DUMMY_NODE_ID, kind, span }
1055 }
1056
1057 pub(super) fn mk_stmt_err(&self, span: Span, guar: ErrorGuaranteed) -> Stmt {
1058 self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span, guar)))
1059 }
1060
1061 pub(super) fn mk_block_err(&self, span: Span, guar: ErrorGuaranteed) -> P<Block> {
1062 self.mk_block(thin_vec![self.mk_stmt_err(span, guar)], BlockCheckMode::Default, span)
1063 }
1064}