typeck: port "missing type params"

Port the "the type parameter `T` must be explicitly specified"
diagnostic to using a diagnostic struct.

Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
David Wood 2022-05-07 07:32:01 +01:00
parent de3e8ca2f3
commit 78cc331bd7
3 changed files with 92 additions and 58 deletions

View File

@ -100,3 +100,25 @@ typeck-explicit-generic-args-with-impl-trait =
.label = explicit generic argument not allowed
.note = see issue #83701 <https://github.com/rust-lang/rust/issues/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

View File

@ -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 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if missing_type_params.is_empty() {
return;
}
let display =
missing_type_params.iter().map(|n| format!("`{}`", n)).collect::<Vec<_>>().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<Type>`.
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

View File

@ -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<String>,
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::<Vec<_>>()
.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<Type>`.
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
}
}