From 06ff310cf95349da078e4cac0c5377172766fa94 Mon Sep 17 00:00:00 2001
From: Obei Sideg <obei.sideg@gmail.com>
Date: Fri, 14 Apr 2023 18:02:41 +0300
Subject: [PATCH] Migrate `rustc_hir_analysis` to session diagnostic

Part 4: Finishing `check/mod.rs` file
---
 compiler/rustc_hir_analysis/messages.ftl      |  37 ++++
 compiler/rustc_hir_analysis/src/check/mod.rs  | 158 +++++++++---------
 compiler/rustc_hir_analysis/src/errors.rs     | 138 +++++++++++++++
 tests/ui/repr/repr-transparent.stderr         |   2 +-
 .../transparent-enum-too-many-variants.stderr |   2 +
 5 files changed, 253 insertions(+), 84 deletions(-)

diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 1d7965ff5f6..f32ae509e33 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -225,3 +225,40 @@ hir_analysis_functions_names_duplicated = functions names are duplicated
 
 hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code
     .help = add `#![feature(simd_ffi)]` to the crate attributes to enable
+
+hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
+    .label = cannot specialize default item `{$ident}`
+    .ok_label = parent `impl` is here
+    .note = to specialize, `{$ident}` in the parent `impl` must be marked `default`
+
+hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
+    .note = parent implementation is in crate `{$cname}`
+
+hir_analysis_missing_trait_item = not all trait items implemented, missing: `{$missing_items_msg}`
+    .label = missing `{$missing_items_msg}` in implementation
+
+hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snippet}`
+
+hir_analysis_missing_trait_item_label = `{$item}` from trait
+
+hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
+    .label = missing one of `{$missing_items_msg}` in implementation
+    .note = required because of this annotation
+
+hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}`
+    .note = default implementation of `{$missing_item_name}` is unstable
+    .some_note = use of unstable library feature '{$feature}': {$r}
+    .none_note = use of unstable library feature '{$feature}'
+
+hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number}
+    .label = needs exactly one variant, but has {$number}
+    .many_label = too many variants in `{$path}`
+    .multi_label = variant here
+
+hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
+    .label = needs at most one non-zero-sized field, but has {$field_count}
+    .labels = this field is non-zero-sized
+
+hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
+    .label = needs at most one non-zero-sized field, but has {$field_count}
+    .labels = this field is non-zero-sized
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 4b3f3cf169d..08154cdae47 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -74,7 +74,7 @@ pub use check::check_abi;
 
 use check::check_mod_item_types;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::BitSet;
@@ -90,6 +90,7 @@ use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 use std::num::NonZeroU32;
 
+use crate::errors;
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
@@ -171,29 +172,13 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
 fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
     let span = tcx.def_span(impl_item);
     let ident = tcx.item_name(impl_item);
-    let mut err = struct_span_err!(
-        tcx.sess,
-        span,
-        E0520,
-        "`{}` specializes an item from a parent `impl`, but that item is not marked `default`",
-        ident,
-    );
-    err.span_label(span, format!("cannot specialize default item `{}`", ident));
 
-    match tcx.span_of_impl(parent_impl) {
-        Ok(span) => {
-            err.span_label(span, "parent `impl` is here");
-            err.note(&format!(
-                "to specialize, `{}` in the parent `impl` must be marked `default`",
-                ident
-            ));
-        }
-        Err(cname) => {
-            err.note(&format!("parent implementation is in crate `{cname}`"));
-        }
-    }
+    let err = match tcx.span_of_impl(parent_impl) {
+        Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
+        Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
+    };
 
