Migrate `rustc_hir_analysis` to session diagnostic

Part 4: Finishing `check/mod.rs` file
This commit is contained in:
Obei Sideg 2023-04-14 18:02:41 +03:00
parent fa4cc63a6b
commit 06ff310cf9
5 changed files with 253 additions and 84 deletions

View File

@ -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

View File

@ -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.

View File

@ -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,
}

View File

@ -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`

View File

@ -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