about summary refs log tree commit diff
path: root/compiler/rustc_parse/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-07-06 03:07:46 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-07-12 03:02:57 +0000
commit692bc344d55cf9d86c60b06c92a70684d013c89f (patch)
tree4ab084f04f99c13c3a5e84aeb405867bc3319f96 /compiler/rustc_parse/src
parent5e311f933d844b6922256a0c0aa49b86159534f5 (diff)
downloadrust-692bc344d55cf9d86c60b06c92a70684d013c89f.tar.gz
rust-692bc344d55cf9d86c60b06c92a70684d013c89f.zip
Make parse error suggestions verbose and fix spans
Go over all structured parser suggestions and make them verbose style.

When suggesting to add or remove delimiters, turn them into multiple suggestion parts.
Diffstat (limited to 'compiler/rustc_parse/src')
-rw-r--r--compiler/rustc_parse/src/errors.rs392
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs35
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs11
-rw-r--r--compiler/rustc_parse/src/parser/item.rs6
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs50
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs8
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs23
7 files changed, 344 insertions, 181 deletions
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 3ae9b6dad99..0f13a8e5e14 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -18,10 +18,10 @@ use crate::parser::{ForbiddenLetReason, TokenDescription};
 #[derive(Diagnostic)]
 #[diag(parse_maybe_report_ambiguous_plus)]
 pub(crate) struct AmbiguousPlus {
-    pub sum_ty: String,
     #[primary_span]
-    #[suggestion(code = "({sum_ty})")]
     pub span: Span,
+    #[subdiagnostic]
+    pub suggestion: AddParen,
 }
 
 #[derive(Diagnostic)]
@@ -35,16 +35,19 @@ pub(crate) struct BadTypePlus {
 }
 
 #[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_add_paren, applicability = "machine-applicable")]
+pub(crate) struct AddParen {
+    #[suggestion_part(code = "(")]
+    pub lo: Span,
+    #[suggestion_part(code = ")")]
+    pub hi: Span,
+}
+
+#[derive(Subdiagnostic)]
 pub(crate) enum BadTypePlusSub {
-    #[suggestion(
-        parse_add_paren,
-        code = "{sum_with_parens}",
-        applicability = "machine-applicable"
-    )]
     AddParen {
-        sum_with_parens: String,
-        #[primary_span]
-        span: Span,
+        #[subdiagnostic]
+        suggestion: AddParen,
     },
     #[label(parse_forgot_paren)]
     ForgotParen {
@@ -80,7 +83,7 @@ pub(crate) struct WrapType {
 #[diag(parse_incorrect_semicolon)]
 pub(crate) struct IncorrectSemicolon<'a> {
     #[primary_span]
-    #[suggestion(style = "short", code = "", applicability = "machine-applicable")]
+    #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
     pub span: Span,
     #[help]
     pub show_help: bool,
@@ -91,7 +94,12 @@ pub(crate) struct IncorrectSemicolon<'a> {
 #[diag(parse_incorrect_use_of_await)]
 pub(crate) struct IncorrectUseOfAwait {
     #[primary_span]
-    #[suggestion(parse_parentheses_suggestion, code = "", applicability = "machine-applicable")]
+    #[suggestion(
+        parse_parentheses_suggestion,
+        style = "verbose",
+        code = "",
+        applicability = "machine-applicable"
+    )]
     pub span: Span,
 }
 
@@ -100,7 +108,11 @@ pub(crate) struct IncorrectUseOfAwait {
 pub(crate) struct IncorrectAwait {
     #[primary_span]
     pub span: Span,
-    #[suggestion(parse_postfix_suggestion, code = "{expr}.await{question_mark}")]
+    #[suggestion(
+        parse_postfix_suggestion,
+        style = "verbose",
+        code = "{expr}.await{question_mark}"
+    )]
     pub sugg_span: (Span, Applicability),
     pub expr: String,
     pub question_mark: &'static str,
@@ -111,7 +123,7 @@ pub(crate) struct IncorrectAwait {
 pub(crate) struct InInTypo {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", style = "verbose", applicability = "machine-applicable")]
     pub sugg_span: Span,
 }
 
@@ -126,17 +138,33 @@ pub(crate) struct InvalidVariableDeclaration {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum InvalidVariableDeclarationSub {
-    #[suggestion(parse_switch_mut_let_order, applicability = "maybe-incorrect", code = "let mut")]
+    #[suggestion(
+        parse_switch_mut_let_order,
+        style = "verbose",
+        applicability = "maybe-incorrect",
+        code = "let mut"
+    )]
     SwitchMutLetOrder(#[primary_span] Span),
     #[suggestion(
         parse_missing_let_before_mut,
         applicability = "machine-applicable",
+        style = "verbose",
         code = "let mut"
     )]
     MissingLet(#[primary_span] Span),
-    #[suggestion(parse_use_let_not_auto, applicability = "machine-applicable", code = "let")]
+    #[suggestion(
+        parse_use_let_not_auto,
+        style = "verbose",
+        applicability = "machine-applicable",
+        code = "let"
+    )]
     UseLetNotAuto(#[primary_span] Span),
-    #[suggestion(parse_use_let_not_var, applicability = "machine-applicable", code = "let")]
+    #[suggestion(
+        parse_use_let_not_var,
+        style = "verbose",
+        applicability = "machine-applicable",
+        code = "let"
+    )]
     UseLetNotVar(#[primary_span] Span),
 }
 
@@ -144,7 +172,7 @@ pub(crate) enum InvalidVariableDeclarationSub {
 #[diag(parse_switch_ref_box_order)]
 pub(crate) struct SwitchRefBoxOrder {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "box ref")]
+    #[suggestion(applicability = "machine-applicable", style = "verbose", code = "box ref")]
     pub span: Span,
 }
 
@@ -162,7 +190,7 @@ pub(crate) struct InvalidComparisonOperator {
 pub(crate) enum InvalidComparisonOperatorSub {
     #[suggestion(
         parse_use_instead,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "{correct}"
     )]
@@ -191,14 +219,14 @@ pub(crate) struct InvalidLogicalOperator {
 pub(crate) enum InvalidLogicalOperatorSub {
     #[suggestion(
         parse_use_amp_amp_for_conjunction,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "&&"
     )]
     Conjunction(#[primary_span] Span),
     #[suggestion(
         parse_use_pipe_pipe_for_disjunction,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "||"
     )]
