diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
commit | ef24de24a82fe681581cc130f342363c47c0969a (patch) | |
tree | 0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_parse/src/parser/diagnostics.rs | |
parent | Releasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip |
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_parse/src/parser/diagnostics.rs')
-rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 211 |
1 files changed, 152 insertions, 59 deletions
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 06b1b1523..2a8eb6edd 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -39,7 +39,7 @@ use rustc_errors::{ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP}; +use rustc_span::{BytePos, Span, SpanSnippetError, Symbol, DUMMY_SP}; use std::mem::take; use std::ops::{Deref, DerefMut}; use thin_vec::{thin_vec, ThinVec}; @@ -314,11 +314,10 @@ impl<'a> Parser<'a> { // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` let ident_name = ident.name.to_string(); - Some(SuggEscapeIdentifier { - span: ident.span.shrink_to_lo(), - ident_name - }) - } else { None }; + Some(SuggEscapeIdentifier { span: ident.span.shrink_to_lo(), ident_name }) + } else { + None + }; let suggest_remove_comma = if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { @@ -375,9 +374,11 @@ impl<'a> Parser<'a> { // and current token should be Ident with the item name (i.e. the function name) // if there is a `<` after the fn name, then don't show a suggestion, show help - if !self.look_ahead(1, |t| *t == token::Lt) && - let Ok(snippet) = self.sess.source_map().span_to_snippet(generic.span) { - err.multipart_suggestion_verbose( + if !self.look_ahead(1, |t| *t == token::Lt) + && let Ok(snippet) = + self.sess.source_map().span_to_snippet(generic.span) + { + err.multipart_suggestion_verbose( format!("place the generic parameter name after the {ident_name} name"), vec![ (self.token.span.shrink_to_hi(), snippet), @@ -385,11 +386,11 @@ impl<'a> Parser<'a> { ], Applicability::MaybeIncorrect, ); - } else { - err.help(format!( - "place the generic parameter name after the {ident_name} name" - )); - } + } else { + err.help(format!( + "place the generic parameter name after the {ident_name} name" + )); + } } } Err(err) => { @@ -402,7 +403,9 @@ impl<'a> Parser<'a> { } } - if let Some(recovered_ident) = recovered_ident && recover { + if let Some(recovered_ident) = recovered_ident + && recover + { err.emit(); Ok(recovered_ident) } else { @@ -501,8 +504,10 @@ impl<'a> Parser<'a> { // Special-case "expected `;`" errors if expected.contains(&TokenType::Token(token::Semi)) { - if self.prev_token == token::Question && self.maybe_recover_from_ternary_operator() { - return Ok(true); + // If the user is trying to write a ternary expression, recover it and + // return an Err to prevent a cascade of irrelevant diagnostics + if self.prev_token == token::Question && let Err(e) = self.maybe_recover_from_ternary_operator() { + return Err(e); } if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP { @@ -617,19 +622,19 @@ impl<'a> Parser<'a> { } if let TokenKind::Ident(prev, _) = &self.prev_token.kind - && let TokenKind::Ident(cur, _) = &self.token.kind + && let TokenKind::Ident(cur, _) = &self.token.kind { - let concat = Symbol::intern(&format!("{prev}{cur}")); - let ident = Ident::new(concat, DUMMY_SP); - if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { - let span = self.prev_token.span.to(self.token.span); - err.span_suggestion_verbose( - span, - format!("consider removing the space to spell keyword `{concat}`"), - concat, - Applicability::MachineApplicable, - ); - } + let concat = Symbol::intern(&format!("{prev}{cur}")); + let ident = Ident::new(concat, DUMMY_SP); + if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { + let span = self.prev_token.span.to(self.token.span); + err.span_suggestion_verbose( + span, + format!("consider removing the space to spell keyword `{concat}`"), + concat, + Applicability::MachineApplicable, + ); + } } // `pub` may be used for an item or `pub(crate)` @@ -645,6 +650,26 @@ impl<'a> Parser<'a> { ); } + if let token::DocComment(kind, style, _) = self.token.kind { + // We have something like `expr //!val` where the user likely meant `expr // !val` + let pos = self.token.span.lo() + BytePos(2); + let span = self.token.span.with_lo(pos).with_hi(pos); + err.span_suggestion_verbose( + span, + format!( + "add a space before {} 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 `*`", + }, + ), + " ".to_string(), + Applicability::MachineApplicable, + ); + } + // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens // there are unclosed angle brackets if self.unmatched_angle_bracket_count > 0 @@ -827,6 +852,65 @@ impl<'a> Parser<'a> { None } + pub(super) fn recover_closure_body( + &mut self, + mut err: DiagnosticBuilder<'a, ErrorGuaranteed>, + before: token::Token, + prev: token::Token, + token: token::Token, + lo: Span, + decl_hi: Span, + ) -> PResult<'a, P<Expr>> { + err.span_label(lo.to(decl_hi), "while parsing the body of this closure"); + match before.kind { + token::OpenDelim(Delimiter::Brace) + if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => + { + // `{ || () }` should have been `|| { () }` + err.multipart_suggestion( + "you might have meant to open the body of the closure, instead of enclosing \ + the closure in a block", + vec![ + (before.span, String::new()), + (prev.span.shrink_to_hi(), " {".to_string()), + ], + Applicability::MaybeIncorrect, + ); + err.emit(); + self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]); + } + token::OpenDelim(Delimiter::Parenthesis) + if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => + { + // We are within a function call or tuple, we can emit the error + // and recover. + self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis), &token::Comma]); + + err.multipart_suggestion_verbose( + "you might have meant to open the body of the closure", + vec![ + (prev.span.shrink_to_hi(), " {".to_string()), + (self.token.span.shrink_to_lo(), "}".to_string()), + ], + Applicability::MaybeIncorrect, + ); + err.emit(); + } + _ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => { + // We don't have a heuristic to correctly identify where the block + // should be closed. + err.multipart_suggestion_verbose( + "you might have meant to open the body of the closure", + vec![(prev.span.shrink_to_hi(), " {".to_string())], + Applicability::HasPlaceholders, + ); + return Err(err); + } + _ => return Err(err), + } + Ok(self.mk_expr_err(lo.to(self.token.span))) + } + /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { @@ -1025,8 +1109,7 @@ impl<'a> Parser<'a> { .emit(); match self.parse_expr() { Ok(_) => { - *expr = - self.mk_expr_err(expr.span.to(self.prev_token.span)); + *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); return Ok(()); } Err(err) => { @@ -1218,7 +1301,9 @@ impl<'a> Parser<'a> { return if token::ModSep == self.token.kind { // We have some certainty that this was a bad turbofish at this point. // `foo< bar >::` - if let ExprKind::Binary(o, ..) = inner_op.kind && o.node == BinOpKind::Lt { + if let ExprKind::Binary(o, ..) = inner_op.kind + && o.node == BinOpKind::Lt + { err.suggest_turbofish = Some(op.span.shrink_to_lo()); } else { err.help_turbofish = Some(()); @@ -1248,7 +1333,9 @@ impl<'a> Parser<'a> { } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind { // We have high certainty that this was a bad turbofish at this point. // `foo< bar >(` - if let ExprKind::Binary(o, ..) = inner_op.kind && o.node == BinOpKind::Lt { + if let ExprKind::Binary(o, ..) = inner_op.kind + && o.node == BinOpKind::Lt + { err.suggest_turbofish = Some(op.span.shrink_to_lo()); } else { err.help_turbofish = Some(()); @@ -1343,10 +1430,10 @@ impl<'a> Parser<'a> { /// Rust has no ternary operator (`cond ? then : else`). Parse it and try /// to recover from it if `then` and `else` are valid expressions. Returns - /// whether it was a ternary operator. - pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> bool { + /// an err if this appears to be a ternary expression. + pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> PResult<'a, ()> { if self.prev_token != token::Question { - return false; + return PResult::Ok(()); } let lo = self.prev_token.span.lo(); @@ -1364,20 +1451,18 @@ impl<'a> Parser<'a> { if self.eat_noexpect(&token::Colon) { match self.parse_expr() { Ok(_) => { - self.sess.emit_err(TernaryOperator { span: self.token.span.with_lo(lo) }); - return true; + return Err(self + .sess + .create_err(TernaryOperator { span: self.token.span.with_lo(lo) })); } Err(err) => { err.cancel(); - self.restore_snapshot(snapshot); } }; } - } else { - self.restore_snapshot(snapshot); - }; - - false + } + self.restore_snapshot(snapshot); + Ok(()) } pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> { @@ -1826,19 +1911,21 @@ impl<'a> Parser<'a> { let sm = self.sess.source_map(); let left = begin_par_sp; let right = self.prev_token.span; - let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left) && - !snip.ends_with(' ') { - " ".to_string() - } else { - "".to_string() - }; + let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left) + && !snip.ends_with(' ') + { + " ".to_string() + } else { + "".to_string() + }; - let right_snippet = if let Ok(snip) = sm.span_to_next_source(right) && - !snip.starts_with(' ') { - " ".to_string() - } else { - "".to_string() - }; + let right_snippet = if let Ok(snip) = sm.span_to_next_source(right) + && !snip.starts_with(' ') + { + " ".to_string() + } else { + "".to_string() + }; self.sess.emit_err(ParenthesesInForHead { span: vec![left, right], @@ -2721,8 +2808,15 @@ impl<'a> Parser<'a> { } pub fn recover_diff_marker(&mut self) { + if let Err(mut err) = self.err_diff_marker() { + err.emit(); + FatalError.raise(); + } + } + + pub fn err_diff_marker(&mut self) -> PResult<'a, ()> { let Some(start) = self.diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) else { - return; + return Ok(()); }; let mut spans = Vec::with_capacity(3); spans.push(start); @@ -2769,8 +2863,7 @@ impl<'a> Parser<'a> { "for an explanation on these markers from the `git` documentation, visit \ <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>", ); - err.emit(); - FatalError.raise() + Err(err) } /// Parse and throw away a parenthesized comma separated |