diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a57f398784916..1d7965ff5f66e 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -189,3 +189,39 @@ hir_analysis_return_type_notation_equality_bound = hir_analysis_return_type_notation_missing_method = cannot find associated function `{$assoc_name}` in trait `{$trait_name}` + +hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} + .label = not allowed in type signatures + +hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters + .suggestion = use a fully qualified path with inferred lifetimes + +hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes + +hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed + .label = overflowed on value after {$discr} + .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome + +hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation + .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it + +hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args + +hir_analysis_must_be_name_of_associated_function = must be a name of an associated function + +hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation + .note = required by this annotation + +hir_analysis_must_implement_not_function = not a function + +hir_analysis_must_implement_not_function_span_note = required by this annotation + +hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names + +hir_analysis_function_not_found_in_trait = function not found in this trait + +hir_analysis_functions_names_duplicated = functions names are duplicated + .note = all `#[rustc_must_implement_one_of]` arguments must be unique + +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 diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c41e96290df16..50862e3426238 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -20,7 +20,7 @@ use crate::errors; use hir::def::DefKind; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; @@ -333,17 +333,7 @@ fn bad_placeholder<'tcx>( let kind = if kind.ends_with('s') { format!("{}es", kind) } else { format!("{}s", kind) }; spans.sort(); - let mut err = struct_span_err!( - tcx.sess, - spans.clone(), - E0121, - "the placeholder `_` is not allowed within types on item signatures for {}", - kind - ); - for span in spans { - err.span_label(span, "not allowed in type signatures"); - } - err + tcx.sess.create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind }) } impl<'tcx> ItemCtxt<'tcx> { @@ -419,13 +409,8 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { self.tcx().mk_projection(item_def_id, item_substs) } else { // There are no late-bound regions; we can just ignore the binder. - let mut err = struct_span_err!( - self.tcx().sess, - span, - E0212, - "cannot use the associated type of a trait \ - with uninferred generic parameters" - ); + let (mut mpart_sugg, mut inferred_sugg) = (None, None); + let mut bound = String::new(); match self.node() { hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => { @@ -444,31 +429,25 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { (bound.span.shrink_to_lo(), format!("{}, ", lt_name)) } }; - let suggestions = vec![ - (lt_sp, sugg), - ( - span.with_hi(item_segment.ident.span.lo()), - format!( - "{}::", - // Replace the existing lifetimes with a new named lifetime. - self.tcx.replace_late_bound_regions_uncached( - poly_trait_ref, - |_| { - self.tcx.mk_re_early_bound(ty::EarlyBoundRegion { - def_id: item_def_id, - index: 0, - name: Symbol::intern(<_name), - }) - } - ), + mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { + fspan: lt_sp, + first: sugg, + sspan: span.with_hi(item_segment.ident.span.lo()), + second: format!( + "{}::", + // Replace the existing lifetimes with a new named lifetime. + self.tcx.replace_late_bound_regions_uncached( + poly_trait_ref, + |_| { + self.tcx.mk_re_early_bound(ty::EarlyBoundRegion { + def_id: item_def_id, + index: 0, + name: Symbol::intern(<_name), + }) + } ), ), - ]; - err.multipart_suggestion( - "use a fully qualified path with explicit lifetimes", - suggestions, - Applicability::MaybeIncorrect, - ); + }); } _ => {} } @@ -482,20 +461,23 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { | hir::Node::ForeignItem(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => { - err.span_suggestion_verbose( - span.with_hi(item_segment.ident.span.lo()), - "use a fully qualified path with inferred lifetimes", - format!( - "{}::", - // Erase named lt, we want `::C`, not `::C`. - self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(), - ), - Applicability::MaybeIncorrect, + inferred_sugg = Some(span.with_hi(item_segment.ident.span.lo())); + bound = format!( + "{}::", + // Erase named lt, we want `::C`, not `::C`. + self.tcx.anonymize_bound_vars(poly_trait_ref).skip_binder(), ); } _ => {} } - self.tcx().ty_error(err.emit()) + self.tcx().ty_error(self.tcx().sess.emit_err( + errors::AssociatedTypeTraitUninferredGenericParams { + span, + inferred_sugg, + bound, + mpart_sugg, + }, + )) } } @@ -763,14 +745,12 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { Some(discr) } else { let span = tcx.def_span(variant.def_id); - struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed") - .span_label(span, format!("overflowed on value after {}", prev_discr.unwrap())) - .note(&format!( - "explicitly set `{} = {}` if that is desired outcome", - tcx.item_name(variant.def_id), - wrapped_discr - )) - .emit(); + tcx.sess.emit_err(errors::EnumDiscriminantOverflowed { + span, + discr: prev_discr.unwrap().to_string(), + item_name: tcx.item_name(variant.def_id), + wrapped_discr: wrapped_discr.to_string(), + }); None } .unwrap_or(wrapped_discr), @@ -915,14 +895,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); if paren_sugar && !tcx.features().unboxed_closures { - tcx.sess - .struct_span_err( - item.span, - "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ - which traits can use parenthetical notation", - ) - .help("add `#![feature(unboxed_closures)]` to the crate attributes to use it") - .emit(); + tcx.sess.emit_err(errors::ParenSugarAttribute { span: item.span }); } let is_marker = tcx.has_attr(def_id, sym::marker); @@ -942,13 +915,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { // and that they are all identifiers .and_then(|attr| match attr.meta_item_list() { Some(items) if items.len() < 2 => { - tcx.sess - .struct_span_err( - attr.span, - "the `#[rustc_must_implement_one_of]` attribute must be \ - used with at least 2 args", - ) - .emit(); + tcx.sess.emit_err(errors::MustImplementOneOfAttribute { span: attr.span }); None } @@ -957,9 +924,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { .map(|item| item.ident().ok_or(item.span())) .collect::, _>>() .map_err(|span| { - tcx.sess - .struct_span_err(span, "must be a name of an associated function") - .emit(); + tcx.sess.emit_err(errors::MustBeNameOfAssociatedFunction { span }); }) .ok() .zip(Some(attr.span)), @@ -975,13 +940,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { match item { Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => { if !tcx.impl_defaultness(item.id.owner_id).has_value() { - tcx.sess - .struct_span_err( - item.span, - "function doesn't have a default implementation", - ) - .span_note(attr_span, "required by this annotation") - .emit(); + tcx.sess.emit_err(errors::FunctionNotHaveDefaultImplementation { + span: item.span, + note_span: attr_span, + }); return Some(()); } @@ -989,19 +951,14 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { return None; } Some(item) => { - tcx.sess - .struct_span_err(item.span, "not a function") - .span_note(attr_span, "required by this annotation") - .note( - "all `#[rustc_must_implement_one_of]` arguments must be associated \ - function names", - ) - .emit(); + tcx.sess.emit_err(errors::MustImplementNotFunction { + span: item.span, + span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span }, + note: errors::MustImplementNotFunctionNote {}, + }); } None => { - tcx.sess - .struct_span_err(ident.span, "function not found in this trait") - .emit(); + tcx.sess.emit_err(errors::FunctionNotFoundInTrait { span: ident.span }); } } @@ -1018,9 +975,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { for ident in &*list { if let Some(dup) = set.insert(ident.name, ident.span) { tcx.sess - .struct_span_err(vec![dup, ident.span], "functions names are duplicated") - .note("all `#[rustc_must_implement_one_of]` arguments must be unique") - .emit(); + .emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] }); no_dups = false; } @@ -1485,17 +1440,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( .source_map() .span_to_snippet(ast_ty.span) .map_or_else(|_| String::new(), |s| format!(" `{}`", s)); - tcx.sess - .struct_span_err( - ast_ty.span, - &format!( - "use of SIMD type{} in FFI is highly experimental and \ - may result in invalid code", - snip - ), - ) - .help("add `#![feature(simd_ffi)]` to the crate attributes to enable") - .emit(); + tcx.sess.emit_err(errors::SIMDFFIHighlyExperimental { span: ast_ty.span, snip }); } }; for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c71ce9a0bc7cd..2a3a683489ddd 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -507,3 +507,127 @@ pub(crate) struct ReturnTypeNotationMissingMethod { pub trait_name: Symbol, pub assoc_name: Symbol, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")] +pub(crate) struct PlaceholderNotAllowedItemSignatures { + #[primary_span] + #[label] + pub spans: Vec, + pub kind: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = "E0212")] +pub(crate) struct AssociatedTypeTraitUninferredGenericParams { + #[primary_span] + pub span: Span, + #[suggestion(style = "verbose", applicability = "maybe-incorrect", code = "{bound}")] + pub inferred_sugg: Option, + pub bound: String, + #[subdiagnostic] + pub mpart_sugg: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion, + applicability = "maybe-incorrect" +)] +pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { + #[suggestion_part(code = "{first}")] + pub fspan: Span, + pub first: String, + #[suggestion_part(code = "{second}")] + pub sspan: Span, + pub second: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_enum_discriminant_overflowed, code = "E0370")] +#[note] +pub(crate) struct EnumDiscriminantOverflowed { + #[primary_span] + #[label] + pub span: Span, + pub discr: String, + pub item_name: Symbol, + pub wrapped_discr: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_paren_sugar_attribute)] +#[help] +pub(crate) struct ParenSugarAttribute { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_must_implement_one_of_attribute)] +pub(crate) struct MustImplementOneOfAttribute { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_must_be_name_of_associated_function)] +pub(crate) struct MustBeNameOfAssociatedFunction { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_function_not_have_default_implementation)] +pub(crate) struct FunctionNotHaveDefaultImplementation { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_must_implement_not_function)] +pub(crate) struct MustImplementNotFunction { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub span_note: MustImplementNotFunctionSpanNote, + #[subdiagnostic] + pub note: MustImplementNotFunctionNote, +} + +#[derive(Subdiagnostic)] +#[note(hir_analysis_must_implement_not_function_span_note)] +pub(crate) struct MustImplementNotFunctionSpanNote { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[note(hir_analysis_must_implement_not_function_note)] +pub(crate) struct MustImplementNotFunctionNote {} + +#[derive(Diagnostic)] +#[diag(hir_analysis_function_not_found_in_trait)] +pub(crate) struct FunctionNotFoundInTrait { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_functions_names_duplicated)] +#[note] +pub(crate) struct FunctionNamesDuplicated { + #[primary_span] + pub spans: Vec, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_simd_ffi_highly_experimental)] +#[help] +pub(crate) struct SIMDFFIHighlyExperimental { + #[primary_span] + pub span: Span, + pub snip: String, +}