@@ -209,7 +237,7 @@ pub(crate) enum InvalidLogicalOperatorSub {
 #[diag(parse_tilde_is_not_unary_operator)]
 pub(crate) struct TildeAsUnaryOperator(
     #[primary_span]
-    #[suggestion(style = "short", applicability = "machine-applicable", code = "!")]
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = "!")]
     pub Span,
 );
 
@@ -227,7 +255,7 @@ pub(crate) struct NotAsNegationOperator {
 pub enum NotAsNegationOperatorSub {
     #[suggestion(
         parse_unexpected_token_after_not_default,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "!"
     )]
@@ -235,7 +263,7 @@ pub enum NotAsNegationOperatorSub {
 
     #[suggestion(
         parse_unexpected_token_after_not_bitwise,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "!"
     )]
@@ -243,7 +271,7 @@ pub enum NotAsNegationOperatorSub {
 
     #[suggestion(
         parse_unexpected_token_after_not_logical,
-        style = "short",
+        style = "verbose",
         applicability = "machine-applicable",
         code = "!"
     )]
@@ -254,9 +282,9 @@ pub enum NotAsNegationOperatorSub {
 #[diag(parse_malformed_loop_label)]
 pub(crate) struct MalformedLoopLabel {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "{correct_label}")]
     pub span: Span,
-    pub correct_label: Ident,
+    #[suggestion(applicability = "machine-applicable", code = "'", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -264,7 +292,7 @@ pub(crate) struct MalformedLoopLabel {
 pub(crate) struct LifetimeInBorrowExpression {
     #[primary_span]
     pub span: Span,
-    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     #[label]
     pub lifetime_span: Span,
 }
@@ -306,7 +334,7 @@ pub(crate) struct RequireColonAfterLabeledExpression {
     pub span: Span,
     #[label]
     pub label: Span,
-    #[suggestion(style = "short", applicability = "machine-applicable", code = ": ")]
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = ": ")]
     pub label_end: Span,
 }
 
@@ -315,7 +343,7 @@ pub(crate) struct RequireColonAfterLabeledExpression {
 #[note]
 pub(crate) struct DoCatchSyntaxRemoved {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "try")]
+    #[suggestion(applicability = "machine-applicable", code = "try", style = "verbose")]
     pub span: Span,
 }
 
@@ -323,9 +351,9 @@ pub(crate) struct DoCatchSyntaxRemoved {
 #[diag(parse_float_literal_requires_integer_part)]
 pub(crate) struct FloatLiteralRequiresIntegerPart {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "{correct}")]
     pub span: Span,
-    pub correct: String,
+    #[suggestion(applicability = "machine-applicable", code = "0", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -394,7 +422,12 @@ pub struct TernaryOperator {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_extra_if_in_let_else, applicability = "maybe-incorrect", code = "")]
+#[suggestion(
+    parse_extra_if_in_let_else,
+    applicability = "maybe-incorrect",
+    code = "",
+    style = "verbose"
+)]
 pub(crate) struct IfExpressionLetSomeSub {
     #[primary_span]
     pub if_span: Span,
@@ -463,7 +496,7 @@ pub(crate) struct ExpectedElseBlock {
     pub first_tok: String,
     #[label]
     pub else_span: Span,
-    #[suggestion(applicability = "maybe-incorrect", code = "if ")]
+    #[suggestion(applicability = "maybe-incorrect", code = "if ", style = "verbose")]
     pub condition_start: Span,
 }
 
@@ -491,7 +524,7 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse {
     pub ctx_span: Span,
     pub ctx: String,
 
-    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     pub attributes: Span,
 }
 
@@ -509,12 +542,17 @@ pub(crate) enum MissingInInForLoopSub {
     // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
     #[suggestion(
         parse_use_in_not_of,
-        style = "short",
+        style = "verbose",
         applicability = "maybe-incorrect",
         code = "in"
     )]
     InNotOf(#[primary_span] Span),
-    #[suggestion(parse_add_in, style = "short", applicability = "maybe-incorrect", code = " in ")]
+    #[suggestion(
+        parse_add_in,
+        style = "verbose",
+        applicability = "maybe-incorrect",
+        code = " in "
+    )]
     AddIn(#[primary_span] Span),
 }
 
@@ -545,7 +583,7 @@ pub(crate) struct LoopElseNotSupported {
 #[diag(parse_missing_comma_after_match_arm)]
 pub(crate) struct MissingCommaAfterMatchArm {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = ",")]
+    #[suggestion(applicability = "machine-applicable", code = ",", style = "verbose")]
     pub span: Span,
 }
 
@@ -563,7 +601,7 @@ pub(crate) struct CatchAfterTry {
 pub(crate) struct CommaAfterBaseStruct {
     #[primary_span]
     pub span: Span,
-    #[suggestion(style = "short", applicability = "machine-applicable", code = "")]
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")]
     pub comma: Span,
 }
 
@@ -572,7 +610,7 @@ pub(crate) struct CommaAfterBaseStruct {
 pub(crate) struct EqFieldInit {
     #[primary_span]
     pub span: Span,
-    #[suggestion(applicability = "machine-applicable", code = ":")]
+    #[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")]
     pub eq: Span,
 }
 
@@ -580,8 +618,18 @@ pub(crate) struct EqFieldInit {
 #[diag(parse_dotdotdot)]
 pub(crate) struct DotDotDot {
     #[primary_span]
-    #[suggestion(parse_suggest_exclusive_range, applicability = "maybe-incorrect", code = "..")]
-    #[suggestion(parse_suggest_inclusive_range, applicability = "maybe-incorrect", code = "..=")]
+    #[suggestion(
+        parse_suggest_exclusive_range,
+        applicability = "maybe-incorrect",
+        code = "..",
+        style = "verbose"
+    )]
+    #[suggestion(
+        parse_suggest_inclusive_range,
+        applicability = "maybe-incorrect",
+        code = "..=",
+        style = "verbose"
+    )]
     pub span: Span,
 }
 
@@ -589,7 +637,7 @@ pub(crate) struct DotDotDot {
 #[diag(parse_left_arrow_operator)]
 pub(crate) struct LeftArrowOperator {
     #[primary_span]
-    #[suggestion(applicability = "maybe-incorrect", code = "< -")]
+    #[suggestion(applicability = "maybe-incorrect", code = "< -", style = "verbose")]
     pub span: Span,
 }
 
@@ -597,7 +645,7 @@ pub(crate) struct LeftArrowOperator {
 #[diag(parse_remove_let)]
 pub(crate) struct RemoveLet {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "")]
+    #[suggestion(applicability = "machine-applicable", code = "", style = "verbose")]
     pub span: Span,
 }
 
