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::visit::{Visitor, walk_expr};
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 AllowConstBlockItems, AttrWrapper, BlockMode, FnContext, FnParseMode, ForceCollect, Parser,
24 Restrictions, SemiColonMode, 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(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Super,
token_type: crate::parser::token_type::TokenType::KwSuper,
}exp!(Super))?;
80 this.expect_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Let,
token_type: crate::parser::token_type::TokenType::KwLet,
}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(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Let,
token_type: crate::parser::token_type::TokenType::KwLet,
}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, context: FnContext::Free, req_body: true },
158 force_collect,
159 AllowConstBlockItems::No,
160 )? {
161 self.mk_stmt(lo.to(item.span), StmtKind::Item(Box::new(item)))
162 } else if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) {
163 self.error_outer_attrs(attrs);
165 self.mk_stmt(lo, StmtKind::Empty)
166 } else if self.token != token::CloseBrace {
167 let restrictions =
170 if force_full_expr { Restrictions::empty() } else { Restrictions::STMT_EXPR };
171 let e = self.collect_tokens(
172 Some(pre_attr_pos),
173 AttrWrapper::empty(),
174 force_collect,
175 |this, _empty_attrs| {
176 let (expr, _) = this.parse_expr_res(restrictions, attrs)?;
177 Ok((expr, Trailing::No, UsePreAttrPos::Yes))
178 },
179 )?;
180 if #[allow(non_exhaustive_omitted_patterns)] match e.kind {
ExprKind::Assign(..) => true,
_ => false,
}matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Else,
token_type: crate::parser::token_type::TokenType::KwElse,
}exp!(Else)) {
181 let bl = self.parse_block()?;
182 self.dcx().emit_err(errors::AssignmentElseNotAllowed { span: e.span.to(bl.span) });
185 }
186 self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
187 } else {
188 self.error_outer_attrs(attrs);
189 return Ok(None);
190 };
191
192 self.maybe_augment_stashed_expr_in_pats_with_suggestions(&stmt);
193 Ok(Some(stmt))
194 }
195
196 fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
197 let stmt = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
198 let path = this.parse_path(PathStyle::Expr)?;
199
200 if this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Bang,
token_type: crate::parser::token_type::TokenType::Bang,
}exp!(Bang)) {
201 let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?;
202 return Ok((
203 stmt_mac,
204 Trailing::from(this.token == token::Semi),
205 UsePreAttrPos::No,
206 ));
207 }
208
209 let expr = if this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace)) {
210 this.parse_expr_struct(None, path, true)?
211 } else {
212 let hi = this.prev_token.span;
213 this.mk_expr(lo.to(hi), ExprKind::Path(None, path))
214 };
215
216 let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
217 this.parse_expr_dot_or_call_with(attrs, expr, lo)
218 })?;
219 Ok((
221 this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)),
222 Trailing::No,
223 UsePreAttrPos::No,
224 ))
225 })?;
226
227 if let StmtKind::Expr(expr) = stmt.kind {
228 let (expr, _) = self.with_res(Restrictions::STMT_EXPR, |this| {
231 this.parse_expr_assoc_rest_with(Bound::Unbounded, true, expr)
232 })?;
233 Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
234 } else {
235 Ok(stmt)
236 }
237 }
238
239 fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResult<'a, Stmt> {
242 let args = self.parse_delim_args()?;
243 let hi = self.prev_token.span;
244
245 let style = match args.delim {
246 Delimiter::Brace => MacStmtStyle::Braces,
247 _ => MacStmtStyle::NoBraces,
248 };
249
250 let mac = Box::new(MacCall { path, args });
251
252 let kind = if (style == MacStmtStyle::Braces
253 && !#[allow(non_exhaustive_omitted_patterns)] match self.token.kind {
token::Dot | token::Question => true,
_ => false,
}matches!(self.token.kind, token::Dot | token::Question))
254 || #[allow(non_exhaustive_omitted_patterns)] match self.token.kind {
token::Semi | token::Eof |
token::CloseInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Stmt)) =>
true,
_ => false,
}matches!(
255 self.token.kind,
256 token::Semi
257 | token::Eof
258 | token::CloseInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Stmt))
259 ) {
260 StmtKind::MacCall(Box::new(MacCallStmt { mac, style, attrs, tokens: None }))
261 } else {
262 let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
264 let e = self.maybe_recover_from_bad_qpath(e)?;
265 let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
266 let (e, _) = self.parse_expr_assoc_rest_with(Bound::Unbounded, false, e)?;
267 StmtKind::Expr(e)
268 };
269 Ok(self.mk_stmt(lo.to(hi), kind))
270 }
271
272 fn error_outer_attrs(&self, attrs: AttrWrapper) {
275 if !attrs.is_empty()
276 && let attrs @ [.., last] = &*attrs.take_for_recovery(self.psess)
277 {
278 if last.is_doc_comment() {
279 self.dcx().emit_err(errors::DocCommentDoesNotDocumentAnything {
280 span: last.span,
281 missing_comma: None,
282 });
283 } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
284 self.dcx().emit_err(errors::ExpectedStatementAfterOuterAttr { span: last.span });
285 }
286 }
287 }
288
289 fn recover_stmt_local_after_let(
290 &mut self,
291 lo: Span,
292 attrs: AttrWrapper,
293 subdiagnostic: fn(Span) -> errors::InvalidVariableDeclarationSub,
294 force_collect: ForceCollect,
295 ) -> PResult<'a, Stmt> {
296 let stmt = self.collect_tokens(None, attrs, force_collect, |this, attrs| {
297 let local = this.parse_local(None, attrs)?;
298 Ok((
300 this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
301 Trailing::No,
302 UsePreAttrPos::No,
303 ))
304 })?;
305 self.dcx()
306 .emit_err(errors::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
307 Ok(stmt)
308 }
309
310 fn parse_local(&mut self, super_: Option<Span>, attrs: AttrVec) -> PResult<'a, Box<Local>> {
312 let lo = super_.unwrap_or(self.prev_token.span);
313
314 if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
315 self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
316 self.bump();
317 }
318
319 let (pat, colon) =
320 self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?;
321
322 let (err, ty, colon_sp) = if colon {
323 let parser_snapshot_before_type = self.clone();
326 let colon_sp = self.prev_token.span;
327 match self.parse_ty() {
328 Ok(ty) => (None, Some(ty), Some(colon_sp)),
329 Err(mut err) => {
330 err.span_label(
331 colon_sp,
332 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("while parsing the type for {0}",
pat.descr().map_or_else(|| "the binding".to_string(),
|n|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", n))
}))))
})format!(
333 "while parsing the type for {}",
334 pat.descr()
335 .map_or_else(|| "the binding".to_string(), |n| format!("`{n}`"))
336 ),
337 );
338 let err = if self.check_noexpect(&token::Eq) {
342 err.emit();
343 None
344 } else {
345 let parser_snapshot_after_type =
347 mem::replace(self, parser_snapshot_before_type);
348 Some((parser_snapshot_after_type, colon_sp, err))
349 };
350 (err, None, Some(colon_sp))
351 }
352 }
353 } else {
354 (None, None, None)
355 };
356 let init = match (self.parse_initializer(err.is_some()), err) {
357 (Ok(init), None) => {
358 init
360 }
361 (Ok(init), Some((_, colon_sp, mut err))) => {
362 err.span_suggestion_short(
366 colon_sp,
367 "use `=` if you meant to assign",
368 " =",
369 Applicability::MachineApplicable,
370 );
371 err.emit();
372 init
376 }
377 (Err(init_err), Some((snapshot, _, ty_err))) => {
378 init_err.cancel();
380 *self = snapshot;
384 return Err(ty_err);
385 }
386 (Err(err), None) => {
387 return Err(err);
391 }
392 };
393 let kind = match init {
394 None => LocalKind::Decl,
395 Some(init) => {
396 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Else,
token_type: crate::parser::token_type::TokenType::KwElse,
}exp!(Else)) {
397 if self.token.is_keyword(kw::If) {
398 let msg = "conditional `else if` is not supported for `let...else`";
401 return Err(self.error_block_no_opening_brace_msg(Cow::from(msg)));
402 }
403 let els = self.parse_block()?;
404 self.check_let_else_init_bool_expr(&init);
405 self.check_let_else_init_trailing_brace(&init);
406 LocalKind::InitElse(init, els)
407 } else {
408 LocalKind::Init(init)
409 }
410 }
411 };
412 let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span };
413 Ok(Box::new(ast::Local {
414 super_,
415 ty,
416 pat,
417 kind,
418 id: DUMMY_NODE_ID,
419 span: lo.to(hi),
420 colon_sp,
421 attrs,
422 tokens: None,
423 }))
424 }
425
426 fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
427 if let ast::ExprKind::Binary(op, ..) = init.kind {
428 if op.node.is_lazy() {
429 self.dcx().emit_err(errors::InvalidExpressionInLetElse {
430 span: init.span,
431 operator: op.node.as_str(),
432 sugg: errors::WrapInParentheses::Expression {
433 left: init.span.shrink_to_lo(),
434 right: init.span.shrink_to_hi(),
435 },
436 });
437 }
438 }
439 }
440
441 fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
442 if let Some(trailing) = classify::expr_trailing_brace(init) {
443 let (span, sugg) = match trailing {
444 TrailingBrace::MacCall(mac) => (
445 mac.span(),
446 errors::WrapInParentheses::MacroArgs {
447 left: mac.args.dspan.open,
448 right: mac.args.dspan.close,
449 },
450 ),
451 TrailingBrace::Expr(expr) => (
452 expr.span,
453 errors::WrapInParentheses::Expression {
454 left: expr.span.shrink_to_lo(),
455 right: expr.span.shrink_to_hi(),
456 },
457 ),
458 };
459 self.dcx().emit_err(errors::InvalidCurlyInLetElse {
460 span: span.with_lo(span.hi() - BytePos(1)),
461 sugg,
462 });
463 }
464 }
465
466 fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<Box<Expr>>> {
468 let eq_consumed = match self.token.kind {
469 token::PlusEq
470 | token::MinusEq
471 | token::StarEq
472 | token::SlashEq
473 | token::PercentEq
474 | token::CaretEq
475 | token::AndEq
476 | token::OrEq
477 | token::ShlEq
478 | token::ShrEq => {
479 let extra_op_span = self.psess.source_map().start_point(self.token.span);
484 self.dcx().emit_err(errors::CompoundAssignmentExpressionInLet {
485 span: self.token.span,
486 suggestion: extra_op_span,
487 });
488 self.bump();
489 true
490 }
491 _ => self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)),
492 };
493
494 Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None })
495 }
496
497 pub fn parse_block(&mut self) -> PResult<'a, Box<Block>> {
499 let (attrs, block) = self.parse_inner_attrs_and_block(None)?;
500 if let [.., last] = &*attrs {
501 let suggest_to_outer = match &last.kind {
502 ast::AttrKind::Normal(attr) => attr.item.is_valid_for_outer_style(),
503 _ => false,
504 };
505 self.error_on_forbidden_inner_attr(
506 last.span,
507 super::attr::InnerAttrPolicy::Forbidden(Some(
508 InnerAttrForbiddenReason::InCodeBlock,
509 )),
510 suggest_to_outer,
511 );
512 }
513 Ok(block)
514 }
515
516 fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> {
517 let prev = self.prev_token.span;
518 let sp = self.token.span;
519 let mut err = self.dcx().struct_span_err(sp, msg);
520 self.label_expected_raw_ref(&mut err);
521
522 let do_not_suggest_help = self.token.is_keyword(kw::In)
523 || self.token == token::Colon
524 || self.prev_token.is_keyword(kw::Raw);
525
526 match self.parse_stmt_without_recovery(false, ForceCollect::No, false) {
533 Ok(Some(_))
548 if (!self.token.is_keyword(kw::Else)
549 && self.look_ahead(1, |t| t == &token::OpenBrace))
550 || do_not_suggest_help => {}
551 Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {}
553 Ok(Some(stmt)) => {
554 let stmt_own_line = self.psess.source_map().is_line_before_span_empty(sp);
555 let stmt_span = if stmt_own_line && self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) {
556 stmt.span.with_hi(self.prev_token.span.hi())
558 } else {
559 stmt.span
560 };
561 self.suggest_fixes_misparsed_for_loop_head(
562 &mut err,
563 prev.between(sp),
564 stmt_span,
565 &stmt.kind,
566 );
567 }
568 Err(e) => {
569 e.delay_as_bug();
570 }
571 _ => {}
572 }
573 err.span_label(sp, "expected `{`");
574 err
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 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("you might have meant to write a field access"))
})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 <[_]>::into_vec(::alloc::boxed::box_new([(stmt_span.shrink_to_lo(),
"{ ".to_string()),
(stmt_span.shrink_to_hi(), " }".to_string())]))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 <[_]>::into_vec(::alloc::boxed::box_new([(stmt_span.shrink_to_lo(),
"{ ".to_string()),
(stmt_span.shrink_to_hi(), " }".to_string())]))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 = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected `{{`, found {0}", tok))
})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, Box<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, Box<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(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}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 fn parse_block_tail(
718 &mut self,
719 lo: Span,
720 s: BlockCheckMode,
721 recover: AttemptLocalParseRecovery,
722 ) -> PResult<'a, Box<Block>> {
723 let mut stmts = ThinVec::new();
724 let mut snapshot = None;
725 while !self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}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_let_else(&mut self, err: &mut Diag<'_>, pat: &ast::Pat, stmt_span: Span) {
789 if self.token.kind != token::OpenBrace {
790 return;
791 }
792 match pat.kind {
793 ast::PatKind::Ident(..) | ast::PatKind::Missing | ast::PatKind::Wild => {
794 return;
796 }
797 _ => {}
798 }
799 let snapshot = self.create_snapshot_for_diagnostic();
800 let block_span = self.token.span;
801 let (if_let, let_else) = match self.parse_block() {
802 Ok(block) => {
803 let mut idents = ::alloc::vec::Vec::new()vec![];
804 pat.walk(&mut |pat: &ast::Pat| {
805 if let ast::PatKind::Ident(_, ident, _) = pat.kind {
806 idents.push(ident);
807 }
808 true
809 });
810
811 struct IdentFinder {
812 idents: Vec<Ident>,
813 references_ident: bool = false,
818 has_return: bool = false,
821 }
822
823 impl<'a> Visitor<'a> for IdentFinder {
824 fn visit_ident(&mut self, ident: &Ident) {
825 for i in &self.idents {
826 if ident.name == i.name {
827 self.references_ident = true;
828 }
829 }
830 }
831 fn visit_expr(&mut self, node: &'a Expr) {
832 if let ExprKind::Ret(..) = node.kind {
833 self.has_return = true;
834 }
835 walk_expr(self, node);
836 }
837 }
838
839 let mut visitor = IdentFinder { idents, .. };
843 visitor.visit_block(&block);
844
845 (visitor.references_ident, visitor.has_return)
846 }
847 Err(e) => {
848 e.cancel();
849 self.restore_snapshot(snapshot);
850 (false, false)
851 }
852 };
853
854 let mut alternatively = "";
855 if if_let || !let_else {
856 alternatively = "alternatively, ";
857 err.span_suggestion_verbose(
858 stmt_span.shrink_to_lo(),
859 "you might have meant to use `if let`",
860 "if ".to_string(),
861 if if_let {
862 Applicability::MachineApplicable
863 } else {
864 Applicability::MaybeIncorrect
865 },
866 );
867 }
868 if let_else || !if_let {
869 err.span_suggestion_verbose(
870 block_span.shrink_to_lo(),
871 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}you might have meant to use `let...else`",
alternatively))
})format!("{alternatively}you might have meant to use `let...else`"),
872 "else ".to_string(),
873 if let_else {
874 Applicability::MachineApplicable
875 } else {
876 Applicability::MaybeIncorrect
877 },
878 );
879 }
880 }
881
882 fn recover_missing_dot(&mut self, err: &mut Diag<'_>) {
883 let Some((ident, _)) = self.token.ident() else {
884 return;
885 };
886 if let Some(c) = ident.name.as_str().chars().next()
887 && c.is_uppercase()
888 {
889 return;
890 }
891 if self.token.is_reserved_ident() && !self.token.is_ident_named(kw::Await) {
892 return;
893 }
894 if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) {
895 } else if self.prev_token.is_non_reserved_ident() {
897 } else if self.prev_token.kind == token::Question {
899 } else if self.prev_token.kind == token::CloseParen {
901 } else {
903 return;
904 }
905 if self.token.span == self.prev_token.span {
906 return;
908 }
909 if self.look_ahead(1, |t| [token::Semi, token::Question, token::Dot].contains(&t.kind)) {
910 err.span_suggestion_verbose(
911 self.prev_token.span.between(self.token.span),
912 "you might have meant to write a field access",
913 ".".to_string(),
914 Applicability::MaybeIncorrect,
915 );
916 }
917 if self.look_ahead(1, |t| t.kind == token::OpenParen) {
918 err.span_suggestion_verbose(
919 self.prev_token.span.between(self.token.span),
920 "you might have meant to write a method call",
921 ".".to_string(),
922 Applicability::MaybeIncorrect,
923 );
924 }
925 }
926
927 pub fn parse_full_stmt(
929 &mut self,
930 recover: AttemptLocalParseRecovery,
931 ) -> PResult<'a, Option<Stmt>> {
932 if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| {
934 this.parse_stmt_without_recovery(false, ForceCollect::No, true)
943 }) {
944 let stmt = stmt.expect("an actual statement");
945 return Ok(Some(stmt));
946 }
947
948 let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No, false)?
949 else {
950 return Ok(None);
951 };
952
953 let mut eat_semi = true;
954 let mut add_semi_to_stmt = false;
955
956 match &mut stmt.kind {
957 StmtKind::Expr(expr)
959 if classify::expr_requires_semi_to_be_stmt(expr)
960 && !expr.attrs.is_empty()
961 && !#[allow(non_exhaustive_omitted_patterns)] match self.token.kind {
token::Eof | token::Semi | token::CloseBrace => true,
_ => false,
}matches!(self.token.kind, token::Eof | token::Semi | token::CloseBrace) =>
962 {
963 let guar = self.attr_on_non_tail_expr(&expr);
965 let sp = expr.span.to(self.prev_token.span);
967 *expr = self.mk_expr_err(sp, guar);
968 }
969
970 StmtKind::Expr(expr)
972 if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
973 {
974 let expect_result =
977 if let Err(e) = self.maybe_recover_from_ternary_operator(Some(expr.span)) {
978 Err(e)
979 } else {
980 self.expect_one_of(&[], &[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi), crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)])
981 };
982
983 let replace_with_err = 'break_recover: {
986 match expect_result {
987 Ok(Recovered::No) => None,
988 Ok(Recovered::Yes(guar)) => {
989 Some(guar)
991 }
992 Err(e) => {
993 if self.recover_colon_as_semi() {
994 e.delay_as_bug();
996 add_semi_to_stmt = true;
997 eat_semi = false;
998
999 break 'break_recover None;
1000 }
1001
1002 match &expr.kind {
1003 ExprKind::Path(None, ast::Path { segments, .. })
1004 if let [segment] = segments.as_slice() =>
1005 {
1006 if self.token == token::Colon
1007 && self.look_ahead(1, |token| {
1008 token.is_metavar_block()
1009 || #[allow(non_exhaustive_omitted_patterns)] match token.kind {
token::Ident(kw::For | kw::Loop | kw::While, token::IdentIsRaw::No) |
token::OpenBrace => true,
_ => false,
}matches!(
1010 token.kind,
1011 token::Ident(
1012 kw::For | kw::Loop | kw::While,
1013 token::IdentIsRaw::No
1014 ) | token::OpenBrace
1015 )
1016 })
1017 {
1018 let snapshot = self.create_snapshot_for_diagnostic();
1019 let label = Label {
1020 ident: Ident::from_str_and_span(
1021 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\'{0}", segment.ident))
})format!("'{}", segment.ident),
1022 segment.ident.span,
1023 ),
1024 };
1025 match self.parse_expr_labeled(label, false) {
1026 Ok(labeled_expr) => {
1027 e.cancel();
1028 self.dcx().emit_err(MalformedLoopLabel {
1029 span: label.ident.span,
1030 suggestion: label.ident.span.shrink_to_lo(),
1031 });
1032 *expr = labeled_expr;
1033 break 'break_recover None;
1034 }
1035 Err(err) => {
1036 err.cancel();
1037 self.restore_snapshot(snapshot);
1038 }
1039 }
1040 }
1041 }
1042 _ => {}
1043 }
1044
1045 let res =
1046 self.check_mistyped_turbofish_with_multiple_type_params(e, expr);
1047
1048 Some(if recover.no() {
1049 res?
1050 } else {
1051 res.unwrap_or_else(|mut e| {
1052 self.recover_missing_dot(&mut e);
1053 let guar = e.emit();
1054 self.recover_stmt();
1055 guar
1056 })
1057 })
1058 }
1059 }
1060 };
1061
1062 if let Some(guar) = replace_with_err {
1063 let sp = expr.span.to(self.prev_token.span);
1065 *expr = self.mk_expr_err(sp, guar);
1066 }
1067 }
1068 StmtKind::Expr(_) | StmtKind::MacCall(_) => {}
1069 StmtKind::Let(local) if let Err(mut e) = self.expect_semi() => {
1070 match &mut local.kind {
1072 LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => {
1073 self.check_mistyped_turbofish_with_multiple_type_params(e, expr).map_err(
1074 |mut e| {
1075 self.recover_missing_dot(&mut e);
1076 self.recover_missing_let_else(&mut e, &local.pat, stmt.span);
1077 e
1078 },
1079 )?;
1080 self.expect_semi()?;
1082 }
1083 LocalKind::Decl => {
1084 if let Some(colon_sp) = local.colon_sp {
1085 e.span_label(
1086 colon_sp,
1087 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("while parsing the type for {0}",
local.pat.descr().map_or_else(|| "the binding".to_string(),
|n|
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", n))
}))))
})format!(
1088 "while parsing the type for {}",
1089 local.pat.descr().map_or_else(
1090 || "the binding".to_string(),
1091 |n| format!("`{n}`")
1092 )
1093 ),
1094 );
1095 let suggest_eq = if self.token == token::Dot
1096 && let _ = self.bump()
1097 && let mut snapshot = self.create_snapshot_for_diagnostic()
1098 && let Ok(_) = snapshot
1099 .parse_dot_suffix_expr(
1100 colon_sp,
1101 self.mk_expr_err(
1102 colon_sp,
1103 self.dcx()
1104 .delayed_bug("error during `:` -> `=` recovery"),
1105 ),
1106 )
1107 .map_err(Diag::cancel)
1108 {
1109 true
1110 } else if let Some(op) = self.check_assoc_op()
1111 && op.node.can_continue_expr_unambiguously()
1112 {
1113 true
1114 } else {
1115 false
1116 };
1117 if suggest_eq {
1118 e.span_suggestion_short(
1119 colon_sp,
1120 "use `=` if you meant to assign",
1121 "=",
1122 Applicability::MaybeIncorrect,
1123 );
1124 }
1125 }
1126 return Err(e);
1127 }
1128 }
1129 eat_semi = false;
1130 }
1131 StmtKind::Empty | StmtKind::Item(_) | StmtKind::Let(_) | StmtKind::Semi(_) => {
1132 eat_semi = false
1133 }
1134 }
1135
1136 if add_semi_to_stmt || (eat_semi && self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi))) {
1137 stmt = stmt.add_trailing_semicolon();
1138 }
1139
1140 stmt.span = stmt.span.to(self.prev_token.span);
1141 Ok(Some(stmt))
1142 }
1143
1144 pub(super) fn mk_block(
1145 &self,
1146 stmts: ThinVec<Stmt>,
1147 rules: BlockCheckMode,
1148 span: Span,
1149 ) -> Box<Block> {
1150 Box::new(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None })
1151 }
1152
1153 pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
1154 Stmt { id: DUMMY_NODE_ID, kind, span }
1155 }
1156
1157 pub(super) fn mk_stmt_err(&self, span: Span, guar: ErrorGuaranteed) -> Stmt {
1158 self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span, guar)))
1159 }
1160
1161 pub(super) fn mk_block_err(&self, span: Span, guar: ErrorGuaranteed) -> Box<Block> {
1162 self.mk_block({
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(self.mk_stmt_err(span, guar));
vec
}thin_vec![self.mk_stmt_err(span, guar)], BlockCheckMode::Default, span)
1163 }
1164}