diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl index be1a45fd872..a6b2b1dbd6a 100644 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -100,3 +100,25 @@ typeck-explicit-generic-args-with-impl-trait = .label = explicit generic argument not allowed .note = see issue #83701 for more information .help = add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable + +typeck-missing-type-params = + the type {$parameterCount -> + [one] parameter + *[other] parameters + } {$parameters} must be explicitly specified + .label = type {$parameterCount -> + [one] parameter + *[other] parameters + } {$parameters} must be specified for this + .suggestion = set the type {$parameterCount -> + [one] parameter + *[other] parameters + } to the desired {$parameterCount -> + [one] type + *[other] types + } + .no-suggestion-label = missing {$parameterCount -> + [one] reference + *[other] references + } to {$parameters} + .note = because of the default `Self` reference, type parameters must be specified on object types diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index 38cc74a5e37..5cfed81017f 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -1,4 +1,5 @@ use crate::astconv::AstConv; +use crate::errors::MissingTypeParams; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; @@ -24,65 +25,13 @@ pub(crate) fn complain_about_missing_type_params( if missing_type_params.is_empty() { return; } - let display = - missing_type_params.iter().map(|n| format!("`{}`", n)).collect::>().join(", "); - let mut err = struct_span_err!( - self.tcx().sess, + + self.tcx().sess.emit_err(MissingTypeParams { span, - E0393, - "the type parameter{} {} must be explicitly specified", - pluralize!(missing_type_params.len()), - display, - ); - err.span_label( - self.tcx().def_span(def_id), - &format!( - "type parameter{} {} must be specified for this", - pluralize!(missing_type_params.len()), - display, - ), - ); - let mut suggested = false; - if let (Ok(snippet), true) = ( - self.tcx().sess.source_map().span_to_snippet(span), - // Don't suggest setting the type params if there are some already: the order is - // tricky to get right and the user will already know what the syntax is. + def_span: self.tcx().def_span(def_id), + missing_type_params, empty_generic_args, - ) { - if snippet.ends_with('>') { - // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion - // we would have to preserve the right order. For now, as clearly the user is - // aware of the syntax, we do nothing. - } else { - // The user wrote `Iterator`, so we don't have a type we can suggest, but at - // least we can clue them to the correct syntax `Iterator`. - err.span_suggestion( - span, - &format!( - "set the type parameter{plural} to the desired type{plural}", - plural = pluralize!(missing_type_params.len()), - ), - format!("{}<{}>", snippet, missing_type_params.join(", ")), - Applicability::HasPlaceholders, - ); - suggested = true; - } - } - if !suggested { - err.span_label( - span, - format!( - "missing reference{} to {}", - pluralize!(missing_type_params.len()), - display, - ), - ); - } - err.note( - "because of the default `Self` reference, type parameters must be \ - specified on object types", - ); - err.emit(); + }); } /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 540fd63e137..93900ae24bb 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -1,7 +1,10 @@ //! Errors emitted by typeck. -use rustc_errors::Applicability; +use rustc_errors::{ + error_code, Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, +}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; +use rustc_session::{parse::ParseSess, SessionDiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] @@ -250,3 +253,63 @@ pub struct ExplicitGenericArgsWithImplTrait { #[help] pub is_nightly_build: Option<()>, } + +pub struct MissingTypeParams { + pub span: Span, + pub def_span: Span, + pub missing_type_params: Vec, + pub empty_generic_args: bool, +} + +// Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`. +impl<'a> SessionDiagnostic<'a> for MissingTypeParams { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + static SLUG: &'static str = "typeck-missing-type-params"; + let mut err = sess.span_diagnostic.struct_span_err_with_code( + self.span, + DiagnosticMessage::fluent(SLUG), + error_code!(E0393), + ); + err.set_arg("parameterCount", self.missing_type_params.len()); + err.set_arg( + "parameters", + self.missing_type_params + .iter() + .map(|n| format!("`{}`", n)) + .collect::>() + .join(", "), + ); + + err.span_label(self.def_span, DiagnosticMessage::fluent_attr(SLUG, "label")); + + let mut suggested = false; + if let (Ok(snippet), true) = ( + sess.source_map().span_to_snippet(self.span), + // Don't suggest setting the type params if there are some already: the order is + // tricky to get right and the user will already know what the syntax is. + self.empty_generic_args, + ) { + if snippet.ends_with('>') { + // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion + // we would have to preserve the right order. For now, as clearly the user is + // aware of the syntax, we do nothing. + } else { + // The user wrote `Iterator`, so we don't have a type we can suggest, but at + // least we can clue them to the correct syntax `Iterator`. + err.span_suggestion( + self.span, + DiagnosticMessage::fluent_attr(SLUG, "suggestion"), + format!("{}<{}>", snippet, self.missing_type_params.join(", ")), + Applicability::HasPlaceholders, + ); + suggested = true; + } + } + if !suggested { + err.span_label(self.span, DiagnosticMessage::fluent_attr(SLUG, "no-suggestion-label")); + } + + err.note(DiagnosticMessage::fluent_attr(SLUG, "note")); + err + } +}