@@ -605,8 +653,9 @@ pub(crate) struct RemoveLet {
 #[diag(parse_use_eq_instead)]
 pub(crate) struct UseEqInstead {
     #[primary_span]
-    #[suggestion(style = "short", applicability = "machine-applicable", code = "=")]
     pub span: Span,
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -780,7 +829,7 @@ pub(crate) struct InclusiveRangeExtraEquals {
     #[primary_span]
     #[suggestion(
         parse_suggestion_remove_eq,
-        style = "short",
+        style = "verbose",
         code = "..=",
         applicability = "maybe-incorrect"
     )]
@@ -803,13 +852,14 @@ pub(crate) struct InclusiveRangeMatchArrow {
 #[note]
 pub(crate) struct InclusiveRangeNoEnd {
     #[primary_span]
+    pub span: Span,
     #[suggestion(
         parse_suggestion_open_range,
-        code = "..",
+        code = "",
         applicability = "machine-applicable",
-        style = "short"
+        style = "verbose"
     )]
-    pub span: Span,
+    pub suggestion: Span,
 }
 
 #[derive(Subdiagnostic)]
@@ -824,7 +874,8 @@ pub(crate) enum MatchArmBodyWithoutBracesSugg {
     #[suggestion(
         parse_suggestion_use_comma_not_semicolon,
         code = ",",
-        applicability = "machine-applicable"
+        applicability = "machine-applicable",
+        style = "verbose"
     )]
     UseComma {
         #[primary_span]
@@ -867,7 +918,7 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
 #[diag(parse_non_string_abi_literal)]
 pub(crate) struct NonStringAbiLiteral {
     #[primary_span]
-    #[suggestion(code = "\"C\"", applicability = "maybe-incorrect")]
+    #[suggestion(code = "\"C\"", applicability = "maybe-incorrect", style = "verbose")]
     pub span: Span,
 }
 
@@ -890,7 +941,7 @@ pub(crate) struct MismatchedClosingDelimiter {
 #[help]
 pub(crate) struct IncorrectVisibilityRestriction {
     #[primary_span]
-    #[suggestion(code = "in {inner_str}", applicability = "machine-applicable")]
+    #[suggestion(code = "in {inner_str}", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub inner_str: String,
 }
@@ -915,7 +966,7 @@ pub(crate) struct ExpectedStatementAfterOuterAttr {
 pub(crate) struct DocCommentDoesNotDocumentAnything {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = ",", applicability = "machine-applicable")]
+    #[suggestion(code = ",", applicability = "machine-applicable", style = "verbose")]
     pub missing_comma: Option<Span>,
 }
 
@@ -923,7 +974,7 @@ pub(crate) struct DocCommentDoesNotDocumentAnything {
 #[diag(parse_const_let_mutually_exclusive)]
 pub(crate) struct ConstLetMutuallyExclusive {
     #[primary_span]
-    #[suggestion(code = "const", applicability = "maybe-incorrect")]
+    #[suggestion(code = "const", applicability = "maybe-incorrect", style = "verbose")]
     pub span: Span,
 }
 
@@ -951,8 +1002,9 @@ pub(crate) struct InvalidCurlyInLetElse {
 #[help]
 pub(crate) struct CompoundAssignmentExpressionInLet {
     #[primary_span]
-    #[suggestion(style = "short", code = "=", applicability = "maybe-incorrect")]
     pub span: Span,
+    #[suggestion(style = "verbose", code = "", applicability = "maybe-incorrect")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -996,7 +1048,12 @@ pub(crate) struct SuggEscapeIdentifier {
 }
 
 #[derive(Subdiagnostic)]
-#[suggestion(parse_sugg_remove_comma, applicability = "machine-applicable", code = "")]
+#[suggestion(
+    parse_sugg_remove_comma,
+    applicability = "machine-applicable",
+    code = "",
+    style = "verbose"
+)]
 pub(crate) struct SuggRemoveComma {
     #[primary_span]
     pub span: Span,
@@ -1147,11 +1204,16 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum ExpectedSemiSugg {
-    #[suggestion(parse_sugg_change_this_to_semi, code = ";", applicability = "machine-applicable")]
+    #[suggestion(
+        parse_sugg_change_this_to_semi,
+        code = ";",
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
     ChangeToSemi(#[primary_span] Span),
     #[suggestion(
         parse_sugg_add_semi,
-        style = "short",
+        style = "verbose",
         code = ";",
         applicability = "machine-applicable"
     )]
@@ -1198,7 +1260,7 @@ pub(crate) struct StructLiteralNeedingParensSugg {
 #[diag(parse_unmatched_angle_brackets)]
 pub(crate) struct UnmatchedAngleBrackets {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub num_extra_brackets: usize,
 }
@@ -1337,7 +1399,7 @@ pub(crate) struct AttributeOnParamType {
 #[diag(parse_pattern_method_param_without_body, code = E0642)]
 pub(crate) struct PatternMethodParamWithoutBody {
     #[primary_span]
-    #[suggestion(code = "_", applicability = "machine-applicable")]
+    #[suggestion(code = "_", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -1421,7 +1483,7 @@ pub(crate) struct AsyncMoveOrderIncorrect {
 pub(crate) struct DoubleColonInBound {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = ": ", applicability = "machine-applicable")]
+    #[suggestion(code = ": ", applicability = "machine-applicable", style = "verbose")]
     pub between: Span,
 }
 
@@ -1500,7 +1562,7 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword {
 #[diag(parse_path_single_colon)]
 pub(crate) struct PathSingleColon {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "::")]
+    #[suggestion(applicability = "machine-applicable", code = "::", style = "verbose")]
     pub span: Span,
 
     #[note(parse_type_ascription_removed)]
@@ -1511,7 +1573,7 @@ pub(crate) struct PathSingleColon {
 #[diag(parse_colon_as_semi)]
 pub(crate) struct ColonAsSemi {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = ";")]
+    #[suggestion(applicability = "machine-applicable", code = ";", style = "verbose")]
     pub span: Span,
 
     #[note(parse_type_ascription_removed)]
@@ -1662,9 +1724,9 @@ pub(crate) enum MissingKeywordForItemDefinition {
 pub(crate) enum AmbiguousMissingKwForItemSub {
     #[suggestion(
         parse_suggestion,
-        style = "verbose",
         applicability = "maybe-incorrect",
-        code = "{snippet}!"
+        code = "{snippet}!",
+        style = "verbose"
     )]
     SuggestMacro {
         #[primary_span]
@@ -1679,7 +1741,7 @@ pub(crate) enum AmbiguousMissingKwForItemSub {
 #[diag(parse_missing_fn_params)]
 pub(crate) struct MissingFnParams {
     #[primary_span]
-    #[suggestion(code = "()", applicability = "machine-applicable", style = "short")]
+    #[suggestion(code = "()", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -1687,9 +1749,19 @@ pub(crate) struct MissingFnParams {
 #[diag(parse_missing_trait_in_trait_impl)]
 pub(crate) struct MissingTraitInTraitImpl {
     #[primary_span]
-    #[suggestion(parse_suggestion_add_trait, code = " Trait ", applicability = "has-placeholders")]
+    #[suggestion(
+        parse_suggestion_add_trait,
+        code = " Trait ",
+        applicability = "has-placeholders",
+        style = "verbose"
+    )]
     pub span: Span,
-    #[suggestion(parse_suggestion_remove_for, code = "", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_suggestion_remove_for,
+        code = "",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     pub for_span: Span,
 }
 
@@ -1697,7 +1769,7 @@ pub(crate) struct MissingTraitInTraitImpl {
 #[diag(parse_missing_for_in_trait_impl)]
 pub(crate) struct MissingForInTraitImpl {
     #[primary_span]
-    #[suggestion(style = "short", code = " for ", applicability = "machine-applicable")]
+    #[suggestion(style = "verbose", code = " for ", applicability = "machine-applicable")]
     pub span: Span,
 }
 
@@ -1712,7 +1784,7 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType {
 #[diag(parse_extra_impl_keyword_in_trait_impl)]
 pub(crate) struct ExtraImplKeywordInTraitImpl {
     #[primary_span]
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub extra_impl_kw: Span,
     #[note]
     pub impl_trait_span: Span,
@@ -1771,7 +1843,7 @@ pub(crate) struct ExternCrateNameWithDashesSugg {
 pub(crate) struct ExternItemCannotBeConst {
     #[primary_span]
     pub ident_span: Span,
-    #[suggestion(code = "static ", applicability = "machine-applicable")]
+    #[suggestion(code = "static ", applicability = "machine-applicable", style = "verbose")]
     pub const_span: Option<Span>,
 }
 
@@ -1781,7 +1853,7 @@ pub(crate) struct ConstGlobalCannotBeMutable {
     #[primary_span]
     #[label]
     pub ident_span: Span,
-    #[suggestion(code = "static", applicability = "maybe-incorrect")]
+    #[suggestion(code = "static", style = "verbose", applicability = "maybe-incorrect")]
     pub const_span: Span,
 }
 
@@ -1789,7 +1861,7 @@ pub(crate) struct ConstGlobalCannotBeMutable {
 #[diag(parse_missing_const_type)]
 pub(crate) struct MissingConstType {
     #[primary_span]
-    #[suggestion(code = "{colon} <type>", applicability = "has-placeholders")]
+    #[suggestion(code = "{colon} <type>", style = "verbose", applicability = "has-placeholders")]
     pub span: Span,
 
     pub kind: &'static str,
@@ -1800,7 +1872,7 @@ pub(crate) struct MissingConstType {
 #[diag(parse_enum_struct_mutually_exclusive)]
 pub(crate) struct EnumStructMutuallyExclusive {
     #[primary_span]
-    #[suggestion(code = "enum", applicability = "machine-applicable")]
+    #[suggestion(code = "enum", style = "verbose", applicability = "machine-applicable")]
     pub span: Span,
 }
 
@@ -2037,7 +2109,12 @@ pub struct UnknownTokenStart {
 
 #[derive(Subdiagnostic)]
 pub enum TokenSubstitution {
-    #[suggestion(parse_sugg_quotes, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_sugg_quotes,
+        code = "{suggestion}",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     DirectedQuotes {
         #[primary_span]
         span: Span,
@@ -2045,7 +2122,12 @@ pub enum TokenSubstitution {
         ascii_str: &'static str,
         ascii_name: &'static str,
     },
-    #[suggestion(parse_sugg_other, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_sugg_other,
+        code = "{suggestion}",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     Other {
         #[primary_span]
         span: Span,
@@ -2081,7 +2163,12 @@ pub enum UnescapeError {
     EscapeOnlyChar {
         #[primary_span]
         span: Span,
-        #[suggestion(parse_escape, applicability = "machine-applicable", code = "{escaped_sugg}")]
+        #[suggestion(
+            parse_escape,
+            applicability = "machine-applicable",
+            code = "{escaped_sugg}",
+            style = "verbose"
+        )]
         char_span: Span,
         escaped_sugg: String,
         escaped_msg: String,
@@ -2090,7 +2177,12 @@ pub enum UnescapeError {
     #[diag(parse_bare_cr)]
     BareCr {
         #[primary_span]
-        #[suggestion(parse_escape, applicability = "machine-applicable", code = "\\r")]
+        #[suggestion(
+            parse_escape,
+            applicability = "machine-applicable",
+            code = "\\r",
+            style = "verbose"
+        )]
         span: Span,
         double_quotes: bool,
     },
@@ -2207,7 +2299,8 @@ pub enum MoreThanOneCharSugg {
     #[suggestion(
         parse_consider_normalized,
         code = "{normalized}",
-        applicability = "machine-applicable"
+        applicability = "machine-applicable",
+        style = "verbose"
     )]
     NormalizedForm {
         #[primary_span]
@@ -2215,13 +2308,23 @@ pub enum MoreThanOneCharSugg {
         ch: String,
         normalized: String,
     },
-    #[suggestion(parse_remove_non, code = "{ch}", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_remove_non,
+        code = "{ch}",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     RemoveNonPrinting {
         #[primary_span]
         span: Span,
         ch: String,
     },
-    #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")]
+    #[suggestion(
+        parse_use_double_quotes,
+        code = "{sugg}",
+        applicability = "machine-applicable",
+        style = "verbose"
+    )]
     QuotesFull {
         #[primary_span]
         span: Span,
@@ -2259,7 +2362,12 @@ pub enum MoreThanOneCharNote {
 
 #[derive(Subdiagnostic)]
 pub enum NoBraceUnicodeSub {
-    #[suggestion(parse_use_braces, code = "{suggestion}", applicability = "maybe-incorrect")]
+    #[suggestion(
+        parse_use_braces,
+        code = "{suggestion}",
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
     Suggestion {
         #[primary_span]
         span: Span,
@@ -2270,26 +2378,31 @@ pub enum NoBraceUnicodeSub {
 }
 
 #[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_sugg_wrap_pattern_in_parens, applicability = "machine-applicable")]
+pub(crate) struct WrapInParens {
+    #[suggestion_part(code = "(")]
+    pub(crate) lo: Span,
+    #[suggestion_part(code = ")")]
+    pub(crate) hi: Span,
+}
+
+#[derive(Subdiagnostic)]
 pub(crate) enum TopLevelOrPatternNotAllowedSugg {
     #[suggestion(
         parse_sugg_remove_leading_vert_in_pattern,
-        code = "{pat}",
-        applicability = "machine-applicable"
+        code = "",
+        applicability = "machine-applicable",
+        style = "verbose"
     )]
     RemoveLeadingVert {
         #[primary_span]
         span: Span,
-        pat: String,
     },
-    #[suggestion(
-        parse_sugg_wrap_pattern_in_parens,
-        code = "({pat})",
-        applicability = "machine-applicable"
-    )]
     WrapInParens {
         #[primary_span]
         span: Span,
-        pat: String,
+        #[subdiagnostic]
+        suggestion: WrapInParens,
     },
 }
 
@@ -2298,7 +2411,7 @@ pub(crate) enum TopLevelOrPatternNotAllowedSugg {
 #[note(parse_note_pattern_alternatives_use_single_vert)]
 pub(crate) struct UnexpectedVertVertBeforeFunctionParam {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2306,7 +2419,7 @@ pub(crate) struct UnexpectedVertVertBeforeFunctionParam {
 #[diag(parse_unexpected_vert_vert_in_pattern)]
 pub(crate) struct UnexpectedVertVertInPattern {
     #[primary_span]
-    #[suggestion(code = "|", applicability = "machine-applicable")]
+    #[suggestion(code = "|", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     #[label(parse_label_while_parsing_or_pattern_here)]
     pub start: Option<Span>,
@@ -2316,7 +2429,7 @@ pub(crate) struct UnexpectedVertVertInPattern {
 #[diag(parse_trailing_vert_not_allowed)]
 pub(crate) struct TrailingVertNotAllowed {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     #[label(parse_label_while_parsing_or_pattern_here)]
     pub start: Option<Span>,
@@ -2329,16 +2442,17 @@ pub(crate) struct TrailingVertNotAllowed {
 #[diag(parse_dotdotdot_rest_pattern)]
 pub(crate) struct DotDotDotRestPattern {
     #[primary_span]
-    #[suggestion(style = "short", code = "..", applicability = "machine-applicable")]
     #[label]
     pub span: Span,
+    #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
 #[diag(parse_pattern_on_wrong_side_of_at)]
 pub(crate) struct PatternOnWrongSideOfAt {
     #[primary_span]
-    #[suggestion(code = "{whole_pat}", applicability = "machine-applicable")]
+    #[suggestion(code = "{whole_pat}", applicability = "machine-applicable", style = "verbose")]
     pub whole_span: Span,
     pub whole_pat: String,
     #[label(parse_label_pattern)]
@@ -2359,22 +2473,35 @@ pub(crate) struct ExpectedBindingLeftOfAt {
     pub rhs: Span,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    parse_ambiguous_range_pattern_suggestion,
+    applicability = "machine-applicable"
+)]
+pub(crate) struct ParenRangeSuggestion {
+    #[suggestion_part(code = "(")]
+    pub lo: Span,
+    #[suggestion_part(code = ")")]
+    pub hi: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_ambiguous_range_pattern)]
 pub(crate) struct AmbiguousRangePattern {
     #[primary_span]
-    #[suggestion(code = "({pat})", applicability = "maybe-incorrect")]
     pub span: Span,
-    pub pat: String,
+    #[subdiagnostic]
+    pub suggestion: ParenRangeSuggestion,
 }
 
 #[derive(Diagnostic)]
 #[diag(parse_unexpected_lifetime_in_pattern)]
 pub(crate) struct UnexpectedLifetimeInPattern {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
     pub span: Span,
     pub symbol: Symbol,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -2383,7 +2510,7 @@ pub(crate) enum InvalidMutInPattern {
     #[note(parse_note_mut_pattern_usage)]
     NestedIdent {
         #[primary_span]
-        #[suggestion(code = "{pat}", applicability = "machine-applicable")]
+        #[suggestion(code = "{pat}", applicability = "machine-applicable", style = "verbose")]
         span: Span,
         pat: String,
     },
@@ -2391,7 +2518,7 @@ pub(crate) enum InvalidMutInPattern {
     #[note(parse_note_mut_pattern_usage)]
     NonIdent {
         #[primary_span]
-        #[suggestion(code = "", applicability = "machine-applicable")]
+        #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
         span: Span,
     },
 }
@@ -2400,7 +2527,7 @@ pub(crate) enum InvalidMutInPattern {
 #[diag(parse_repeated_mut_in_pattern)]
 pub(crate) struct RepeatedMutInPattern {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2408,7 +2535,7 @@ pub(crate) struct RepeatedMutInPattern {
 #[diag(parse_dot_dot_dot_range_to_pattern_not_allowed)]
 pub(crate) struct DotDotDotRangeToPatternNotAllowed {
     #[primary_span]
-    #[suggestion(style = "short", code = "..=", applicability = "machine-applicable")]
+    #[suggestion(style = "verbose", code = "..=", applicability = "machine-applicable")]
     pub span: Span,
 }
 
@@ -2472,8 +2599,9 @@ pub(crate) struct UnexpectedParenInRangePatSugg {
 #[diag(parse_return_types_use_thin_arrow)]
 pub(crate) struct ReturnTypesUseThinArrow {
     #[primary_span]
-    #[suggestion(style = "short", code = "->", applicability = "machine-applicable")]
     pub span: Span,
+    #[suggestion(style = "verbose", code = " -> ", applicability = "machine-applicable")]
+    pub suggestion: Span,
 }
 
 #[derive(Diagnostic)]
@@ -2488,7 +2616,7 @@ pub(crate) struct NeedPlusAfterTraitObjectLifetime {
 pub(crate) struct ExpectedMutOrConstInRawPointerType {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code("mut ", "const "), applicability = "has-placeholders")]
+    #[suggestion(code("mut ", "const "), applicability = "has-placeholders", style = "verbose")]
     pub after_asterisk: Span,
 }
 
@@ -2497,7 +2625,7 @@ pub(crate) struct ExpectedMutOrConstInRawPointerType {
 pub(crate) struct LifetimeAfterMut {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect")]
+    #[suggestion(code = "&{snippet} mut", applicability = "maybe-incorrect", style = "verbose")]
     pub suggest_lifetime: Option<Span>,
     pub snippet: String,
 }
@@ -2506,7 +2634,7 @@ pub(crate) struct LifetimeAfterMut {
 #[diag(parse_dyn_after_mut)]
 pub(crate) struct DynAfterMut {
     #[primary_span]
-    #[suggestion(code = "&mut dyn", applicability = "machine-applicable")]
+    #[suggestion(code = "&mut dyn", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2515,7 +2643,7 @@ pub(crate) struct DynAfterMut {
 pub(crate) struct FnPointerCannotBeConst {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     #[label]
     pub qualifier: Span,
 }
@@ -2525,7 +2653,7 @@ pub(crate) struct FnPointerCannotBeConst {
 pub(crate) struct FnPointerCannotBeAsync {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     #[label]
     pub qualifier: Span,
 }
@@ -2542,8 +2670,9 @@ pub(crate) struct NestedCVariadicType {
 #[help]
 pub(crate) struct InvalidDynKeyword {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
     pub span: Span,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
+    pub suggestion: Span,
 }
 
 #[derive(Subdiagnostic)]
@@ -2584,7 +2713,7 @@ pub struct BoxSyntaxRemoved<'a> {
 #[diag(parse_bad_return_type_notation_output)]
 pub(crate) struct BadReturnTypeNotationOutput {
     #[primary_span]
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub span: Span,
 }
 
@@ -2655,14 +2784,25 @@ pub(crate) struct ModifierLifetime {
     pub modifier: &'static str,
 }
 
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    parse_parenthesized_lifetime_suggestion,
+    applicability = "machine-applicable"
+)]
+pub(crate) struct RemoveParens {
+    #[suggestion_part(code = "")]
+    pub lo: Span,
+    #[suggestion_part(code = "")]
+    pub hi: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(parse_parenthesized_lifetime)]
 pub(crate) struct ParenthesizedLifetime {
     #[primary_span]
     pub span: Span,
-    #[suggestion(style = "short", applicability = "machine-applicable", code = "{snippet}")]
-    pub sugg: Option<Span>,
-    pub snippet: String,
+    #[subdiagnostic]
+    pub sugg: RemoveParens,
 }
 
 #[derive(Diagnostic)]
@@ -2677,7 +2817,7 @@ pub(crate) struct UnderscoreLiteralSuffix {
 pub(crate) struct ExpectedLabelFoundIdent {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "'", applicability = "machine-applicable", style = "short")]
+    #[suggestion(code = "'", applicability = "machine-applicable", style = "verbose")]
     pub start: Span,
 }
 
@@ -2696,7 +2836,7 @@ pub(crate) struct InappropriateDefault {
 #[diag(parse_recover_import_as_use)]
 pub(crate) struct RecoverImportAsUse {
     #[primary_span]
-    #[suggestion(code = "use", applicability = "machine-applicable", style = "short")]
+    #[suggestion(code = "use", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub token_name: String,
 }
@@ -2706,7 +2846,7 @@ pub(crate) struct RecoverImportAsUse {
 #[note]
 pub(crate) struct SingleColonImportPath {
     #[primary_span]
-    #[suggestion(code = "::", applicability = "machine-applicable", style = "short")]
+    #[suggestion(code = "::", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2733,7 +2873,7 @@ pub(crate) struct SingleColonStructType {
 #[diag(parse_equals_struct_default)]
 pub(crate) struct EqualsStructDefault {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2750,7 +2890,7 @@ pub(crate) struct MacroRulesMissingBang {
 #[diag(parse_macro_name_remove_bang)]
 pub(crate) struct MacroNameRemoveBang {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
 }
 
@@ -2758,7 +2898,7 @@ pub(crate) struct MacroNameRemoveBang {
 #[diag(parse_macro_rules_visibility)]
 pub(crate) struct MacroRulesVisibility<'a> {
     #[primary_span]
-    #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect")]
+    #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect", style = "verbose")]
     pub span: Span,
     pub vis: &'a str,
 }
@@ -2768,7 +2908,7 @@ pub(crate) struct MacroRulesVisibility<'a> {
 #[help]
 pub(crate) struct MacroInvocationVisibility<'a> {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub vis: &'a str,
 }
@@ -2778,7 +2918,7 @@ pub(crate) struct MacroInvocationVisibility<'a> {
 pub(crate) struct NestedAdt<'a> {
     #[primary_span]
     pub span: Span,
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
+    #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")]
     pub item: Span,
     pub keyword: &'a str,
     pub kw_str: Cow<'a, str>,
@@ -2818,7 +2958,7 @@ pub(crate) struct BoxNotPat {
 #[diag(parse_unmatched_angle)]
 pub(crate) struct UnmatchedAngle {
     #[primary_span]
-    #[suggestion(code = "", applicability = "machine-applicable")]
+    #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
     pub span: Span,
     pub plural: bool,
 }
@@ -2858,7 +2998,7 @@ pub(crate) struct IncorrectParensTraitBoundsSugg {
 #[diag(parse_kw_bad_case)]
 pub(crate) struct KwBadCase<'a> {
     #[primary_span]
-    #[suggestion(code = "{kw}", applicability = "machine-applicable")]
+    #[suggestion(code = "{kw}", style = "verbose", applicability = "machine-applicable")]
     pub span: Span,
     pub kw: &'a str,
 }
@@ -2895,7 +3035,7 @@ pub(crate) struct MetaBadDelimSugg {
 #[note]
 pub(crate) struct MalformedCfgAttr {
     #[primary_span]
-    #[suggestion(code = "{sugg}")]
+    #[suggestion(style = "verbose", code = "{sugg}")]
     pub span: Span,
     pub sugg: &'static str,
 }
@@ -3000,7 +3140,7 @@ pub(crate) struct AsyncImpl {
 #[help]
 pub(crate) struct ExprRArrowCall {
     #[primary_span]
-    #[suggestion(style = "short", applicability = "machine-applicable", code = ".")]
+    #[suggestion(style = "verbose", applicability = "machine-applicable", code = ".")]
     pub span: Span,
 }
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 81d5f0fca0e..63e4d8a4352 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -3,8 +3,8 @@ use super::{
     BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenType,
 };
 use crate::errors::{
-    AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2, BadTypePlus,
-    BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
+    AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, BadQPathStage2,
+    BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained,
     ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces,
     ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
     DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
@@ -566,7 +566,10 @@ impl<'a> Parser<'a> {
             && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
         {
             // Likely typo: `=` → `==` in let expr or enum item
-            return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
+            return Err(self.dcx().create_err(UseEqInstead {
+                span: self.token.span,
+                suggestion: self.token.span.with_lo(self.token.span.lo() + BytePos(1)),
+            }));
         }
 
         if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) {
@@ -1151,7 +1154,7 @@ impl<'a> Parser<'a> {
             // Eat from where we started until the end token so that parsing can continue
             // as if we didn't have those extra angle brackets.
             self.eat_to_tokens(end);
-            let span = lo.until(self.token.span);
+            let span = lo.to(self.prev_token.span);
 
             let num_extra_brackets = number_of_gt + number_of_shr * 2;
             return Some(self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets }));
@@ -1539,7 +1542,10 @@ impl<'a> Parser<'a> {
 
     pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
         if impl_dyn_multi {
-            self.dcx().emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(ty), span: ty.span });
+            self.dcx().emit_err(AmbiguousPlus {
+                span: ty.span,
+                suggestion: AddParen { lo: ty.span.shrink_to_lo(), hi: ty.span.shrink_to_hi() },
+            });
         }
     }
 
@@ -1608,21 +1614,10 @@ impl<'a> Parser<'a> {
         let sum_span = ty.span.to(self.prev_token.span);
 
         let sub = match &ty.kind {
-            TyKind::Ref(lifetime, mut_ty) => {
-                let sum_with_parens = pprust::to_string(|s| {
-                    s.s.word("&");
-                    s.print_opt_lifetime(lifetime);
-                    s.print_mutability(mut_ty.mutbl, false);
-                    s.popen();
-                    s.print_type(&mut_ty.ty);
-                    if !bounds.is_empty() {
-                        s.word(" + ");
-                        s.print_type_bounds(&bounds);
-                    }
-                    s.pclose()
-                });
-
-                BadTypePlusSub::AddParen { sum_with_parens, span: sum_span }
+            TyKind::Ref(_lifetime, mut_ty) => {
+                let lo = mut_ty.ty.span.shrink_to_lo();
+                let hi = self.prev_token.span.shrink_to_hi();
+                BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
             }
             TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span },
             _ => BadTypePlusSub::ExpectPath { span: sum_span },
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index b2df9a14eb0..4bd20be4171 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -714,7 +714,7 @@ impl<'a> Parser<'a> {
                                 type_err.cancel();
                                 self.dcx().emit_err(errors::MalformedLoopLabel {
                                     span: label.ident.span,
-                                    correct_label: label.ident,
+                                    suggestion: label.ident.span.shrink_to_lo(),
                                 });
                                 return Ok(expr);
                             }
@@ -856,7 +856,7 @@ impl<'a> Parser<'a> {
         let hi = self.interpolated_or_expr_span(&expr);
         let span = lo.to(hi);
         if let Some(lt) = lifetime {
-            self.error_remove_borrow_lifetime(span, lt.ident.span);
+            self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
         }
         Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
     }
@@ -1653,6 +1653,7 @@ impl<'a> Parser<'a> {
         let lo = label_.ident.span;
         let label = Some(label_);
         let ate_colon = self.eat(&token::Colon);
+        let tok_sp = self.token.span;
         let expr = if self.eat_keyword(kw::While) {
             self.parse_expr_while(label, lo)
         } else if self.eat_keyword(kw::For) {
@@ -1747,7 +1748,7 @@ impl<'a> Parser<'a> {
             self.dcx().emit_err(errors::RequireColonAfterLabeledExpression {
                 span: expr.span,
                 label: lo,
-                label_end: lo.shrink_to_hi(),
+                label_end: lo.between(tok_sp),
             });
         }
 
@@ -2106,7 +2107,7 @@ impl<'a> Parser<'a> {
                 self.bump();
                 self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart {
                     span: token.span,
-                    correct: pprust::token_to_string(token).into_owned(),
+                    suggestion: token.span.shrink_to_lo(),
                 });
             }
         }
@@ -2741,7 +2742,7 @@ impl<'a> Parser<'a> {
         if !attrs.is_empty()
             && let [x0 @ xn] | [x0, .., xn] = &*attrs.take_for_recovery(self.psess)
         {
-            let attributes = x0.span.to(xn.span);
+            let attributes = x0.span.until(branch_span);
             let last = xn.span;
             let ctx = if is_ctx_else { "else" } else { "if" };
             self.dcx().emit_err(errors::OuterAttributeNotAllowedOnIfElse {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 2c98feeece7..81e2ca2a490 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2241,9 +2241,13 @@ impl<'a> Parser<'a> {
             let kw_token = self.token.clone();
             let kw_str = pprust::token_to_string(&kw_token);
             let item = self.parse_item(ForceCollect::No)?;
+            let mut item = item.unwrap().span;
+            if self.token == token::Comma {
+                item = item.to(self.token.span);
+            }
             self.dcx().emit_err(errors::NestedAdt {
                 span: kw_token.span,
-                item: item.unwrap().span,
+                item,
                 kw_str,
                 keyword: keyword.as_str(),
             });
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 6f2b7177159..e4e89615d71 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -4,11 +4,11 @@ use crate::errors::{
     DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
     ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
     InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
-    PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder,
-    TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed,
-    UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
-    UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
-    UnexpectedVertVertInPattern,
+    ParenRangeSuggestion, PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern,
+    SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
+    TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
+    UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
+    UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
 };
 use crate::parser::expr::{could_be_unclosed_char_literal, LhsExpr};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -24,7 +24,7 @@ use rustc_errors::{Applicability, Diag, PResult};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{ErrorGuaranteed, Span};
+use rustc_span::{BytePos, ErrorGuaranteed, Span};
 use thin_vec::{thin_vec, ThinVec};
 
 #[derive(PartialEq, Copy, Clone)]
@@ -236,11 +236,15 @@ impl<'a> Parser<'a> {
 
         if let PatKind::Or(pats) = &pat.kind {
             let span = pat.span;
-            let pat = pprust::pat_to_string(&pat);
             let sub = if pats.len() == 1 {
-                Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat })
+                Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert {
+                    span: span.with_hi(span.lo() + BytePos(1)),
+                })
             } else {
-                Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat })
+                Some(TopLevelOrPatternNotAllowedSugg::WrapInParens {
+                    span,
+                    suggestion: WrapInParens { lo: span.shrink_to_lo(), hi: span.shrink_to_hi() },
+                })
             };
 
             let err = self.dcx().create_err(match syntax_loc {
@@ -599,7 +603,10 @@ impl<'a> Parser<'a> {
         self.bump(); // `...`
 
         // The user probably mistook `...` for a rest pattern `..`.
-        self.dcx().emit_err(DotDotDotRestPattern { span: lo });
+        self.dcx().emit_err(DotDotDotRestPattern {
+            span: lo,
+            suggestion: lo.with_lo(lo.hi() - BytePos(1)),
+        });
         PatKind::Rest
     }
 
@@ -664,8 +671,13 @@ impl<'a> Parser<'a> {
             _ => return,
         }
 
-        self.dcx()
-            .emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(pat) });
+        self.dcx().emit_err(AmbiguousRangePattern {
+            span: pat.span,
+            suggestion: ParenRangeSuggestion {
+                lo: pat.span.shrink_to_lo(),
+                hi: pat.span.shrink_to_hi(),
+            },
+        });
     }
 
     /// Parse `&pat` / `&mut pat`.
@@ -674,8 +686,11 @@ impl<'a> Parser<'a> {
         if let token::Lifetime(name) = self.token.kind {
             self.bump(); // `'a`
 
-            self.dcx()
-                .emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name });
+            self.dcx().emit_err(UnexpectedLifetimeInPattern {
+                span: self.prev_token.span,
+                symbol: name,
+                suggestion: self.prev_token.span.until(self.token.span),
+            });
         }
 
         let mutbl = self.parse_mutability();
@@ -913,10 +928,13 @@ impl<'a> Parser<'a> {
                 self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq })
             }
             token::Gt if no_space => {
-                let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
+                let after_pat = span.with_hi(span.hi() - BytePos(1)).shrink_to_hi();
                 self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat })
             }
-            _ => self.dcx().emit_err(InclusiveRangeNoEnd { span }),
+            _ => self.dcx().emit_err(InclusiveRangeNoEnd {
+                span,
+                suggestion: span.with_lo(span.hi() - BytePos(1)),
+            }),
         }
     }
 
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index d65f6ff68ee..70d41de00a7 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -430,8 +430,10 @@ impl<'a> Parser<'a> {
         let eq_consumed = match self.token.kind {
             token::BinOpEq(..) => {
                 // Recover `let x <op>= 1` as `let x = 1`
-                self.dcx()
-                    .emit_err(errors::CompoundAssignmentExpressionInLet { span: self.token.span });
+                self.dcx().emit_err(errors::CompoundAssignmentExpressionInLet {
+                    span: self.token.span,
+                    suggestion: self.token.span.with_hi(self.token.span.lo() + BytePos(1)),
+                });
                 self.bump();
                 true
             }
@@ -717,7 +719,7 @@ impl<'a> Parser<'a> {
                                                 e.cancel();
                                                 self.dcx().emit_err(MalformedLoopLabel {
                                                     span: label.ident.span,
-                                                    correct_label: label.ident,
+                                                    suggestion: label.ident.span.shrink_to_lo(),
                                                 });
                                                 *expr = labeled_expr;
                                                 break 'break_recover None;
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 1e5b227aaa9..94321b1dddd 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -209,6 +209,7 @@ impl<'a> Parser<'a> {
         recover_qpath: RecoverQPath,
         recover_return_sign: RecoverReturnSign,
     ) -> PResult<'a, FnRetTy> {
+        let lo = self.prev_token.span;
         Ok(if self.eat(&token::RArrow) {
             // FIXME(Centril): Can we unconditionally `allow_plus`?
             let ty = self.parse_ty_common(
@@ -224,7 +225,10 @@ impl<'a> Parser<'a> {
             // Don't `eat` to prevent `=>` from being added as an expected token which isn't
             // actually expected and could only confuse users
             self.bump();
-            self.dcx().emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span });
+            self.dcx().emit_err(ReturnTypesUseThinArrow {
+                span: self.prev_token.span,
+                suggestion: lo.between(self.token.span),
+            });
             let ty = self.parse_ty_common(
                 allow_plus,
                 AllowCVariadic::No,
@@ -794,8 +798,11 @@ impl<'a> Parser<'a> {
         {
             if self.token.is_keyword(kw::Dyn) {
                 // Account for `&dyn Trait + dyn Other`.
-                self.dcx().emit_err(InvalidDynKeyword { span: self.token.span });
                 self.bump();
+                self.dcx().emit_err(InvalidDynKeyword {
+                    span: self.prev_token.span,
+                    suggestion: self.prev_token.span.until(self.token.span),
+                });
             }
             bounds.push(self.parse_generic_bound()?);
             if allow_plus == AllowPlus::No || !self.eat_plus() {
@@ -861,7 +868,7 @@ impl<'a> Parser<'a> {
         if has_parens {
             // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead,
             // possibly introducing `GenericBound::Paren(P<GenericBound>)`?
-            self.recover_paren_lifetime(lo, lt.ident.span)?;
+            self.recover_paren_lifetime(lo)?;
         }
         Ok(bound)
     }
@@ -909,16 +916,12 @@ impl<'a> Parser<'a> {
     }
 
     /// Recover on `('lifetime)` with `(` already eaten.
-    fn recover_paren_lifetime(&mut self, lo: Span, lt_span: Span) -> PResult<'a, ()> {
+    fn recover_paren_lifetime(&mut self, lo: Span) -> PResult<'a, ()> {
         self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
         let span = lo.to(self.prev_token.span);
-        let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(lt_span) {
-            (Some(span), snippet)
-        } else {
-            (None, String::new())
-        };
+        let sugg = errors::RemoveParens { lo, hi: self.prev_token.span };
 
-        self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg, snippet });
+        self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg });
         Ok(())
     }