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