1use std::mem::take;
2use std::ops::{Deref, DerefMut};
3
4use ast::token::IdentIsRaw;
5use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
6use rustc_ast::util::parser::AssocOp;
7use rustc_ast::{
8 self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
9 Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind,
10 MgcaDisambiguation, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind,
11};
12use rustc_ast_pretty::pprust;
13use rustc_data_structures::fx::FxHashSet;
14use rustc_errors::{
15 Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, PResult, Subdiagnostic, Suggestions,
16 inline_fluent, pluralize,
17};
18use rustc_session::errors::ExprParenthesesNeeded;
19use rustc_span::source_map::Spanned;
20use rustc_span::symbol::used_keywords;
21use rustc_span::{BytePos, DUMMY_SP, Ident, Span, SpanSnippetError, Symbol, kw, sym};
22use thin_vec::{ThinVec, thin_vec};
23use tracing::{debug, trace};
24
25use super::pat::Expected;
26use super::{
27 BlockMode, CommaRecoveryMode, ExpTokenPair, Parser, PathStyle, Restrictions, SemiColonMode,
28 SeqSep, TokenType,
29};
30use crate::errors::{
31 AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType,
32 AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
33 ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
34 DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound,
35 ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets,
36 GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition,
37 InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse,
38 MisspelledKw, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg,
39 SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg,
40 SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
41 TernaryOperatorSuggestion, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
42 UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
43};
44use crate::exp;
45use crate::parser::FnContext;
46use crate::parser::attr::InnerAttrPolicy;
47use crate::parser::item::IsDotDotDot;
48
49pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param {
51 let pat = Box::new(Pat {
52 id: ast::DUMMY_NODE_ID,
53 kind: PatKind::Ident(BindingMode::NONE, ident, None),
54 span: ident.span,
55 tokens: None,
56 });
57 let ty = Ty { kind: TyKind::Err(guar), span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None };
58 Param {
59 attrs: AttrVec::default(),
60 id: ast::DUMMY_NODE_ID,
61 pat,
62 span: ident.span,
63 ty: Box::new(ty),
64 is_placeholder: false,
65 }
66}
67
68pub(super) trait RecoverQPath: Sized + 'static {
69 const PATH_STYLE: PathStyle = PathStyle::Expr;
70 fn to_ty(&self) -> Option<Box<Ty>>;
71 fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self;
72}
73
74impl<T: RecoverQPath> RecoverQPath for Box<T> {
75 const PATH_STYLE: PathStyle = T::PATH_STYLE;
76 fn to_ty(&self) -> Option<Box<Ty>> {
77 T::to_ty(self)
78 }
79 fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self {
80 Box::new(T::recovered(qself, path))
81 }
82}
83
84impl RecoverQPath for Ty {
85 const PATH_STYLE: PathStyle = PathStyle::Type;
86 fn to_ty(&self) -> Option<Box<Ty>> {
87 Some(Box::new(self.clone()))
88 }
89 fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self {
90 Self {
91 span: path.span,
92 kind: TyKind::Path(qself, path),
93 id: ast::DUMMY_NODE_ID,
94 tokens: None,
95 }
96 }
97}
98
99impl RecoverQPath for Pat {
100 const PATH_STYLE: PathStyle = PathStyle::Pat;
101 fn to_ty(&self) -> Option<Box<Ty>> {
102 self.to_ty()
103 }
104 fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self {
105 Self {
106 span: path.span,
107 kind: PatKind::Path(qself, path),
108 id: ast::DUMMY_NODE_ID,
109 tokens: None,
110 }
111 }
112}
113
114impl RecoverQPath for Expr {
115 fn to_ty(&self) -> Option<Box<Ty>> {
116 self.to_ty()
117 }
118 fn recovered(qself: Option<Box<QSelf>>, path: ast::Path) -> Self {
119 Self {
120 span: path.span,
121 kind: ExprKind::Path(qself, path),
122 attrs: AttrVec::new(),
123 id: ast::DUMMY_NODE_ID,
124 tokens: None,
125 }
126 }
127}
128
129pub(crate) enum ConsumeClosingDelim {
131 Yes,
132 No,
133}
134
135#[derive(#[automatically_derived]
impl ::core::clone::Clone for AttemptLocalParseRecovery {
#[inline]
fn clone(&self) -> AttemptLocalParseRecovery { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for AttemptLocalParseRecovery { }Copy)]
136pub enum AttemptLocalParseRecovery {
137 Yes,
138 No,
139}
140
141impl AttemptLocalParseRecovery {
142 pub(super) fn yes(&self) -> bool {
143 match self {
144 AttemptLocalParseRecovery::Yes => true,
145 AttemptLocalParseRecovery::No => false,
146 }
147 }
148
149 pub(super) fn no(&self) -> bool {
150 match self {
151 AttemptLocalParseRecovery::Yes => false,
152 AttemptLocalParseRecovery::No => true,
153 }
154 }
155}
156
157#[derive(#[automatically_derived]
impl ::core::fmt::Debug for IncDecRecovery {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"IncDecRecovery", "standalone", &self.standalone, "op", &self.op,
"fixity", &&self.fixity)
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for IncDecRecovery { }Copy, #[automatically_derived]
impl ::core::clone::Clone for IncDecRecovery {
#[inline]
fn clone(&self) -> IncDecRecovery {
let _: ::core::clone::AssertParamIsClone<IsStandalone>;
let _: ::core::clone::AssertParamIsClone<IncOrDec>;
let _: ::core::clone::AssertParamIsClone<UnaryFixity>;
*self
}
}Clone)]
160struct IncDecRecovery {
161 standalone: IsStandalone,
163 op: IncOrDec,
165 fixity: UnaryFixity,
167}
168
169#[derive(#[automatically_derived]
impl ::core::fmt::Debug for IsStandalone {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
IsStandalone::Standalone => "Standalone",
IsStandalone::Subexpr => "Subexpr",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for IsStandalone { }Copy, #[automatically_derived]
impl ::core::clone::Clone for IsStandalone {
#[inline]
fn clone(&self) -> IsStandalone { *self }
}Clone)]
171enum IsStandalone {
172 Standalone,
174 Subexpr,
176}
177
178#[derive(#[automatically_derived]
impl ::core::fmt::Debug for IncOrDec {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self { IncOrDec::Inc => "Inc", IncOrDec::Dec => "Dec", })
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for IncOrDec { }Copy, #[automatically_derived]
impl ::core::clone::Clone for IncOrDec {
#[inline]
fn clone(&self) -> IncOrDec { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for IncOrDec {
#[inline]
fn eq(&self, other: &IncOrDec) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for IncOrDec {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
}Eq)]
179enum IncOrDec {
180 Inc,
181 Dec,
182}
183
184#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UnaryFixity {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
UnaryFixity::Pre => "Pre",
UnaryFixity::Post => "Post",
})
}
}Debug, #[automatically_derived]
impl ::core::marker::Copy for UnaryFixity { }Copy, #[automatically_derived]
impl ::core::clone::Clone for UnaryFixity {
#[inline]
fn clone(&self) -> UnaryFixity { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for UnaryFixity {
#[inline]
fn eq(&self, other: &UnaryFixity) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for UnaryFixity {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {}
}Eq)]
185enum UnaryFixity {
186 Pre,
187 Post,
188}
189
190impl IncOrDec {
191 fn chr(&self) -> char {
192 match self {
193 Self::Inc => '+',
194 Self::Dec => '-',
195 }
196 }
197
198 fn name(&self) -> &'static str {
199 match self {
200 Self::Inc => "increment",
201 Self::Dec => "decrement",
202 }
203 }
204}
205
206impl std::fmt::Display for UnaryFixity {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 match self {
209 Self::Pre => f.write_fmt(format_args!("prefix"))write!(f, "prefix"),
210 Self::Post => f.write_fmt(format_args!("postfix"))write!(f, "postfix"),
211 }
212 }
213}
214
215fn find_similar_kw(lookup: Ident, candidates: &[Symbol]) -> Option<MisspelledKw> {
220 lookup.name.find_similar(candidates).map(|(similar_kw, is_incorrect_case)| MisspelledKw {
221 similar_kw: similar_kw.to_string(),
222 is_incorrect_case,
223 span: lookup.span,
224 })
225}
226
227struct MultiSugg {
228 msg: String,
229 patches: Vec<(Span, String)>,
230 applicability: Applicability,
231}
232
233impl MultiSugg {
234 fn emit(self, err: &mut Diag<'_>) {
235 err.multipart_suggestion(self.msg, self.patches, self.applicability);
236 }
237
238 fn emit_verbose(self, err: &mut Diag<'_>) {
239 err.multipart_suggestion_verbose(self.msg, self.patches, self.applicability);
240 }
241}
242
243pub struct SnapshotParser<'a> {
247 parser: Parser<'a>,
248}
249
250impl<'a> Deref for SnapshotParser<'a> {
251 type Target = Parser<'a>;
252
253 fn deref(&self) -> &Self::Target {
254 &self.parser
255 }
256}
257
258impl<'a> DerefMut for SnapshotParser<'a> {
259 fn deref_mut(&mut self) -> &mut Self::Target {
260 &mut self.parser
261 }
262}
263
264impl<'a> Parser<'a> {
265 pub fn dcx(&self) -> DiagCtxtHandle<'a> {
266 self.psess.dcx()
267 }
268
269 pub fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
271 *self = snapshot.parser;
272 }
273
274 pub fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
276 let snapshot = self.clone();
277 SnapshotParser { parser: snapshot }
278 }
279
280 pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
281 self.psess.source_map().span_to_snippet(span)
282 }
283
284 pub(super) fn expected_ident_found(
288 &mut self,
289 recover: bool,
290 ) -> PResult<'a, (Ident, IdentIsRaw)> {
291 let valid_follow = &[
292 TokenKind::Eq,
293 TokenKind::Colon,
294 TokenKind::Comma,
295 TokenKind::Semi,
296 TokenKind::PathSep,
297 TokenKind::OpenBrace,
298 TokenKind::OpenParen,
299 TokenKind::CloseBrace,
300 TokenKind::CloseParen,
301 ];
302 if let TokenKind::DocComment(..) = self.prev_token.kind
303 && valid_follow.contains(&self.token.kind)
304 {
305 let err = self.dcx().create_err(DocCommentDoesNotDocumentAnything {
306 span: self.prev_token.span,
307 missing_comma: None,
308 });
309 return Err(err);
310 }
311
312 let mut recovered_ident = None;
313 let bad_token = self.token;
316
317 let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident()
319 && ident.is_raw_guess()
320 && self.look_ahead(1, |t| valid_follow.contains(&t.kind))
321 {
322 recovered_ident = Some((ident, IdentIsRaw::Yes));
323
324 let ident_name = ident.name.to_string();
327
328 Some(SuggEscapeIdentifier { span: ident.span.shrink_to_lo(), ident_name })
329 } else {
330 None
331 };
332
333 let suggest_remove_comma =
334 if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) {
335 if recover {
336 self.bump();
337 recovered_ident = self.ident_or_err(false).ok();
338 };
339
340 Some(SuggRemoveComma { span: bad_token.span })
341 } else {
342 None
343 };
344
345 let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| {
346 let (invalid, valid) = self.token.span.split_at(len as u32);
347
348 recovered_ident = Some((Ident::new(valid_portion, valid), IdentIsRaw::No));
349
350 HelpIdentifierStartsWithNumber { num_span: invalid }
351 });
352
353 let err = ExpectedIdentifier {
354 span: bad_token.span,
355 token: bad_token,
356 suggest_raw,
357 suggest_remove_comma,
358 help_cannot_start_number,
359 };
360 let mut err = self.dcx().create_err(err);
361
362 if self.token == token::Lt {
366 let valid_prev_keywords =
368 [kw::Fn, kw::Type, kw::Struct, kw::Enum, kw::Union, kw::Trait];
369
370 let maybe_keyword = self.prev_token;
376 if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) {
377 match self.parse_generics() {
380 Ok(generic) => {
381 if let TokenKind::Ident(symbol, _) = maybe_keyword.kind {
382 let ident_name = symbol;
383 if !self.look_ahead(1, |t| *t == token::Lt)
389 && let Ok(snippet) =
390 self.psess.source_map().span_to_snippet(generic.span)
391 {
392 err.multipart_suggestion_verbose(
393 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("place the generic parameter name after the {0} name",
ident_name))
})format!("place the generic parameter name after the {ident_name} name"),
394 <[_]>::into_vec(::alloc::boxed::box_new([(self.token.span.shrink_to_hi(),
snippet), (generic.span, String::new())]))vec![
395 (self.token.span.shrink_to_hi(), snippet),
396 (generic.span, String::new())
397 ],
398 Applicability::MaybeIncorrect,
399 );
400 } else {
401 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("place the generic parameter name after the {0} name",
ident_name))
})format!(
402 "place the generic parameter name after the {ident_name} name"
403 ));
404 }
405 }
406 }
407 Err(err) => {
408 err.cancel();
412 }
413 }
414 }
415 }
416
417 if let Some(recovered_ident) = recovered_ident
418 && recover
419 {
420 err.emit();
421 Ok(recovered_ident)
422 } else {
423 Err(err)
424 }
425 }
426
427 pub(super) fn expected_ident_found_err(&mut self) -> Diag<'a> {
428 self.expected_ident_found(false).unwrap_err()
429 }
430
431 pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> {
437 if let token::Literal(Lit {
441 kind: token::LitKind::Integer | token::LitKind::Float,
442 symbol,
443 suffix: Some(suffix), }) = self.token.kind
445 && rustc_ast::MetaItemLit::from_token(&self.token).is_none()
446 {
447 Some((symbol.as_str().len(), suffix))
448 } else {
449 None
450 }
451 }
452
453 pub(super) fn expected_one_of_not_found(
454 &mut self,
455 edible: &[ExpTokenPair],
456 inedible: &[ExpTokenPair],
457 ) -> PResult<'a, ErrorGuaranteed> {
458 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:458",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(458u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("expected_one_of_not_found(edible: {0:?}, inedible: {1:?})",
edible, inedible) as &dyn Value))])
});
} else { ; }
};debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
459 fn tokens_to_string(tokens: &[TokenType]) -> String {
460 let mut i = tokens.iter();
461 let b = i.next().map_or_else(String::new, |t| t.to_string());
463 i.enumerate().fold(b, |mut b, (i, a)| {
464 if tokens.len() > 2 && i == tokens.len() - 2 {
465 b.push_str(", or ");
466 } else if tokens.len() == 2 && i == tokens.len() - 2 {
467 b.push_str(" or ");
468 } else {
469 b.push_str(", ");
470 }
471 b.push_str(&a.to_string());
472 b
473 })
474 }
475
476 for exp in edible.iter().chain(inedible.iter()) {
477 self.expected_token_types.insert(exp.token_type);
478 }
479 let mut expected: Vec<_> = self.expected_token_types.iter().collect();
480 expected.sort_by_cached_key(|x| x.to_string());
481 expected.dedup();
482
483 let sm = self.psess.source_map();
484
485 if expected.contains(&TokenType::Semi) {
487 if self.prev_token == token::Question
490 && let Err(e) = self.maybe_recover_from_ternary_operator(None)
491 {
492 return Err(e);
493 }
494
495 if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
496 } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
498 } else if [token::Comma, token::Colon].contains(&self.token.kind)
500 && self.prev_token == token::CloseParen
501 {
502 } else if self.look_ahead(1, |t| {
511 t == &token::CloseBrace || t.can_begin_expr() && *t != token::Colon
512 }) && [token::Comma, token::Colon].contains(&self.token.kind)
513 {
514 let guar = self.dcx().emit_err(ExpectedSemi {
521 span: self.token.span,
522 token: self.token,
523 unexpected_token_label: None,
524 sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
525 });
526 self.bump();
527 return Ok(guar);
528 } else if self.look_ahead(0, |t| {
529 t == &token::CloseBrace
530 || ((t.can_begin_expr() || t.can_begin_item())
531 && t != &token::Semi
532 && t != &token::Pound)
533 || (sm.is_multiline(
535 self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
536 ) && t == &token::Pound)
537 }) && !expected.contains(&TokenType::Comma)
538 {
539 let span = self.prev_token.span.shrink_to_hi();
545 let guar = self.dcx().emit_err(ExpectedSemi {
546 span,
547 token: self.token,
548 unexpected_token_label: Some(self.token.span),
549 sugg: ExpectedSemiSugg::AddSemi(span),
550 });
551 return Ok(guar);
552 }
553 }
554
555 if self.token == TokenKind::EqEq
556 && self.prev_token.is_ident()
557 && expected.contains(&TokenType::Eq)
558 {
559 return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
561 }
562
563 if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use))
564 && self.prev_token.is_keyword(kw::Async)
565 {
566 let span = self.prev_token.span.to(self.token.span);
568 if self.token.is_keyword(kw::Move) {
569 return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
570 } else {
571 return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span }));
573 }
574 }
575
576 let expect = tokens_to_string(&expected);
577 let actual = super::token_descr(&self.token);
578 let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
579 let fmt = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected one of {0}, found {1}",
expect, actual))
})format!("expected one of {expect}, found {actual}");
580 let short_expect = if expected.len() > 6 {
581 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} possible tokens",
expected.len()))
})format!("{} possible tokens", expected.len())
582 } else {
583 expect
584 };
585 (fmt, (self.prev_token.span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected one of {0}",
short_expect))
})format!("expected one of {short_expect}")))
586 } else if expected.is_empty() {
587 (
588 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unexpected token: {0}", actual))
})format!("unexpected token: {actual}"),
589 (self.prev_token.span, "unexpected token after this".to_string()),
590 )
591 } else {
592 (
593 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected {0}, found {1}", expect,
actual))
})format!("expected {expect}, found {actual}"),
594 (self.prev_token.span.shrink_to_hi(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected {0}", expect))
})format!("expected {expect}")),
595 )
596 };
597 self.last_unexpected_token_span = Some(self.token.span);
598 let mut err = self.dcx().struct_span_err(self.token.span, msg_exp);
600
601 self.label_expected_raw_ref(&mut err);
602
603 if self.token == token::FatArrow
605 && expected.iter().any(|tok| #[allow(non_exhaustive_omitted_patterns)] match tok {
TokenType::Operator | TokenType::Le => true,
_ => false,
}matches!(tok, TokenType::Operator | TokenType::Le))
606 && !expected.iter().any(|tok| #[allow(non_exhaustive_omitted_patterns)] match tok {
TokenType::FatArrow | TokenType::Comma => true,
_ => false,
}matches!(tok, TokenType::FatArrow | TokenType::Comma))
607 {
608 err.span_suggestion(
609 self.token.span,
610 "you might have meant to write a \"greater than or equal to\" comparison",
611 ">=",
612 Applicability::MaybeIncorrect,
613 );
614 }
615
616 if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
617 if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
618 err.span_suggestion_short(
619 self.prev_token.span,
620 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("write `fn` instead of `{0}` to declare a function",
symbol))
})format!("write `fn` instead of `{symbol}` to declare a function"),
621 "fn",
622 Applicability::MachineApplicable,
623 );
624 }
625 }
626
627 if let TokenKind::Ident(prev, _) = &self.prev_token.kind
628 && let TokenKind::Ident(cur, _) = &self.token.kind
629 {
630 let concat = Symbol::intern(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}{1}", prev, cur))
})format!("{prev}{cur}"));
631 let ident = Ident::new(concat, DUMMY_SP);
632 if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() {
633 let concat_span = self.prev_token.span.to(self.token.span);
634 err.span_suggestion_verbose(
635 concat_span,
636 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("consider removing the space to spell keyword `{0}`",
concat))
})format!("consider removing the space to spell keyword `{concat}`"),
637 concat,
638 Applicability::MachineApplicable,
639 );
640 }
641 }
642
643 if ((self.prev_token == TokenKind::Ident(sym::c, IdentIsRaw::No)
651 && #[allow(non_exhaustive_omitted_patterns)] match &self.token.kind {
TokenKind::Literal(token::Lit { kind: token::Str, .. }) => true,
_ => false,
}matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
652 || (self.prev_token == TokenKind::Ident(sym::cr, IdentIsRaw::No)
653 && #[allow(non_exhaustive_omitted_patterns)] match &self.token.kind {
TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound =>
true,
_ => false,
}matches!(
654 &self.token.kind,
655 TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
656 )))
657 && self.prev_token.span.hi() == self.token.span.lo()
658 && !self.token.span.at_least_rust_2021()
659 {
660 err.note("you may be trying to write a c-string literal");
661 err.note("c-string literals require Rust 2021 or later");
662 err.subdiagnostic(HelpUseLatestEdition::new());
663 }
664
665 if self.prev_token.is_ident_named(sym::public)
667 && (self.token.can_begin_item() || self.token == TokenKind::OpenParen)
668 {
669 err.span_suggestion_short(
670 self.prev_token.span,
671 "write `pub` instead of `public` to make the item public",
672 "pub",
673 Applicability::MachineApplicable,
674 );
675 }
676
677 if let token::DocComment(kind, style, _) = self.token.kind {
678 if !expected.contains(&TokenType::Comma) {
688 let pos = self.token.span.lo() + BytePos(2);
690 let span = self.token.span.with_lo(pos).with_hi(pos);
691 err.span_suggestion_verbose(
692 span,
693 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("add a space before {0} to write a regular comment",
match (kind, style) {
(token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`",
(token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`",
(token::CommentKind::Line, ast::AttrStyle::Outer) =>
"the last `/`",
(token::CommentKind::Block, ast::AttrStyle::Outer) =>
"the last `*`",
}))
})format!(
694 "add a space before {} to write a regular comment",
695 match (kind, style) {
696 (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`",
697 (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`",
698 (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`",
699 (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`",
700 },
701 ),
702 " ".to_string(),
703 Applicability::MaybeIncorrect,
704 );
705 }
706 }
707
708 let sp = if self.token == token::Eof {
709 self.prev_token.span
711 } else {
712 label_sp
713 };
714
715 if self.check_too_many_raw_str_terminators(&mut err) {
716 if expected.contains(&TokenType::Semi) && self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) {
717 let guar = err.emit();
718 return Ok(guar);
719 } else {
720 return Err(err);
721 }
722 }
723
724 if self.prev_token.span == DUMMY_SP {
725 err.span_label(self.token.span, label_exp);
728 } else if !sm.is_multiline(self.token.span.shrink_to_hi().until(sp.shrink_to_lo())) {
729 err.span_label(self.token.span, label_exp);
742 } else {
743 err.span_label(sp, label_exp);
744 err.span_label(self.token.span, "unexpected token");
745 }
746
747 if let Suggestions::Enabled(list) = &err.suggestions
749 && list.is_empty()
750 {
751 self.check_for_misspelled_kw(&mut err, &expected);
752 }
753 Err(err)
754 }
755
756 pub(super) fn label_expected_raw_ref(&mut self, err: &mut Diag<'_>) {
761 if self.prev_token.is_keyword(kw::Raw)
762 && self.expected_token_types.contains(TokenType::KwMut)
763 && self.expected_token_types.contains(TokenType::KwConst)
764 && self.token.can_begin_expr()
765 {
766 err.span_suggestions(
767 self.prev_token.span.shrink_to_hi(),
768 "`&raw` must be followed by `const` or `mut` to be a raw reference expression",
769 [" const".to_string(), " mut".to_string()],
770 Applicability::MaybeIncorrect,
771 );
772 }
773 }
774
775 fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) {
778 let Some((curr_ident, _)) = self.token.ident() else {
779 return;
780 };
781 let expected_token_types: &[TokenType] =
782 expected.len().checked_sub(10).map_or(&expected, |index| &expected[index..]);
783 let expected_keywords: Vec<Symbol> =
784 expected_token_types.iter().filter_map(|token| token.is_keyword()).collect();
785
786 if !expected_keywords.is_empty()
791 && !curr_ident.is_used_keyword()
792 && let Some(misspelled_kw) = find_similar_kw(curr_ident, &expected_keywords)
793 {
794 err.subdiagnostic(misspelled_kw);
795 err.seal_suggestions();
798 } else if let Some((prev_ident, _)) = self.prev_token.ident()
799 && !prev_ident.is_used_keyword()
800 {
801 let all_keywords = used_keywords(|| prev_ident.span.edition());
806
807 if let Some(misspelled_kw) = find_similar_kw(prev_ident, &all_keywords) {
812 err.subdiagnostic(misspelled_kw);
813 err.seal_suggestions();
816 }
817 }
818 }
819
820 pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed {
822 let span = self.prev_token.span.shrink_to_hi();
824 let mut err = self.dcx().create_err(ExpectedSemi {
825 span,
826 token: self.token,
827 unexpected_token_label: Some(self.token.span),
828 sugg: ExpectedSemiSugg::AddSemi(span),
829 });
830 let attr_span = match &expr.attrs[..] {
831 [] => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
832 [only] => only.span,
833 [first, rest @ ..] => {
834 for attr in rest {
835 err.span_label(attr.span, "");
836 }
837 first.span
838 }
839 };
840 err.span_label(
841 attr_span,
842 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("only `;` terminated statements or tail expressions are allowed after {0}",
if expr.attrs.len() == 1 {
"this attribute"
} else { "these attributes" }))
})format!(
843 "only `;` terminated statements or tail expressions are allowed after {}",
844 if expr.attrs.len() == 1 { "this attribute" } else { "these attributes" },
845 ),
846 );
847 if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
848 err.span_label(span, "expected `;` here");
854 err.multipart_suggestion(
855 "alternatively, consider surrounding the expression with a block",
856 <[_]>::into_vec(::alloc::boxed::box_new([(expr.span.shrink_to_lo(),
"{ ".to_string()),
(expr.span.shrink_to_hi(), " }".to_string())]))vec![
857 (expr.span.shrink_to_lo(), "{ ".to_string()),
858 (expr.span.shrink_to_hi(), " }".to_string()),
859 ],
860 Applicability::MachineApplicable,
861 );
862
863 let mut snapshot = self.create_snapshot_for_diagnostic();
865 if let [attr] = &expr.attrs[..]
866 && let ast::AttrKind::Normal(attr_kind) = &attr.kind
867 && let [segment] = &attr_kind.item.path.segments[..]
868 && segment.ident.name == sym::cfg
869 && let Some(args_span) = attr_kind.item.args.span()
870 && let next_attr = match snapshot.parse_attribute(InnerAttrPolicy::Forbidden(None))
871 {
872 Ok(next_attr) => next_attr,
873 Err(inner_err) => {
874 inner_err.cancel();
875 return err.emit();
876 }
877 }
878 && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind
879 && let Some(next_attr_args_span) = next_attr_kind.item.args.span()
880 && let [next_segment] = &next_attr_kind.item.path.segments[..]
881 && segment.ident.name == sym::cfg
882 {
883 let next_expr = match snapshot.parse_expr() {
884 Ok(next_expr) => next_expr,
885 Err(inner_err) => {
886 inner_err.cancel();
887 return err.emit();
888 }
889 };
890 let margin = self.psess.source_map().span_to_margin(next_expr.span).unwrap_or(0);
897 let sugg = <[_]>::into_vec(::alloc::boxed::box_new([(attr.span.with_hi(segment.span().hi()),
"if cfg!".to_string()),
(args_span.shrink_to_hi().with_hi(attr.span.hi()),
" {".to_string()),
(expr.span.shrink_to_lo(), " ".to_string()),
(next_attr.span.with_hi(next_segment.span().hi()),
"} else if cfg!".to_string()),
(next_attr_args_span.shrink_to_hi().with_hi(next_attr.span.hi()),
" {".to_string()),
(next_expr.span.shrink_to_lo(), " ".to_string()),
(next_expr.span.shrink_to_hi(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("\n{0}}}",
" ".repeat(margin)))
}))]))vec![
898 (attr.span.with_hi(segment.span().hi()), "if cfg!".to_string()),
899 (args_span.shrink_to_hi().with_hi(attr.span.hi()), " {".to_string()),
900 (expr.span.shrink_to_lo(), " ".to_string()),
901 (
902 next_attr.span.with_hi(next_segment.span().hi()),
903 "} else if cfg!".to_string(),
904 ),
905 (
906 next_attr_args_span.shrink_to_hi().with_hi(next_attr.span.hi()),
907 " {".to_string(),
908 ),
909 (next_expr.span.shrink_to_lo(), " ".to_string()),
910 (next_expr.span.shrink_to_hi(), format!("\n{}}}", " ".repeat(margin))),
911 ];
912 err.multipart_suggestion(
913 "it seems like you are trying to provide different expressions depending on \
914 `cfg`, consider using `if cfg!(..)`",
915 sugg,
916 Applicability::MachineApplicable,
917 );
918 }
919 }
920
921 err.emit()
922 }
923
924 fn check_too_many_raw_str_terminators(&mut self, err: &mut Diag<'_>) -> bool {
925 let sm = self.psess.source_map();
926 match (&self.prev_token.kind, &self.token.kind) {
927 (
928 TokenKind::Literal(Lit {
929 kind: LitKind::StrRaw(n_hashes) | LitKind::ByteStrRaw(n_hashes),
930 ..
931 }),
932 TokenKind::Pound,
933 ) if !sm.is_multiline(
934 self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()),
935 ) =>
936 {
937 let n_hashes: u8 = *n_hashes;
938 err.primary_message("too many `#` when terminating raw string");
939 let str_span = self.prev_token.span;
940 let mut span = self.token.span;
941 let mut count = 0;
942 while self.token == TokenKind::Pound
943 && !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo()))
944 {
945 span = span.with_hi(self.token.span.hi());
946 self.bump();
947 count += 1;
948 }
949 err.span(span);
950 err.span_suggestion(
951 span,
952 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("remove the extra `#`{0}",
if count == 1 { "" } else { "s" }))
})format!("remove the extra `#`{}", pluralize!(count)),
953 "",
954 Applicability::MachineApplicable,
955 );
956 err.span_label(
957 str_span,
958 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this raw string started with {1} `#`{0}",
if n_hashes == 1 { "" } else { "s" }, n_hashes))
})format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
959 );
960 true
961 }
962 _ => false,
963 }
964 }
965
966 pub(super) fn maybe_suggest_struct_literal(
967 &mut self,
968 lo: Span,
969 s: BlockCheckMode,
970 maybe_struct_name: token::Token,
971 ) -> Option<PResult<'a, Box<Block>>> {
972 if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) {
973 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:977",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(977u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["maybe_struct_name",
"self.token"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&maybe_struct_name)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&self.token)
as &dyn Value))])
});
} else { ; }
};debug!(?maybe_struct_name, ?self.token);
978 let mut snapshot = self.create_snapshot_for_diagnostic();
979 let path = Path {
980 segments: ThinVec::new(),
981 span: self.prev_token.span.shrink_to_lo(),
982 tokens: None,
983 };
984 let struct_expr = snapshot.parse_expr_struct(None, path, false);
985 let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
986 return Some(match (struct_expr, block_tail) {
987 (Ok(expr), Err(err)) => {
988 err.cancel();
997 self.restore_snapshot(snapshot);
998 let guar = self.dcx().emit_err(StructLiteralBodyWithoutPath {
999 span: expr.span,
1000 sugg: StructLiteralBodyWithoutPathSugg {
1001 before: expr.span.shrink_to_lo(),
1002 after: expr.span.shrink_to_hi(),
1003 },
1004 });
1005 Ok(self.mk_block(
1006 {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(self.mk_stmt_err(expr.span, guar));
vec
}thin_vec![self.mk_stmt_err(expr.span, guar)],
1007 s,
1008 lo.to(self.prev_token.span),
1009 ))
1010 }
1011 (Err(err), Ok(tail)) => {
1012 err.cancel();
1014 Ok(tail)
1015 }
1016 (Err(snapshot_err), Err(err)) => {
1017 snapshot_err.cancel();
1019 self.consume_block(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenBrace,
token_type: crate::parser::token_type::TokenType::OpenBrace,
}exp!(OpenBrace), crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace), ConsumeClosingDelim::Yes);
1020 Err(err)
1021 }
1022 (Ok(_), Ok(tail)) => Ok(tail),
1023 });
1024 }
1025 None
1026 }
1027
1028 pub(super) fn recover_closure_body(
1029 &mut self,
1030 mut err: Diag<'a>,
1031 before: token::Token,
1032 prev: token::Token,
1033 token: token::Token,
1034 lo: Span,
1035 decl_hi: Span,
1036 ) -> PResult<'a, Box<Expr>> {
1037 err.span_label(lo.to(decl_hi), "while parsing the body of this closure");
1038 let guar = match before.kind {
1039 token::OpenBrace if token.kind != token::OpenBrace => {
1040 err.multipart_suggestion(
1042 "you might have meant to open the body of the closure, instead of enclosing \
1043 the closure in a block",
1044 <[_]>::into_vec(::alloc::boxed::box_new([(before.span, String::new()),
(prev.span.shrink_to_hi(), " {".to_string())]))vec![
1045 (before.span, String::new()),
1046 (prev.span.shrink_to_hi(), " {".to_string()),
1047 ],
1048 Applicability::MaybeIncorrect,
1049 );
1050 let guar = err.emit();
1051 self.eat_to_tokens(&[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseBrace,
token_type: crate::parser::token_type::TokenType::CloseBrace,
}exp!(CloseBrace)]);
1052 guar
1053 }
1054 token::OpenParen if token.kind != token::OpenBrace => {
1055 self.eat_to_tokens(&[crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen), crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)]);
1058
1059 err.multipart_suggestion_verbose(
1060 "you might have meant to open the body of the closure",
1061 <[_]>::into_vec(::alloc::boxed::box_new([(prev.span.shrink_to_hi(),
" {".to_string()),
(self.token.span.shrink_to_lo(), "}".to_string())]))vec![
1062 (prev.span.shrink_to_hi(), " {".to_string()),
1063 (self.token.span.shrink_to_lo(), "}".to_string()),
1064 ],
1065 Applicability::MaybeIncorrect,
1066 );
1067 err.emit()
1068 }
1069 _ if token.kind != token::OpenBrace => {
1070 err.multipart_suggestion_verbose(
1073 "you might have meant to open the body of the closure",
1074 <[_]>::into_vec(::alloc::boxed::box_new([(prev.span.shrink_to_hi(),
" {".to_string())]))vec![(prev.span.shrink_to_hi(), " {".to_string())],
1075 Applicability::HasPlaceholders,
1076 );
1077 return Err(err);
1078 }
1079 _ => return Err(err),
1080 };
1081 Ok(self.mk_expr_err(lo.to(self.token.span), guar))
1082 }
1083
1084 pub(super) fn eat_to_tokens(&mut self, closes: &[ExpTokenPair]) {
1087 if let Err(err) = self
1088 .parse_seq_to_before_tokens(closes, &[], SeqSep::none(), |p| Ok(p.parse_token_tree()))
1089 {
1090 err.cancel();
1091 }
1092 }
1093
1094 pub(super) fn check_trailing_angle_brackets(
1105 &mut self,
1106 segment: &PathSegment,
1107 end: &[ExpTokenPair],
1108 ) -> Option<ErrorGuaranteed> {
1109 if !self.may_recover() {
1110 return None;
1111 }
1112
1113 let parsed_angle_bracket_args =
1138 segment.args.as_ref().is_some_and(|args| args.is_angle_bracketed());
1139
1140 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:1140",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(1140u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("check_trailing_angle_brackets: parsed_angle_bracket_args={0:?}",
parsed_angle_bracket_args) as &dyn Value))])
});
} else { ; }
};debug!(
1141 "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
1142 parsed_angle_bracket_args,
1143 );
1144 if !parsed_angle_bracket_args {
1145 return None;
1146 }
1147
1148 let lo = self.token.span;
1151
1152 let mut position = 0;
1156
1157 let mut number_of_shr = 0;
1161 let mut number_of_gt = 0;
1162 while self.look_ahead(position, |t| {
1163 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:1163",
"rustc_parse::parser::diagnostics", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(1163u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("check_trailing_angle_brackets: t={0:?}",
t) as &dyn Value))])
});
} else { ; }
};trace!("check_trailing_angle_brackets: t={:?}", t);
1164 if *t == token::Shr {
1165 number_of_shr += 1;
1166 true
1167 } else if *t == token::Gt {
1168 number_of_gt += 1;
1169 true
1170 } else {
1171 false
1172 }
1173 }) {
1174 position += 1;
1175 }
1176
1177 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:1178",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(1178u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("check_trailing_angle_brackets: number_of_gt={0:?} number_of_shr={1:?}",
number_of_gt, number_of_shr) as &dyn Value))])
});
} else { ; }
};debug!(
1179 "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}",
1180 number_of_gt, number_of_shr,
1181 );
1182 if number_of_gt < 1 && number_of_shr < 1 {
1183 return None;
1184 }
1185
1186 if self.look_ahead(position, |t| {
1189 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:1189",
"rustc_parse::parser::diagnostics", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(1189u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("check_trailing_angle_brackets: t={0:?}",
t) as &dyn Value))])
});
} else { ; }
};trace!("check_trailing_angle_brackets: t={:?}", t);
1190 end.iter().any(|exp| exp.tok == t.kind)
1191 }) {
1192 self.eat_to_tokens(end);
1195 let span = lo.to(self.prev_token.span);
1196
1197 let num_extra_brackets = number_of_gt + number_of_shr * 2;
1198 return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets }));
1199 }
1200 None
1201 }
1202
1203 pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
1206 if !self.may_recover() {
1207 return;
1208 }
1209
1210 if self.token == token::PathSep && segment.args.is_none() {
1211 let snapshot = self.create_snapshot_for_diagnostic();
1212 self.bump();
1213 let lo = self.token.span;
1214 match self.parse_angle_args(None) {
1215 Ok(args) => {
1216 let span = lo.to(self.prev_token.span);
1217 let mut trailing_span = self.prev_token.span.shrink_to_hi();
1219 while self.token == token::Shr || self.token == token::Gt {
1220 trailing_span = trailing_span.to(self.token.span);
1221 self.bump();
1222 }
1223 if self.token == token::OpenParen {
1224 segment.args = Some(AngleBracketedArgs { args, span }.into());
1226
1227 self.dcx().emit_err(GenericParamsWithoutAngleBrackets {
1228 span,
1229 sugg: GenericParamsWithoutAngleBracketsSugg {
1230 left: span.shrink_to_lo(),
1231 right: trailing_span,
1232 },
1233 });
1234 } else {
1235 self.restore_snapshot(snapshot);
1237 }
1238 }
1239 Err(err) => {
1240 err.cancel();
1243 self.restore_snapshot(snapshot);
1244 }
1245 }
1246 }
1247 }
1248
1249 pub(super) fn check_mistyped_turbofish_with_multiple_type_params(
1252 &mut self,
1253 mut e: Diag<'a>,
1254 expr: &mut Box<Expr>,
1255 ) -> PResult<'a, ErrorGuaranteed> {
1256 if let ExprKind::Binary(binop, _, _) = &expr.kind
1257 && let ast::BinOpKind::Lt = binop.node
1258 && self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma))
1259 {
1260 let x = self.parse_seq_to_before_end(
1261 crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Gt,
token_type: crate::parser::token_type::TokenType::Gt,
}exp!(Gt),
1262 SeqSep::trailing_allowed(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)),
1263 |p| match p.parse_generic_arg(None)? {
1264 Some(arg) => Ok(arg),
1265 None => p.unexpected_any(),
1267 },
1268 );
1269 match x {
1270 Ok((_, _, Recovered::No)) => {
1271 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Gt,
token_type: crate::parser::token_type::TokenType::Gt,
}exp!(Gt)) {
1272 e.span_suggestion_verbose(
1274 binop.span.shrink_to_lo(),
1275 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments"))inline_fluent!("use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments"),
1276 "::",
1277 Applicability::MaybeIncorrect,
1278 );
1279 match self.parse_expr() {
1280 Ok(_) => {
1281 let guar = e.emit();
1285 *expr = self.mk_expr_err(expr.span.to(self.prev_token.span), guar);
1286 return Ok(guar);
1287 }
1288 Err(err) => {
1289 err.cancel();
1290 }
1291 }
1292 }
1293 }
1294 Ok((_, _, Recovered::Yes(_))) => {}
1295 Err(err) => {
1296 err.cancel();
1297 }
1298 }
1299 }
1300 Err(e)
1301 }
1302
1303 pub(super) fn suggest_add_missing_let_for_stmt(&mut self, err: &mut Diag<'a>) {
1306 if self.token == token::Colon {
1307 let prev_span = self.prev_token.span.shrink_to_lo();
1308 let snapshot = self.create_snapshot_for_diagnostic();
1309 self.bump();
1310 match self.parse_ty() {
1311 Ok(_) => {
1312 if self.token == token::Eq {
1313 let sugg = SuggAddMissingLetStmt { span: prev_span };
1314 sugg.add_to_diag(err);
1315 }
1316 }
1317 Err(e) => {
1318 e.cancel();
1319 }
1320 }
1321 self.restore_snapshot(snapshot);
1322 }
1323 }
1324
1325 fn attempt_chained_comparison_suggestion(
1329 &mut self,
1330 err: &mut ComparisonOperatorsCannotBeChained,
1331 inner_op: &Expr,
1332 outer_op: &Spanned<AssocOp>,
1333 ) -> bool {
1334 if let ExprKind::Binary(op, l1, r1) = &inner_op.kind {
1335 if let ExprKind::Field(_, ident) = l1.kind
1336 && !ident.is_numeric()
1337 && !#[allow(non_exhaustive_omitted_patterns)] match r1.kind {
ExprKind::Lit(_) => true,
_ => false,
}matches!(r1.kind, ExprKind::Lit(_))
1338 {
1339 return false;
1342 }
1343 return match (op.node, &outer_op.node) {
1344 (BinOpKind::Eq, AssocOp::Binary(BinOpKind::Eq)) |
1346 (BinOpKind::Lt, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
1348 (BinOpKind::Le, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) |
1349 (BinOpKind::Gt, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) |
1351 (BinOpKind::Ge, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) => {
1352 let expr_to_str = |e: &Expr| {
1353 self.span_to_snippet(e.span)
1354 .unwrap_or_else(|_| pprust::expr_to_string(e))
1355 };
1356 err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::SplitComparison {
1357 span: inner_op.span.shrink_to_hi(),
1358 middle_term: expr_to_str(r1),
1359 });
1360 false }
1362 (
1364 BinOpKind::Eq,
1365 AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge)
1366 ) => {
1367 let snapshot = self.create_snapshot_for_diagnostic();
1369 match self.parse_expr() {
1370 Ok(r2) => {
1371 err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
1374 left: r1.span.shrink_to_lo(),
1375 right: r2.span.shrink_to_hi(),
1376 });
1377 true
1378 }
1379 Err(expr_err) => {
1380 expr_err.cancel();
1381 self.restore_snapshot(snapshot);
1382 true
1383 }
1384 }
1385 }
1386 (
1388 BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge,
1389 AssocOp::Binary(BinOpKind::Eq)
1390 ) => {
1391 let snapshot = self.create_snapshot_for_diagnostic();
1392 match self.parse_expr() {
1395 Ok(_) => {
1396 err.chaining_sugg = Some(ComparisonOperatorsCannotBeChainedSugg::Parenthesize {
1397 left: l1.span.shrink_to_lo(),
1398 right: r1.span.shrink_to_hi(),
1399 });
1400 true
1401 }
1402 Err(expr_err) => {
1403 expr_err.cancel();
1404 self.restore_snapshot(snapshot);
1405 false
1406 }
1407 }
1408 }
1409 _ => false
1410 };
1411 }
1412 false
1413 }
1414
1415 pub(super) fn check_no_chained_comparison(
1434 &mut self,
1435 inner_op: &Expr,
1436 outer_op: &Spanned<AssocOp>,
1437 ) -> PResult<'a, Option<Box<Expr>>> {
1438 if true {
if !outer_op.node.is_comparison() {
{
::core::panicking::panic_fmt(format_args!("check_no_chained_comparison: {0:?} is not comparison",
outer_op.node));
}
};
};debug_assert!(
1439 outer_op.node.is_comparison(),
1440 "check_no_chained_comparison: {:?} is not comparison",
1441 outer_op.node,
1442 );
1443
1444 let mk_err_expr =
1445 |this: &Self, span, guar| Ok(Some(this.mk_expr(span, ExprKind::Err(guar))));
1446
1447 match &inner_op.kind {
1448 ExprKind::Binary(op, l1, r1) if op.node.is_comparison() => {
1449 let mut err = ComparisonOperatorsCannotBeChained {
1450 span: <[_]>::into_vec(::alloc::boxed::box_new([op.span, self.prev_token.span]))vec![op.span, self.prev_token.span],
1451 suggest_turbofish: None,
1452 help_turbofish: false,
1453 chaining_sugg: None,
1454 };
1455
1456 if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Binary(BinOpKind::Lt)
1459 || outer_op.node == AssocOp::Binary(BinOpKind::Gt)
1460 {
1461 if outer_op.node == AssocOp::Binary(BinOpKind::Lt) {
1462 let snapshot = self.create_snapshot_for_diagnostic();
1463 self.bump();
1464 let modifiers = [(token::Lt, 1), (token::Gt, -1), (token::Shr, -2)];
1466 self.consume_tts(1, &modifiers);
1467
1468 if !#[allow(non_exhaustive_omitted_patterns)] match self.token.kind {
token::OpenParen | token::PathSep => true,
_ => false,
}matches!(self.token.kind, token::OpenParen | token::PathSep) {
1469 self.restore_snapshot(snapshot);
1472 }
1473 }
1474 return if self.token == token::PathSep {
1475 if let ExprKind::Binary(o, ..) = inner_op.kind
1478 && o.node == BinOpKind::Lt
1479 {
1480 err.suggest_turbofish = Some(op.span.shrink_to_lo());
1481 } else {
1482 err.help_turbofish = true;
1483 }
1484
1485 let snapshot = self.create_snapshot_for_diagnostic();
1486 self.bump(); match self.parse_expr() {
1490 Ok(_) => {
1491 let guar = self.dcx().emit_err(err);
1493 mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1497 }
1498 Err(expr_err) => {
1499 expr_err.cancel();
1500 self.restore_snapshot(snapshot);
1503 Err(self.dcx().create_err(err))
1504 }
1505 }
1506 } else if self.token == token::OpenParen {
1507 if let ExprKind::Binary(o, ..) = inner_op.kind
1510 && o.node == BinOpKind::Lt
1511 {
1512 err.suggest_turbofish = Some(op.span.shrink_to_lo());
1513 } else {
1514 err.help_turbofish = true;
1515 }
1516 match self.consume_fn_args() {
1518 Err(()) => Err(self.dcx().create_err(err)),
1519 Ok(()) => {
1520 let guar = self.dcx().emit_err(err);
1521 mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1525 }
1526 }
1527 } else {
1528 if !#[allow(non_exhaustive_omitted_patterns)] match l1.kind {
ExprKind::Lit(_) => true,
_ => false,
}matches!(l1.kind, ExprKind::Lit(_))
1529 && !#[allow(non_exhaustive_omitted_patterns)] match r1.kind {
ExprKind::Lit(_) => true,
_ => false,
}matches!(r1.kind, ExprKind::Lit(_))
1530 {
1531 err.help_turbofish = true;
1534 }
1535
1536 let recovered = self
1539 .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
1540 if recovered {
1541 let guar = self.dcx().emit_err(err);
1542 mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
1543 } else {
1544 Err(self.dcx().create_err(err))
1546 }
1547 };
1548 }
1549 let recovered =
1550 self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
1551 let guar = self.dcx().emit_err(err);
1552 if recovered {
1553 return mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar);
1554 }
1555 }
1556 _ => {}
1557 }
1558 Ok(None)
1559 }
1560
1561 fn consume_fn_args(&mut self) -> Result<(), ()> {
1562 let snapshot = self.create_snapshot_for_diagnostic();
1563 self.bump(); let modifiers = [(token::OpenParen, 1), (token::CloseParen, -1)];
1567 self.consume_tts(1, &modifiers);
1568
1569 if self.token == token::Eof {
1570 self.restore_snapshot(snapshot);
1572 Err(())
1573 } else {
1574 Ok(())
1576 }
1577 }
1578
1579 pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
1580 if impl_dyn_multi {
1581 self.dcx().emit_err(AmbiguousPlus {
1582 span: ty.span,
1583 suggestion: AddParen { lo: ty.span.shrink_to_lo(), hi: ty.span.shrink_to_hi() },
1584 });
1585 }
1586 }
1587
1588 pub(super) fn maybe_recover_from_question_mark(&mut self, ty: Box<Ty>) -> Box<Ty> {
1590 if self.token == token::Question {
1591 self.bump();
1592 let guar = self.dcx().emit_err(QuestionMarkInType {
1593 span: self.prev_token.span,
1594 sugg: QuestionMarkInTypeSugg {
1595 left: ty.span.shrink_to_lo(),
1596 right: self.prev_token.span,
1597 },
1598 });
1599 self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err(guar))
1600 } else {
1601 ty
1602 }
1603 }
1604
1605 pub(super) fn maybe_recover_from_ternary_operator(
1611 &mut self,
1612 cond: Option<Span>,
1613 ) -> PResult<'a, ()> {
1614 if self.prev_token != token::Question {
1615 return PResult::Ok(());
1616 }
1617
1618 let question = self.prev_token.span;
1619 let lo = cond.unwrap_or(question).lo();
1620 let snapshot = self.create_snapshot_for_diagnostic();
1621
1622 if match self.parse_expr() {
1623 Ok(_) => true,
1624 Err(err) => {
1625 err.cancel();
1626 self.token == token::Colon
1629 }
1630 } {
1631 if self.eat_noexpect(&token::Colon) {
1632 let colon = self.prev_token.span;
1633 match self.parse_expr() {
1634 Ok(expr) => {
1635 let sugg = cond.map(|cond| TernaryOperatorSuggestion {
1636 before_cond: cond.shrink_to_lo(),
1637 question,
1638 colon,
1639 end: expr.span.shrink_to_hi(),
1640 });
1641 return Err(self.dcx().create_err(TernaryOperator {
1642 span: self.prev_token.span.with_lo(lo),
1643 sugg,
1644 no_sugg: sugg.is_none(),
1645 }));
1646 }
1647 Err(err) => {
1648 err.cancel();
1649 }
1650 };
1651 }
1652 }
1653 self.restore_snapshot(snapshot);
1654 Ok(())
1655 }
1656
1657 pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
1658 if !self.token.is_like_plus() {
1660 return Ok(());
1661 }
1662
1663 self.bump(); let _bounds = self.parse_generic_bounds()?;
1665 let sub = match &ty.kind {
1666 TyKind::Ref(_lifetime, mut_ty) => {
1667 let lo = mut_ty.ty.span.shrink_to_lo();
1668 let hi = self.prev_token.span.shrink_to_hi();
1669 BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
1670 }
1671 TyKind::Ptr(..) | TyKind::FnPtr(..) => {
1672 BadTypePlusSub::ForgotParen { span: ty.span.to(self.prev_token.span) }
1673 }
1674 _ => BadTypePlusSub::ExpectPath { span: ty.span },
1675 };
1676
1677 self.dcx().emit_err(BadTypePlus { span: ty.span, sub });
1678
1679 Ok(())
1680 }
1681
1682 pub(super) fn recover_from_prefix_increment(
1683 &mut self,
1684 operand_expr: Box<Expr>,
1685 op_span: Span,
1686 start_stmt: bool,
1687 ) -> PResult<'a, Box<Expr>> {
1688 let standalone = if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr };
1689 let kind = IncDecRecovery { standalone, op: IncOrDec::Inc, fixity: UnaryFixity::Pre };
1690 self.recover_from_inc_dec(operand_expr, kind, op_span)
1691 }
1692
1693 pub(super) fn recover_from_postfix_increment(
1694 &mut self,
1695 operand_expr: Box<Expr>,
1696 op_span: Span,
1697 start_stmt: bool,
1698 ) -> PResult<'a, Box<Expr>> {
1699 let kind = IncDecRecovery {
1700 standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
1701 op: IncOrDec::Inc,
1702 fixity: UnaryFixity::Post,
1703 };
1704 self.recover_from_inc_dec(operand_expr, kind, op_span)
1705 }
1706
1707 pub(super) fn recover_from_postfix_decrement(
1708 &mut self,
1709 operand_expr: Box<Expr>,
1710 op_span: Span,
1711 start_stmt: bool,
1712 ) -> PResult<'a, Box<Expr>> {
1713 let kind = IncDecRecovery {
1714 standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr },
1715 op: IncOrDec::Dec,
1716 fixity: UnaryFixity::Post,
1717 };
1718 self.recover_from_inc_dec(operand_expr, kind, op_span)
1719 }
1720
1721 fn recover_from_inc_dec(
1722 &mut self,
1723 base: Box<Expr>,
1724 kind: IncDecRecovery,
1725 op_span: Span,
1726 ) -> PResult<'a, Box<Expr>> {
1727 let mut err = self.dcx().struct_span_err(
1728 op_span,
1729 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Rust has no {0} {1} operator",
kind.fixity, kind.op.name()))
})format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
1730 );
1731 err.span_label(op_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("not a valid {0} operator",
kind.fixity))
})format!("not a valid {} operator", kind.fixity));
1732
1733 let help_base_case = |mut err: Diag<'_, _>, base| {
1734 err.help(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `{0}= 1` instead",
kind.op.chr()))
})format!("use `{}= 1` instead", kind.op.chr()));
1735 err.emit();
1736 Ok(base)
1737 };
1738
1739 let spans = match kind.fixity {
1741 UnaryFixity::Pre => (op_span, base.span.shrink_to_hi()),
1742 UnaryFixity::Post => (base.span.shrink_to_lo(), op_span),
1743 };
1744
1745 match kind.standalone {
1746 IsStandalone::Standalone => {
1747 self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err)
1748 }
1749 IsStandalone::Subexpr => {
1750 let Ok(base_src) = self.span_to_snippet(base.span) else {
1751 return help_base_case(err, base);
1752 };
1753 match kind.fixity {
1754 UnaryFixity::Pre => {
1755 self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
1756 }
1757 UnaryFixity::Post => {
1758 if !#[allow(non_exhaustive_omitted_patterns)] match base.kind {
ExprKind::Binary(_, _, _) => true,
_ => false,
}matches!(base.kind, ExprKind::Binary(_, _, _)) {
1761 self.postfix_inc_dec_suggest(base_src, kind, spans).emit(&mut err)
1762 }
1763 }
1764 }
1765 }
1766 }
1767 Err(err)
1768 }
1769
1770 fn prefix_inc_dec_suggest(
1771 &mut self,
1772 base_src: String,
1773 kind: IncDecRecovery,
1774 (pre_span, post_span): (Span, Span),
1775 ) -> MultiSugg {
1776 MultiSugg {
1777 msg: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `{0}= 1` instead",
kind.op.chr()))
})format!("use `{}= 1` instead", kind.op.chr()),
1778 patches: <[_]>::into_vec(::alloc::boxed::box_new([(pre_span, "{ ".to_string()),
(post_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}= 1; {1} }}",
kind.op.chr(), base_src))
}))]))vec![
1779 (pre_span, "{ ".to_string()),
1780 (post_span, format!(" {}= 1; {} }}", kind.op.chr(), base_src)),
1781 ],
1782 applicability: Applicability::MachineApplicable,
1783 }
1784 }
1785
1786 fn postfix_inc_dec_suggest(
1787 &mut self,
1788 base_src: String,
1789 kind: IncDecRecovery,
1790 (pre_span, post_span): (Span, Span),
1791 ) -> MultiSugg {
1792 let tmp_var = if base_src.trim() == "tmp" { "tmp_" } else { "tmp" };
1793 MultiSugg {
1794 msg: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `{0}= 1` instead",
kind.op.chr()))
})format!("use `{}= 1` instead", kind.op.chr()),
1795 patches: <[_]>::into_vec(::alloc::boxed::box_new([(pre_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{{ let {0} = ", tmp_var))
})),
(post_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("; {0} {1}= 1; {2} }}",
base_src, kind.op.chr(), tmp_var))
}))]))vec![
1796 (pre_span, format!("{{ let {tmp_var} = ")),
1797 (post_span, format!("; {} {}= 1; {} }}", base_src, kind.op.chr(), tmp_var)),
1798 ],
1799 applicability: Applicability::HasPlaceholders,
1800 }
1801 }
1802
1803 fn inc_dec_standalone_suggest(
1804 &mut self,
1805 kind: IncDecRecovery,
1806 (pre_span, post_span): (Span, Span),
1807 ) -> MultiSugg {
1808 let mut patches = Vec::new();
1809
1810 if !pre_span.is_empty() {
1811 patches.push((pre_span, String::new()));
1812 }
1813
1814 patches.push((post_span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}= 1", kind.op.chr()))
})format!(" {}= 1", kind.op.chr())));
1815 MultiSugg {
1816 msg: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("use `{0}= 1` instead",
kind.op.chr()))
})format!("use `{}= 1` instead", kind.op.chr()),
1817 patches,
1818 applicability: Applicability::MachineApplicable,
1819 }
1820 }
1821
1822 pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>(
1826 &mut self,
1827 base: T,
1828 ) -> PResult<'a, T> {
1829 if self.may_recover() && self.token == token::PathSep {
1831 return self.recover_from_bad_qpath(base);
1832 }
1833 Ok(base)
1834 }
1835
1836 #[cold]
1837 fn recover_from_bad_qpath<T: RecoverQPath>(&mut self, base: T) -> PResult<'a, T> {
1838 if let Some(ty) = base.to_ty() {
1839 return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty);
1840 }
1841 Ok(base)
1842 }
1843
1844 pub(super) fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
1847 &mut self,
1848 ty_span: Span,
1849 ty: Box<Ty>,
1850 ) -> PResult<'a, T> {
1851 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::PathSep,
token_type: crate::parser::token_type::TokenType::PathSep,
}exp!(PathSep))?;
1852
1853 let mut path = ast::Path { segments: ThinVec::new(), span: DUMMY_SP, tokens: None };
1854 self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
1855 path.span = ty_span.to(self.prev_token.span);
1856
1857 self.dcx().emit_err(BadQPathStage2 {
1858 span: ty_span,
1859 wrap: WrapType { lo: ty_span.shrink_to_lo(), hi: ty_span.shrink_to_hi() },
1860 });
1861
1862 let path_span = ty_span.shrink_to_hi(); Ok(T::recovered(Some(Box::new(QSelf { ty, path_span, position: 0 })), path))
1864 }
1865
1866 pub fn maybe_consume_incorrect_semicolon(&mut self, previous_item: Option<&Item>) -> bool {
1869 if self.token != TokenKind::Semi {
1870 return false;
1871 }
1872
1873 let err = match previous_item {
1876 Some(previous_item) => {
1877 let name = match previous_item.kind {
1878 ItemKind::Struct(..) => "braced struct",
1881 _ => previous_item.kind.descr(),
1882 };
1883 IncorrectSemicolon { span: self.token.span, name, show_help: true }
1884 }
1885 None => IncorrectSemicolon { span: self.token.span, name: "", show_help: false },
1886 };
1887 self.dcx().emit_err(err);
1888
1889 self.bump();
1890 true
1891 }
1892
1893 pub(super) fn unexpected_try_recover(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
1896 let token_str = pprust::token_kind_to_string(t);
1897 let this_token_str = super::token_descr(&self.token);
1898 let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
1899 (token::Eof, Some(_)) => {
1901 let sp = self.prev_token.span.shrink_to_hi();
1902 (sp, sp)
1903 }
1904 _ if self.prev_token.span == DUMMY_SP => (self.token.span, self.token.span),
1907 (token::Eof, None) => (self.prev_token.span, self.token.span),
1909 _ => (self.prev_token.span.shrink_to_hi(), self.token.span),
1910 };
1911 let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected `{0}`, found {1}",
token_str,
match (&self.token.kind, self.subparser_name) {
(token::Eof, Some(origin)) =>
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("end of {0}", origin))
}),
_ => this_token_str,
}))
})format!(
1912 "expected `{}`, found {}",
1913 token_str,
1914 match (&self.token.kind, self.subparser_name) {
1915 (token::Eof, Some(origin)) => format!("end of {origin}"),
1916 _ => this_token_str,
1917 },
1918 );
1919 let mut err = self.dcx().struct_span_err(sp, msg);
1920 let label_exp = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected `{0}`", token_str))
})format!("expected `{token_str}`");
1921 let sm = self.psess.source_map();
1922 if !sm.is_multiline(prev_sp.until(sp)) {
1923 err.span_label(sp, label_exp);
1926 } else {
1927 err.span_label(prev_sp, label_exp);
1928 err.span_label(sp, "unexpected token");
1929 }
1930 Err(err)
1931 }
1932
1933 pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> {
1934 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)) || self.recover_colon_as_semi() {
1935 return Ok(());
1936 }
1937 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Semi,
token_type: crate::parser::token_type::TokenType::Semi,
}exp!(Semi)).map(drop) }
1939
1940 pub(super) fn recover_colon_as_semi(&mut self) -> bool {
1941 let line_idx = |span: Span| {
1942 self.psess
1943 .source_map()
1944 .span_to_lines(span)
1945 .ok()
1946 .and_then(|lines| Some(lines.lines.get(0)?.line_index))
1947 };
1948
1949 if self.may_recover()
1950 && self.token == token::Colon
1951 && self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span))
1952 {
1953 self.dcx().emit_err(ColonAsSemi { span: self.token.span });
1954 self.bump();
1955 return true;
1956 }
1957
1958 false
1959 }
1960
1961 pub(super) fn recover_incorrect_await_syntax(
1964 &mut self,
1965 await_sp: Span,
1966 ) -> PResult<'a, Box<Expr>> {
1967 let (hi, expr, is_question) = if self.token == token::Bang {
1968 self.recover_await_macro()?
1970 } else {
1971 self.recover_await_prefix(await_sp)?
1972 };
1973 let (sp, guar) = self.error_on_incorrect_await(await_sp, hi, &expr, is_question);
1974 let expr = self.mk_expr_err(await_sp.to(sp), guar);
1975 self.maybe_recover_from_bad_qpath(expr)
1976 }
1977
1978 fn recover_await_macro(&mut self) -> PResult<'a, (Span, Box<Expr>, bool)> {
1979 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Bang,
token_type: crate::parser::token_type::TokenType::Bang,
}exp!(Bang))?;
1980 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen))?;
1981 let expr = self.parse_expr()?;
1982 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen))?;
1983 Ok((self.prev_token.span, expr, false))
1984 }
1985
1986 fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, Box<Expr>, bool)> {
1987 let is_question = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Question,
token_type: crate::parser::token_type::TokenType::Question,
}exp!(Question)); let expr = if self.token == token::OpenBrace {
1989 self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)
1993 } else {
1994 self.parse_expr()
1995 }
1996 .map_err(|mut err| {
1997 err.span_label(await_sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("while parsing this incorrect await expression"))
})format!("while parsing this incorrect await expression"));
1998 err
1999 })?;
2000 Ok((expr.span, expr, is_question))
2001 }
2002
2003 fn error_on_incorrect_await(
2004 &self,
2005 lo: Span,
2006 hi: Span,
2007 expr: &Expr,
2008 is_question: bool,
2009 ) -> (Span, ErrorGuaranteed) {
2010 let span = lo.to(hi);
2011 let guar = self.dcx().emit_err(IncorrectAwait {
2012 span,
2013 suggestion: AwaitSuggestion {
2014 removal: lo.until(expr.span),
2015 dot_await: expr.span.shrink_to_hi(),
2016 question_mark: if is_question { "?" } else { "" },
2017 },
2018 });
2019 (span, guar)
2020 }
2021
2022 pub(super) fn recover_from_await_method_call(&mut self) {
2024 if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
2025 let lo = self.token.span;
2027 self.bump(); let span = lo.to(self.token.span);
2029 self.bump(); self.dcx().emit_err(IncorrectUseOfAwait { span });
2032 }
2033 }
2034 pub(super) fn recover_from_use(&mut self) {
2037 if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
2038 let lo = self.token.span;
2040 self.bump(); let span = lo.to(self.token.span);
2042 self.bump(); self.dcx().emit_err(IncorrectUseOfUse { span });
2045 }
2046 }
2047
2048 pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, Box<Expr>> {
2049 let is_try = self.token.is_keyword(kw::Try);
2050 let is_questionmark = self.look_ahead(1, |t| t == &token::Bang); let is_open = self.look_ahead(2, |t| t == &token::OpenParen); if is_try && is_questionmark && is_open {
2054 let lo = self.token.span;
2055 self.bump(); self.bump(); let try_span = lo.to(self.token.span); self.bump(); let is_empty = self.token == token::CloseParen; self.consume_block(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::OpenParen,
token_type: crate::parser::token_type::TokenType::OpenParen,
}exp!(OpenParen), crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen), ConsumeClosingDelim::No); let hi = self.token.span;
2062 self.bump(); let mut err = self.dcx().struct_span_err(lo.to(hi), "use of deprecated `try` macro");
2064 err.note("in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated");
2065 let prefix = if is_empty { "" } else { "alternatively, " };
2066 if !is_empty {
2067 err.multipart_suggestion(
2068 "you can use the `?` operator instead",
2069 <[_]>::into_vec(::alloc::boxed::box_new([(try_span, "".to_owned()),
(hi, "?".to_owned())]))vec![(try_span, "".to_owned()), (hi, "?".to_owned())],
2070 Applicability::MachineApplicable,
2071 );
2072 }
2073 err.span_suggestion(lo.shrink_to_lo(), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax",
prefix))
})format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
2074 let guar = err.emit();
2075 Ok(self.mk_expr_err(lo.to(hi), guar))
2076 } else {
2077 Err(self.expected_expression_found()) }
2079 }
2080
2081 pub(super) fn expect_gt_or_maybe_suggest_closing_generics(
2088 &mut self,
2089 params: &[ast::GenericParam],
2090 ) -> PResult<'a, ()> {
2091 let Err(mut err) = self.expect_gt() else {
2092 return Ok(());
2093 };
2094 if let [.., ast::GenericParam { bounds, .. }] = params
2096 && let Some(poly) = bounds
2097 .iter()
2098 .filter_map(|bound| match bound {
2099 ast::GenericBound::Trait(poly) => Some(poly),
2100 _ => None,
2101 })
2102 .next_back()
2103 {
2104 err.span_suggestion_verbose(
2105 poly.span.shrink_to_hi(),
2106 "you might have meant to end the type parameters here",
2107 ">",
2108 Applicability::MaybeIncorrect,
2109 );
2110 }
2111 Err(err)
2112 }
2113
2114 pub(super) fn recover_seq_parse_error(
2115 &mut self,
2116 open: ExpTokenPair,
2117 close: ExpTokenPair,
2118 lo: Span,
2119 err: Diag<'a>,
2120 ) -> Box<Expr> {
2121 let guar = err.emit();
2122 self.consume_block(open, close, ConsumeClosingDelim::Yes);
2124 self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err(guar))
2125 }
2126
2127 pub(super) fn recover_stmt(&mut self) {
2132 self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore)
2133 }
2134
2135 pub(super) fn recover_stmt_(
2143 &mut self,
2144 break_on_semi: SemiColonMode,
2145 break_on_block: BlockMode,
2146 ) {
2147 let mut brace_depth = 0;
2148 let mut bracket_depth = 0;
2149 let mut in_block = false;
2150 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:2150",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(2150u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("recover_stmt_ enter loop (semi={0:?}, block={1:?})",
break_on_semi, break_on_block) as &dyn Value))])
});
} else { ; }
};debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", break_on_semi, break_on_block);
2151 loop {
2152 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:2152",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(2152u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("recover_stmt_ loop {0:?}",
self.token) as &dyn Value))])
});
} else { ; }
};debug!("recover_stmt_ loop {:?}", self.token);
2153 match self.token.kind {
2154 token::OpenBrace => {
2155 brace_depth += 1;
2156 self.bump();
2157 if break_on_block == BlockMode::Break && brace_depth == 1 && bracket_depth == 0
2158 {
2159 in_block = true;
2160 }
2161 }
2162 token::OpenBracket => {
2163 bracket_depth += 1;
2164 self.bump();
2165 }
2166 token::CloseBrace => {
2167 if brace_depth == 0 {
2168 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:2168",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(2168u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("recover_stmt_ return - close delim {0:?}",
self.token) as &dyn Value))])
});
} else { ; }
};debug!("recover_stmt_ return - close delim {:?}", self.token);
2169 break;
2170 }
2171 brace_depth -= 1;
2172 self.bump();
2173 if in_block && bracket_depth == 0 && brace_depth == 0 {
2174 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:2174",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(2174u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("recover_stmt_ return - block end {0:?}",
self.token) as &dyn Value))])
});
} else { ; }
};debug!("recover_stmt_ return - block end {:?}", self.token);
2175 break;
2176 }
2177 }
2178 token::CloseBracket => {
2179 bracket_depth -= 1;
2180 if bracket_depth < 0 {
2181 bracket_depth = 0;
2182 }
2183 self.bump();
2184 }
2185 token::Eof => {
2186 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:2186",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(2186u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("recover_stmt_ return - Eof")
as &dyn Value))])
});
} else { ; }
};debug!("recover_stmt_ return - Eof");
2187 break;
2188 }
2189 token::Semi => {
2190 self.bump();
2191 if break_on_semi == SemiColonMode::Break
2192 && brace_depth == 0
2193 && bracket_depth == 0
2194 {
2195 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_parse/src/parser/diagnostics.rs:2195",
"rustc_parse::parser::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_parse/src/parser/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(2195u32),
::tracing_core::__macro_support::Option::Some("rustc_parse::parser::diagnostics"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("recover_stmt_ return - Semi")
as &dyn Value))])
});
} else { ; }
};debug!("recover_stmt_ return - Semi");
2196 break;
2197 }
2198 }
2199 token::Comma
2200 if break_on_semi == SemiColonMode::Comma
2201 && brace_depth == 0
2202 && bracket_depth == 0 =>
2203 {
2204 break;
2205 }
2206 _ => self.bump(),
2207 }
2208 }
2209 }
2210
2211 pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
2212 if self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::In,
token_type: crate::parser::token_type::TokenType::KwIn,
}exp!(In)) {
2213 self.dcx().emit_err(InInTypo {
2215 span: self.prev_token.span,
2216 sugg_span: in_span.until(self.prev_token.span),
2217 });
2218 }
2219 }
2220
2221 pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
2222 if let token::DocComment(..) = self.token.kind {
2223 self.dcx().emit_err(DocCommentOnParamType { span: self.token.span });
2224 self.bump();
2225 } else if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
2226 let lo = self.token.span;
2227 while self.token != token::CloseBracket {
2229 self.bump();
2230 }
2231 let sp = lo.to(self.token.span);
2232 self.bump();
2233 self.dcx().emit_err(AttributeOnParamType { span: sp });
2234 }
2235 }
2236
2237 pub(super) fn parameter_without_type(
2238 &mut self,
2239 err: &mut Diag<'_>,
2240 pat: Box<ast::Pat>,
2241 require_name: bool,
2242 first_param: bool,
2243 fn_parse_mode: &crate::parser::item::FnParseMode,
2244 ) -> Option<Ident> {
2245 if self.check_ident()
2248 && self.look_ahead(1, |t| *t == token::Comma || *t == token::CloseParen)
2249 {
2250 let ident = self.parse_ident_common(true).unwrap();
2252 let span = pat.span.with_hi(ident.span.hi());
2253
2254 err.span_suggestion(
2255 span,
2256 "declare the type after the parameter binding",
2257 "<identifier>: <type>",
2258 Applicability::HasPlaceholders,
2259 );
2260 return Some(ident);
2261 } else if require_name
2262 && (self.token == token::Comma
2263 || self.token == token::Lt
2264 || self.token == token::CloseParen)
2265 {
2266 let maybe_emit_anon_params_note = |this: &mut Self, err: &mut Diag<'_>| {
2267 let ed = this.token.span.with_neighbor(this.prev_token.span).edition();
2268 if #[allow(non_exhaustive_omitted_patterns)] match fn_parse_mode.context {
crate::parser::item::FnContext::Trait => true,
_ => false,
}matches!(fn_parse_mode.context, crate::parser::item::FnContext::Trait)
2269 && (fn_parse_mode.req_name)(ed, IsDotDotDot::No)
2270 {
2271 err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)");
2272 }
2273 };
2274
2275 let (ident, self_sugg, param_sugg, type_sugg, self_span, param_span, type_span) =
2276 match pat.kind {
2277 PatKind::Ident(_, ident, _) => (
2278 ident,
2279 "self: ",
2280 ": TypeName".to_string(),
2281 "_: ",
2282 pat.span.shrink_to_lo(),
2283 pat.span.shrink_to_hi(),
2284 pat.span.shrink_to_lo(),
2285 ),
2286 PatKind::Ref(ref inner_pat, _, _)
2287 if let PatKind::Ref(_, _, _) = &inner_pat.kind
2290 && let PatKind::Path(_, path) = &pat.peel_refs().kind
2291 && let [a, ..] = path.segments.as_slice()
2292 && a.ident.name == kw::SelfLower =>
2293 {
2294 let mut inner = inner_pat;
2295 let mut span_vec = <[_]>::into_vec(::alloc::boxed::box_new([pat.span]))vec![pat.span];
2296
2297 while let PatKind::Ref(ref inner_type, _, _) = inner.kind {
2298 inner = inner_type;
2299 span_vec.push(inner.span.shrink_to_lo());
2300 }
2301
2302 let span = match span_vec.len() {
2303 0 | 1 => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
2305 2 => span_vec[0].until(inner_pat.span.shrink_to_lo()),
2306 _ => span_vec[0].until(span_vec[span_vec.len() - 2].shrink_to_lo()),
2307 };
2308
2309 err.span_suggestion_verbose(
2310 span,
2311 "`self` should be `self`, `&self` or `&mut self`, consider removing extra references",
2312 "".to_string(),
2313 Applicability::MachineApplicable,
2314 );
2315
2316 return None;
2317 }
2318 PatKind::Ref(ref inner_pat, pinned, mutab)
2320 if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind =>
2321 {
2322 let mutab = pinned.prefix_str(mutab);
2323 (
2324 ident,
2325 "self: ",
2326 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: &{1}TypeName", ident, mutab))
})format!("{ident}: &{mutab}TypeName"),
2327 "_: ",
2328 pat.span.shrink_to_lo(),
2329 pat.span,
2330 pat.span.shrink_to_lo(),
2331 )
2332 }
2333 _ => {
2334 if let Some(_) = pat.to_ty() {
2336 err.span_suggestion_verbose(
2337 pat.span.shrink_to_lo(),
2338 "explicitly ignore the parameter name",
2339 "_: ".to_string(),
2340 Applicability::MachineApplicable,
2341 );
2342 maybe_emit_anon_params_note(self, err);
2343 }
2344
2345 return None;
2346 }
2347 };
2348
2349 if first_param
2351 && #[allow(non_exhaustive_omitted_patterns)] match fn_parse_mode.context {
FnContext::Trait | FnContext::Impl => true,
_ => false,
}matches!(
2353 fn_parse_mode.context,
2354 FnContext::Trait | FnContext::Impl
2355 )
2356 {
2357 err.span_suggestion_verbose(
2358 self_span,
2359 "if this is a `self` type, give it a parameter name",
2360 self_sugg,
2361 Applicability::MaybeIncorrect,
2362 );
2363 }
2364 if self.token != token::Lt {
2367 err.span_suggestion_verbose(
2368 param_span,
2369 "if this is a parameter name, give it a type",
2370 param_sugg,
2371 Applicability::HasPlaceholders,
2372 );
2373 }
2374 err.span_suggestion_verbose(
2375 type_span,
2376 "if this is a type, explicitly ignore the parameter name",
2377 type_sugg,
2378 Applicability::MachineApplicable,
2379 );
2380 maybe_emit_anon_params_note(self, err);
2381
2382 return if self.token == token::Lt { None } else { Some(ident) };
2384 }
2385 None
2386 }
2387
2388 #[cold]
2389 pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (Box<ast::Pat>, Box<ast::Ty>)> {
2390 let pat = self.parse_pat_no_top_alt(Some(Expected::ArgumentName), None)?;
2391 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon))?;
2392 let ty = self.parse_ty()?;
2393
2394 self.dcx().emit_err(PatternMethodParamWithoutBody { span: pat.span });
2395
2396 let pat = Box::new(Pat {
2398 kind: PatKind::Wild,
2399 span: pat.span,
2400 id: ast::DUMMY_NODE_ID,
2401 tokens: None,
2402 });
2403 Ok((pat, ty))
2404 }
2405
2406 pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> {
2407 let span = param.pat.span;
2408 let guar = self.dcx().emit_err(SelfParamNotFirst { span });
2409 param.ty.kind = TyKind::Err(guar);
2410 Ok(param)
2411 }
2412
2413 pub(super) fn consume_block(
2414 &mut self,
2415 open: ExpTokenPair,
2416 close: ExpTokenPair,
2417 consume_close: ConsumeClosingDelim,
2418 ) {
2419 let mut brace_depth = 0;
2420 loop {
2421 if self.eat(open) {
2422 brace_depth += 1;
2423 } else if self.check(close) {
2424 if brace_depth == 0 {
2425 if let ConsumeClosingDelim::Yes = consume_close {
2426 self.bump();
2430 }
2431 return;
2432 } else {
2433 self.bump();
2434 brace_depth -= 1;
2435 continue;
2436 }
2437 } else if self.token == token::Eof {
2438 return;
2439 } else {
2440 self.bump();
2441 }
2442 }
2443 }
2444
2445 pub(super) fn expected_expression_found(&self) -> Diag<'a> {
2446 let (span, msg) = match (&self.token.kind, self.subparser_name) {
2447 (&token::Eof, Some(origin)) => {
2448 let sp = self.prev_token.span.shrink_to_hi();
2449 (sp, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected expression, found end of {0}",
origin))
})format!("expected expression, found end of {origin}"))
2450 }
2451 _ => (
2452 self.token.span,
2453 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected expression, found {0}",
super::token_descr(&self.token)))
})format!("expected expression, found {}", super::token_descr(&self.token)),
2454 ),
2455 };
2456 let mut err = self.dcx().struct_span_err(span, msg);
2457 let sp = self.psess.source_map().start_point(self.token.span);
2458 if let Some(sp) = self.psess.ambiguous_block_expr_parse.borrow().get(&sp) {
2459 err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
2460 }
2461 err.span_label(span, "expected expression");
2462 err
2463 }
2464
2465 fn consume_tts(
2466 &mut self,
2467 mut acc: i64, modifier: &[(token::TokenKind, i64)],
2470 ) {
2471 while acc > 0 {
2472 if let Some((_, val)) = modifier.iter().find(|(t, _)| self.token == *t) {
2473 acc += *val;
2474 }
2475 if self.token == token::Eof {
2476 break;
2477 }
2478 self.bump();
2479 }
2480 }
2481
2482 pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec<Param>) {
2491 let mut seen_inputs = FxHashSet::default();
2492 for input in fn_inputs.iter_mut() {
2493 let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) =
2494 (&input.pat.kind, &input.ty.kind)
2495 {
2496 Some(*ident)
2497 } else {
2498 None
2499 };
2500 if let Some(ident) = opt_ident {
2501 if seen_inputs.contains(&ident) {
2502 input.pat.kind = PatKind::Wild;
2503 }
2504 seen_inputs.insert(ident);
2505 }
2506 }
2507 }
2508
2509 pub(super) fn handle_ambiguous_unbraced_const_arg(
2513 &mut self,
2514 args: &mut ThinVec<AngleBracketedArg>,
2515 ) -> PResult<'a, bool> {
2516 let arg = args.pop().unwrap();
2520 let mut err = self.dcx().struct_span_err(
2526 self.token.span,
2527 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected one of `,` or `>`, found {0}",
super::token_descr(&self.token)))
})format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
2528 );
2529 err.span_label(self.token.span, "expected one of `,` or `>`");
2530 match self.recover_const_arg(arg.span(), err) {
2531 Ok(arg) => {
2532 args.push(AngleBracketedArg::Arg(arg));
2533 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
2534 return Ok(true); }
2536 }
2537 Err(err) => {
2538 args.push(arg);
2539 err.delay_as_bug();
2541 }
2542 }
2543 Ok(false) }
2545
2546 fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option<GenericArg> {
2547 let snapshot = self.create_snapshot_for_diagnostic();
2548 let param = match self.parse_const_param(AttrVec::new()) {
2549 Ok(param) => param,
2550 Err(err) => {
2551 err.cancel();
2552 self.restore_snapshot(snapshot);
2553 return None;
2554 }
2555 };
2556
2557 let ident = param.ident.to_string();
2558 let sugg = match (ty_generics, self.psess.source_map().span_to_snippet(param.span())) {
2559 (Some(Generics { params, span: impl_generics, .. }), Ok(snippet)) => {
2560 Some(match ¶ms[..] {
2561 [] => UnexpectedConstParamDeclarationSugg::AddParam {
2562 impl_generics: *impl_generics,
2563 incorrect_decl: param.span(),
2564 snippet,
2565 ident,
2566 },
2567 [.., generic] => UnexpectedConstParamDeclarationSugg::AppendParam {
2568 impl_generics_end: generic.span().shrink_to_hi(),
2569 incorrect_decl: param.span(),
2570 snippet,
2571 ident,
2572 },
2573 })
2574 }
2575 _ => None,
2576 };
2577 let guar =
2578 self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
2579
2580 let value = self.mk_expr_err(param.span(), guar);
2581 Some(GenericArg::Const(AnonConst {
2582 id: ast::DUMMY_NODE_ID,
2583 value,
2584 mgca_disambiguation: MgcaDisambiguation::Direct,
2585 }))
2586 }
2587
2588 pub(super) fn recover_const_param_declaration(
2589 &mut self,
2590 ty_generics: Option<&Generics>,
2591 ) -> PResult<'a, Option<GenericArg>> {
2592 if let Some(arg) = self.recover_const_param_decl(ty_generics) {
2594 return Ok(Some(arg));
2595 }
2596
2597 let start = self.token.span;
2599 self.bump(); let mut err = UnexpectedConstInGenericParam { span: start, to_remove: None };
2603 if self.check_const_arg() {
2604 err.to_remove = Some(start.until(self.token.span));
2605 self.dcx().emit_err(err);
2606 Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
2607 } else {
2608 let after_kw_const = self.token.span;
2609 self.recover_const_arg(after_kw_const, self.dcx().create_err(err)).map(Some)
2610 }
2611 }
2612
2613 pub(super) fn recover_const_arg(
2619 &mut self,
2620 start: Span,
2621 mut err: Diag<'a>,
2622 ) -> PResult<'a, GenericArg> {
2623 let is_op_or_dot = AssocOp::from_token(&self.token)
2624 .and_then(|op| {
2625 if let AssocOp::Binary(
2626 BinOpKind::Gt
2627 | BinOpKind::Lt
2628 | BinOpKind::Shr
2629 | BinOpKind::Ge
2630 )
2631 | AssocOp::Assign
2634 | AssocOp::AssignOp(_) = op
2635 {
2636 None
2637 } else {
2638 Some(op)
2639 }
2640 })
2641 .is_some()
2642 || self.token == TokenKind::Dot;
2643 let was_op = #[allow(non_exhaustive_omitted_patterns)] match self.prev_token.kind {
token::Plus | token::Shr | token::Gt => true,
_ => false,
}matches!(self.prev_token.kind, token::Plus | token::Shr | token::Gt);
2646 if !is_op_or_dot && !was_op {
2647 return Err(err);
2649 }
2650 let snapshot = self.create_snapshot_for_diagnostic();
2651 if is_op_or_dot {
2652 self.bump();
2653 }
2654 match (|| {
2655 let attrs = self.parse_outer_attributes()?;
2656 self.parse_expr_res(Restrictions::CONST_EXPR, attrs)
2657 })() {
2658 Ok((expr, _)) => {
2659 if snapshot.token == token::EqEq {
2661 err.span_suggestion(
2662 snapshot.token.span,
2663 "if you meant to use an associated type binding, replace `==` with `=`",
2664 "=",
2665 Applicability::MaybeIncorrect,
2666 );
2667 let guar = err.emit();
2668 let value = self.mk_expr_err(start.to(expr.span), guar);
2669 return Ok(GenericArg::Const(AnonConst {
2670 id: ast::DUMMY_NODE_ID,
2671 value,
2672 mgca_disambiguation: MgcaDisambiguation::Direct,
2673 }));
2674 } else if snapshot.token == token::Colon
2675 && expr.span.lo() == snapshot.token.span.hi()
2676 && #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ExprKind::Path(..) => true,
_ => false,
}matches!(expr.kind, ExprKind::Path(..))
2677 {
2678 err.span_suggestion(
2680 snapshot.token.span,
2681 "write a path separator here",
2682 "::",
2683 Applicability::MaybeIncorrect,
2684 );
2685 let guar = err.emit();
2686 return Ok(GenericArg::Type(
2687 self.mk_ty(start.to(expr.span), TyKind::Err(guar)),
2688 ));
2689 } else if self.token == token::Comma || self.token.kind.should_end_const_arg() {
2690 return Ok(self.dummy_const_arg_needs_braces(err, start.to(expr.span)));
2697 }
2698 }
2699 Err(err) => {
2700 err.cancel();
2701 }
2702 }
2703 self.restore_snapshot(snapshot);
2704 Err(err)
2705 }
2706
2707 pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty(
2711 &mut self,
2712 mut snapshot: SnapshotParser<'a>,
2713 ) -> Option<Box<ast::Expr>> {
2714 match (|| {
2715 let attrs = self.parse_outer_attributes()?;
2716 snapshot.parse_expr_res(Restrictions::CONST_EXPR, attrs)
2717 })() {
2718 Ok((expr, _)) if let token::Comma | token::Gt = snapshot.token.kind => {
2721 self.restore_snapshot(snapshot);
2722 Some(expr)
2723 }
2724 Ok(_) => None,
2725 Err(err) => {
2726 err.cancel();
2727 None
2728 }
2729 }
2730 }
2731
2732 pub(super) fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg {
2734 err.multipart_suggestion(
2735 "expressions must be enclosed in braces to be used as const generic \
2736 arguments",
2737 <[_]>::into_vec(::alloc::boxed::box_new([(span.shrink_to_lo(),
"{ ".to_string()),
(span.shrink_to_hi(), " }".to_string())]))vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())],
2738 Applicability::MaybeIncorrect,
2739 );
2740 let guar = err.emit();
2741 let value = self.mk_expr_err(span, guar);
2742 GenericArg::Const(AnonConst {
2743 id: ast::DUMMY_NODE_ID,
2744 value,
2745 mgca_disambiguation: MgcaDisambiguation::Direct,
2746 })
2747 }
2748
2749 #[cold]
2752 pub(crate) fn recover_colon_colon_in_pat_typo(
2753 &mut self,
2754 mut first_pat: Pat,
2755 expected: Option<Expected>,
2756 ) -> Pat {
2757 if token::Colon != self.token.kind {
2758 return first_pat;
2759 }
2760
2761 let colon_span = self.token.span;
2764 let mut snapshot_pat = self.create_snapshot_for_diagnostic();
2767 let mut snapshot_type = self.create_snapshot_for_diagnostic();
2768
2769 match self.expected_one_of_not_found(&[], &[]) {
2771 Err(mut err) => {
2772 snapshot_pat.bump();
2774 snapshot_type.bump();
2775 match snapshot_pat.parse_pat_no_top_alt(expected, None) {
2776 Err(inner_err) => {
2777 inner_err.cancel();
2778 }
2779 Ok(mut pat) => {
2780 let new_span = first_pat.span.to(pat.span);
2782 let mut show_sugg = false;
2783 match &mut pat.kind {
2785 PatKind::Struct(qself @ None, path, ..)
2786 | PatKind::TupleStruct(qself @ None, path, _)
2787 | PatKind::Path(qself @ None, path) => match &first_pat.kind {
2788 PatKind::Ident(_, ident, _) => {
2789 path.segments.insert(0, PathSegment::from_ident(*ident));
2790 path.span = new_span;
2791 show_sugg = true;
2792 first_pat = pat;
2793 }
2794 PatKind::Path(old_qself, old_path) => {
2795 path.segments = old_path
2796 .segments
2797 .iter()
2798 .cloned()
2799 .chain(take(&mut path.segments))
2800 .collect();
2801 path.span = new_span;
2802 *qself = old_qself.clone();
2803 first_pat = pat;
2804 show_sugg = true;
2805 }
2806 _ => {}
2807 },
2808 PatKind::Ident(BindingMode::NONE, ident, None) => {
2809 match &first_pat.kind {
2810 PatKind::Ident(_, old_ident, _) => {
2811 let path = PatKind::Path(
2812 None,
2813 Path {
2814 span: new_span,
2815 segments: {
let len = [(), ()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(PathSegment::from_ident(*old_ident));
vec.push(PathSegment::from_ident(*ident));
vec
}thin_vec![
2816 PathSegment::from_ident(*old_ident),
2817 PathSegment::from_ident(*ident),
2818 ],
2819 tokens: None,
2820 },
2821 );
2822 first_pat = self.mk_pat(new_span, path);
2823 show_sugg = true;
2824 }
2825 PatKind::Path(old_qself, old_path) => {
2826 let mut segments = old_path.segments.clone();
2827 segments.push(PathSegment::from_ident(*ident));
2828 let path = PatKind::Path(
2829 old_qself.clone(),
2830 Path { span: new_span, segments, tokens: None },
2831 );
2832 first_pat = self.mk_pat(new_span, path);
2833 show_sugg = true;
2834 }
2835 _ => {}
2836 }
2837 }
2838 _ => {}
2839 }
2840 if show_sugg {
2841 err.span_suggestion_verbose(
2842 colon_span.until(self.look_ahead(1, |t| t.span)),
2843 "maybe write a path separator here",
2844 "::",
2845 Applicability::MaybeIncorrect,
2846 );
2847 } else {
2848 first_pat = self.mk_pat(
2849 new_span,
2850 PatKind::Err(
2851 self.dcx()
2852 .span_delayed_bug(colon_span, "recovered bad path pattern"),
2853 ),
2854 );
2855 }
2856 self.restore_snapshot(snapshot_pat);
2857 }
2858 }
2859 match snapshot_type.parse_ty() {
2860 Err(inner_err) => {
2861 inner_err.cancel();
2862 }
2863 Ok(ty) => {
2864 err.span_label(ty.span, "specifying the type of a pattern isn't supported");
2865 self.restore_snapshot(snapshot_type);
2866 let new_span = first_pat.span.to(ty.span);
2867 first_pat =
2868 self.mk_pat(
2869 new_span,
2870 PatKind::Err(self.dcx().span_delayed_bug(
2871 colon_span,
2872 "recovered bad pattern with type",
2873 )),
2874 );
2875 }
2876 }
2877 err.emit();
2878 }
2879 _ => {
2880 }
2882 };
2883 first_pat
2884 }
2885
2886 pub(crate) fn maybe_recover_unexpected_block_label(
2889 &mut self,
2890 loop_header: Option<Span>,
2891 ) -> bool {
2892 if !(self.check_lifetime()
2894 && self.look_ahead(1, |t| *t == token::Colon)
2895 && self.look_ahead(2, |t| *t == token::OpenBrace))
2896 {
2897 return false;
2898 }
2899 let label = self.eat_label().expect("just checked if a label exists");
2900 self.bump(); let span = label.ident.span.to(self.prev_token.span);
2902 let mut diag = self
2903 .dcx()
2904 .struct_span_err(span, "block label not supported here")
2905 .with_span_label(span, "not supported here");
2906 if let Some(loop_header) = loop_header {
2907 diag.multipart_suggestion(
2908 "if you meant to label the loop, move this label before the loop",
2909 <[_]>::into_vec(::alloc::boxed::box_new([(label.ident.span.until(self.token.span),
String::from("")),
(loop_header.shrink_to_lo(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: ", label.ident))
}))]))vec![
2910 (label.ident.span.until(self.token.span), String::from("")),
2911 (loop_header.shrink_to_lo(), format!("{}: ", label.ident)),
2912 ],
2913 Applicability::MachineApplicable,
2914 );
2915 } else {
2916 diag.tool_only_span_suggestion(
2917 label.ident.span.until(self.token.span),
2918 "remove this block label",
2919 "",
2920 Applicability::MachineApplicable,
2921 );
2922 }
2923 diag.emit();
2924 true
2925 }
2926
2927 pub(crate) fn maybe_recover_unexpected_comma(
2930 &mut self,
2931 lo: Span,
2932 rt: CommaRecoveryMode,
2933 ) -> PResult<'a, ()> {
2934 if self.token != token::Comma {
2935 return Ok(());
2936 }
2937 self.recover_unexpected_comma(lo, rt)
2938 }
2939
2940 #[cold]
2941 fn recover_unexpected_comma(&mut self, lo: Span, rt: CommaRecoveryMode) -> PResult<'a, ()> {
2942 let comma_span = self.token.span;
2947 self.bump();
2948 if let Err(err) = self.skip_pat_list() {
2949 err.cancel();
2952 }
2953 let seq_span = lo.to(self.prev_token.span);
2954 let mut err = self.dcx().struct_span_err(comma_span, "unexpected `,` in pattern");
2955 err.multipart_suggestion(
2956 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("try adding parentheses to match on a tuple{0}",
if let CommaRecoveryMode::LikelyTuple = rt {
""
} else { "..." }))
})format!(
2957 "try adding parentheses to match on a tuple{}",
2958 if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
2959 ),
2960 <[_]>::into_vec(::alloc::boxed::box_new([(seq_span.shrink_to_lo(),
"(".to_string()),
(seq_span.shrink_to_hi(), ")".to_string())]))vec![
2961 (seq_span.shrink_to_lo(), "(".to_string()),
2962 (seq_span.shrink_to_hi(), ")".to_string()),
2963 ],
2964 Applicability::MachineApplicable,
2965 );
2966 if let CommaRecoveryMode::EitherTupleOrPipe = rt {
2967 err.span_suggestion(
2968 comma_span,
2969 "...or a vertical bar to match on alternatives",
2970 " |",
2971 Applicability::MachineApplicable,
2972 );
2973 }
2974 Err(err)
2975 }
2976
2977 pub(crate) fn maybe_recover_bounds_doubled_colon(&mut self, ty: &Ty) -> PResult<'a, ()> {
2978 let TyKind::Path(qself, path) = &ty.kind else { return Ok(()) };
2979 let qself_position = qself.as_ref().map(|qself| qself.position);
2980 for (i, segments) in path.segments.windows(2).enumerate() {
2981 if qself_position.is_some_and(|pos| i < pos) {
2982 continue;
2983 }
2984 if let [a, b] = segments {
2985 let (a_span, b_span) = (a.span(), b.span());
2986 let between_span = a_span.shrink_to_hi().to(b_span.shrink_to_lo());
2987 if self.span_to_snippet(between_span).as_deref() == Ok(":: ") {
2988 return Err(self.dcx().create_err(DoubleColonInBound {
2989 span: path.span.shrink_to_hi(),
2990 between: between_span,
2991 }));
2992 }
2993 }
2994 }
2995 Ok(())
2996 }
2997
2998 pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: Diag<'a>) -> Diag<'a> {
3000 if maybe_lt == token::Lt
3001 && (self.expected_token_types.contains(TokenType::Gt)
3002 || #[allow(non_exhaustive_omitted_patterns)] match self.token.kind {
token::Literal(..) => true,
_ => false,
}matches!(self.token.kind, token::Literal(..)))
3003 {
3004 err.span_suggestion(
3005 maybe_lt.span,
3006 "remove the `<` to write an exclusive range",
3007 "",
3008 Applicability::MachineApplicable,
3009 );
3010 }
3011 err
3012 }
3013
3014 pub(super) fn is_vcs_conflict_marker(
3022 &mut self,
3023 long_kind: &TokenKind,
3024 short_kind: &TokenKind,
3025 ) -> bool {
3026 if long_kind == short_kind {
3027 (0..7).all(|i| self.look_ahead(i, |tok| tok == long_kind))
3029 } else {
3030 (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
3032 && self.look_ahead(3, |tok| tok == short_kind || tok == long_kind)
3033 }
3034 }
3035
3036 fn conflict_marker(
3037 &mut self,
3038 long_kind: &TokenKind,
3039 short_kind: &TokenKind,
3040 expected: Option<usize>,
3041 ) -> Option<(Span, usize)> {
3042 if self.is_vcs_conflict_marker(long_kind, short_kind) {
3043 let lo = self.token.span;
3044 if self.psess.source_map().span_to_margin(lo) != Some(0) {
3045 return None;
3046 }
3047 let mut len = 0;
3048 while self.token.kind == *long_kind || self.token.kind == *short_kind {
3049 if self.token.kind.break_two_token_op(1).is_some() {
3050 len += 2;
3051 } else {
3052 len += 1;
3053 }
3054 self.bump();
3055 if expected == Some(len) {
3056 break;
3057 }
3058 }
3059 if expected.is_some() && expected != Some(len) {
3060 return None;
3061 }
3062 return Some((lo.to(self.prev_token.span), len));
3063 }
3064 None
3065 }
3066
3067 pub(super) fn recover_vcs_conflict_marker(&mut self) {
3068 let Some((start, len)) = self.conflict_marker(&TokenKind::Shl, &TokenKind::Lt, None) else {
3070 return;
3071 };
3072 let mut spans = Vec::with_capacity(2);
3073 spans.push(start);
3074 let mut middlediff3 = None;
3076 let mut middle = None;
3078 let mut end = None;
3080 loop {
3081 if self.token == TokenKind::Eof {
3082 break;
3083 }
3084 if let Some((span, _)) =
3085 self.conflict_marker(&TokenKind::OrOr, &TokenKind::Or, Some(len))
3086 {
3087 middlediff3 = Some(span);
3088 }
3089 if let Some((span, _)) =
3090 self.conflict_marker(&TokenKind::EqEq, &TokenKind::Eq, Some(len))
3091 {
3092 middle = Some(span);
3093 }
3094 if let Some((span, _)) =
3095 self.conflict_marker(&TokenKind::Shr, &TokenKind::Gt, Some(len))
3096 {
3097 spans.push(span);
3098 end = Some(span);
3099 break;
3100 }
3101 self.bump();
3102 }
3103
3104 let mut err = self.dcx().struct_span_fatal(spans, "encountered diff marker");
3105 let middle_marker = match middlediff3 {
3106 Some(middlediff3) => {
3108 err.span_label(
3109 middlediff3,
3110 "between this marker and `=======` is the base code (what the two refs \
3111 diverged from)",
3112 );
3113 "|||||||"
3114 }
3115 None => "=======",
3116 };
3117 err.span_label(
3118 start,
3119 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("between this marker and `{0}` is the code that you are merging into",
middle_marker))
})format!(
3120 "between this marker and `{middle_marker}` is the code that you are merging into",
3121 ),
3122 );
3123
3124 if let Some(middle) = middle {
3125 err.span_label(middle, "between this marker and `>>>>>>>` is the incoming code");
3126 }
3127 if let Some(end) = end {
3128 err.span_label(end, "this marker concludes the conflict region");
3129 }
3130 err.note(
3131 "conflict markers indicate that a merge was started but could not be completed due \
3132 to merge conflicts\n\
3133 to resolve a conflict, keep only the code you want and then delete the lines \
3134 containing conflict markers",
3135 );
3136 err.help(
3137 "if you are in a merge, the top section is the code you already had checked out and \
3138 the bottom section is the new code\n\
3139 if you are in a rebase, the top section is the code being rebased onto and the bottom \
3140 section is the code you had checked out which is being rebased",
3141 );
3142
3143 err.note(
3144 "for an explanation on these markers from the `git` documentation, visit \
3145 <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
3146 );
3147
3148 err.emit();
3149 }
3150
3151 fn skip_pat_list(&mut self) -> PResult<'a, ()> {
3154 while !self.check(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::CloseParen,
token_type: crate::parser::token_type::TokenType::CloseParen,
}exp!(CloseParen)) {
3155 self.parse_pat_no_top_alt(None, None)?;
3156 if !self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
3157 return Ok(());
3158 }
3159 }
3160 Ok(())
3161 }
3162}