-    err.emit();
+    tcx.sess.emit_err(err);
 }
 
 fn missing_items_err(
@@ -211,15 +196,6 @@ fn missing_items_err(
         .collect::<Vec<_>>()
         .join("`, `");
 
-    let impl_span = tcx.def_span(impl_def_id);
-    let mut err = struct_span_err!(
-        tcx.sess,
-        impl_span,
-        E0046,
-        "not all trait items implemented, missing: `{missing_items_msg}`",
-    );
-    err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
-
     // `Span` before impl block closing brace.
     let hi = full_impl_span.hi() - BytePos(1);
     // Point at the place right before the closing brace of the relevant `impl` to suggest
@@ -228,6 +204,8 @@ fn missing_items_err(
     // Obtain the level of indentation ending in `sugg_sp`.
     let padding =
         tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
+    let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =
+        (Vec::new(), Vec::new(), Vec::new());
 
     for &trait_item in missing_items {
         let snippet = suggestion_signature(
@@ -236,16 +214,30 @@ fn missing_items_err(
             tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(),
         );
         let code = format!("{}{}\n{}", padding, snippet, padding);
-        let msg = format!("implement the missing item: `{snippet}`");
-        let appl = Applicability::HasPlaceholders;
         if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
-            err.span_label(span, format!("`{}` from trait", trait_item.name));
-            err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
+            missing_trait_item_label
+                .push(errors::MissingTraitItemLabel { span, item: trait_item.name });
+            missing_trait_item.push(errors::MissingTraitItemSuggestion {
+                span: sugg_sp,
+                code,
+                snippet,
+            });
         } else {
-            err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
+            missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone {
+                span: sugg_sp,
+                code,
+                snippet,
+            })
         }
     }
-    err.emit();
+
+    tcx.sess.emit_err(errors::MissingTraitItem {
+        span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
+        missing_items_msg,
+        missing_trait_item_label,
+        missing_trait_item,
+        missing_trait_item_none,
+    });
 }
 
 fn missing_items_must_implement_one_of_err(
@@ -257,19 +249,11 @@ fn missing_items_must_implement_one_of_err(
     let missing_items_msg =
         missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
 
-    let mut err = struct_span_err!(
-        tcx.sess,
-        impl_span,
-        E0046,
-        "not all trait items implemented, missing one of: `{missing_items_msg}`",
-    );
-    err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
-
-    if let Some(annotation_span) = annotation_span {
-        err.span_note(annotation_span, "required because of this annotation");
-    }
-
-    err.emit();
+    tcx.sess.emit_err(errors::MissingOneOfTraitItem {
+        span: impl_span,
+        note: annotation_span,
+        missing_items_msg,
+    });
 }
 
 fn default_body_is_unstable(
@@ -281,25 +265,31 @@ fn default_body_is_unstable(
     issue: Option<NonZeroU32>,
 ) {
     let missing_item_name = tcx.associated_item(item_did).name;
-    let use_of_unstable_library_feature_note = match reason {
-        Some(r) => format!("use of unstable library feature '{feature}': {r}"),
-        None => format!("use of unstable library feature '{feature}'"),
+    let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
+    match reason {
+        Some(r) => {
+            some_note = true;
+            reason_str = r.to_string();
+        }
+        None => none_note = true,
     };
 
-    let mut err = struct_span_err!(
-        tcx.sess,
-        impl_span,
-        E0046,
-        "not all trait items implemented, missing: `{missing_item_name}`",
-    );
-    err.note(format!("default implementation of `{missing_item_name}` is unstable"));
-    err.note(use_of_unstable_library_feature_note);
+    let mut err = tcx.sess.create_err(errors::MissingTraitItemUnstable {
+        span: impl_span,
+        some_note,
+        none_note,
+        missing_item_name,
+        feature,
+        reason: reason_str,
+    });
+
     rustc_session::parse::add_feature_diagnostics_for_issue(
         &mut err,
         &tcx.sess.parse_sess,
         feature,
         rustc_feature::GateIssue::Library(issue),
     );
+
     err.emit();
 }
 
@@ -488,16 +478,18 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, d
         .iter()
         .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
         .collect();
-    let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
-    let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
-    err.span_label(sp, &msg);
+    let (mut spans, mut many) = (Vec::new(), None);
     if let [start @ .., end] = &*variant_spans {
-        for variant_span in start {
-            err.span_label(*variant_span, "");
-        }
-        err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
+        spans = start.to_vec();
+        many = Some(*end);
     }
-    err.emit();
+    tcx.sess.emit_err(errors::TransparentEnumVariant {
+        span: sp,
+        spans,
+        many,
+        number: adt.variants().len(),
+        path: tcx.def_path_str(did),
+    });
 }
 
 /// Emit an error when encountering two or more non-zero-sized fields in a transparent
@@ -509,21 +501,21 @@ fn bad_non_zero_sized_fields<'tcx>(
     field_spans: impl Iterator<Item = Span>,
     sp: Span,
 ) {
-    let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
-    let mut err = struct_span_err!(
-        tcx.sess,
-        sp,
-        E0690,
-        "{}transparent {} {}",
-        if adt.is_enum() { "the variant of a " } else { "" },
-        adt.descr(),
-        msg,
-    );
-    err.span_label(sp, &msg);
-    for sp in field_spans {
-        err.span_label(sp, "this field is non-zero-sized");
+    if adt.is_enum() {
+        tcx.sess.emit_err(errors::TransparentNonZeroSizedEnum {
+            span: sp,
+            spans: field_spans.collect(),
+            field_count,
+            desc: adt.descr(),
+        });
+    } else {
+        tcx.sess.emit_err(errors::TransparentNonZeroSized {
+            span: sp,
+            spans: field_spans.collect(),
+            field_count,
+            desc: adt.descr(),
+        });
     }
-    err.emit();
 }
 
 // FIXME: Consider moving this method to a more fitting place.
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 2a3a683489d..cfce2463b18 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -631,3 +631,141 @@ pub(crate) struct SIMDFFIHighlyExperimental {
     pub span: Span,
     pub snip: String,
 }
+
+#[derive(Diagnostic)]
+pub enum ImplNotMarkedDefault {
+    #[diag(hir_analysis_impl_not_marked_default, code = "E0520")]
+    #[note]
+    Ok {
+        #[primary_span]
+        #[label]
+        span: Span,
+        #[label(hir_analysis_ok_label)]
+        ok_label: Span,
+        ident: Symbol,
+    },
+    #[diag(hir_analysis_impl_not_marked_default_err, code = "E0520")]
+    #[note]
+    Err {
+        #[primary_span]
+        #[label]
+        span: Span,
+        cname: Symbol,
+        ident: Symbol,
+    },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_trait_item, code = "E0046")]
+pub(crate) struct MissingTraitItem {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub missing_trait_item_label: Vec<MissingTraitItemLabel>,
+    #[subdiagnostic]
+    pub missing_trait_item: Vec<MissingTraitItemSuggestion>,
+    #[subdiagnostic]
+    pub missing_trait_item_none: Vec<MissingTraitItemSuggestionNone>,
+    pub missing_items_msg: String,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_missing_trait_item_label)]
+pub(crate) struct MissingTraitItemLabel {
+    #[primary_span]
+    pub span: Span,
+    pub item: Symbol,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    hir_analysis_missing_trait_item_suggestion,
+    style = "tool-only",
+    applicability = "has-placeholders",
+    code = "{code}"
+)]
+pub(crate) struct MissingTraitItemSuggestion {
+    #[primary_span]
+    pub span: Span,
+    pub code: String,
+    pub snippet: String,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    hir_analysis_missing_trait_item_suggestion,
+    style = "hidden",
+    applicability = "has-placeholders",
+    code = "{code}"
+)]
+pub(crate) struct MissingTraitItemSuggestionNone {
+    #[primary_span]
+    pub span: Span,
+    pub code: String,
+    pub snippet: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_one_of_trait_item, code = "E0046")]
+pub(crate) struct MissingOneOfTraitItem {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note]
+    pub note: Option<Span>,
+    pub missing_items_msg: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_trait_item_unstable, code = "E0046")]
+#[note]
+pub(crate) struct MissingTraitItemUnstable {
+    #[primary_span]
+    pub span: Span,
+    #[note(hir_analysis_some_note)]
+    pub some_note: bool,
+    #[note(hir_analysis_none_note)]
+    pub none_note: bool,
+    pub missing_item_name: Symbol,
+    pub feature: Symbol,
+    pub reason: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_enum_variant, code = "E0731")]
+pub(crate) struct TransparentEnumVariant {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_analysis_multi_label)]
+    pub spans: Vec<Span>,
+    #[label(hir_analysis_many_label)]
+    pub many: Option<Span>,
+    pub number: usize,
+    pub path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_non_zero_sized_enum, code = "E0690")]
+pub(crate) struct TransparentNonZeroSizedEnum<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_analysis_labels)]
+    pub spans: Vec<Span>,
+    pub field_count: usize,
+    pub desc: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_non_zero_sized, code = "E0690")]
+pub(crate) struct TransparentNonZeroSized<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_analysis_labels)]
+    pub spans: Vec<Span>,
+    pub field_count: usize,
+    pub desc: &'a str,
+}
diff --git a/tests/ui/repr/repr-transparent.stderr b/tests/ui/repr/repr-transparent.stderr
index f1c570b9523..cb1e2337776 100644
--- a/tests/ui/repr/repr-transparent.stderr
+++ b/tests/ui/repr/repr-transparent.stderr
@@ -58,7 +58,7 @@ error[E0731]: transparent enum needs exactly one variant, but has 2
 LL | enum MultipleVariants {
    | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
 LL |     Foo(String),
-   |     ---
+   |     --- variant here
 LL |     Bar,
    |     --- too many variants in `MultipleVariants`
 
diff --git a/tests/ui/repr/transparent-enum-too-many-variants.stderr b/tests/ui/repr/transparent-enum-too-many-variants.stderr
index fb44757efaf..1a500257f48 100644
--- a/tests/ui/repr/transparent-enum-too-many-variants.stderr
+++ b/tests/ui/repr/transparent-enum-too-many-variants.stderr
@@ -5,6 +5,8 @@ LL | enum Foo {
    | ^^^^^^^^ needs exactly one variant, but has 2
 LL |     A(u8), B(u8),
    |     -      - too many variants in `Foo`
+   |     |
+   |     variant here
 
 error: aborting due to previous error