Auto merge of #96853 - davidtwco:diagnostic-translation-unit-and-more-porting, r=oli-obk
diagnostics: port more diagnostics to derive + support for `()` fields - Extend diagnostic derive so that spanless subdiagnostics (e.g. some uses of `help`/`note`) can be applied via attributes to fields of type `()` (currently spanless subdiagnostics are applied via attributes on the diagnostic struct itself). A consequence of this is that `Option<()>` fields can be used to represent optional spanless subdiagnostics, which are sometimes useful (e.g. for a `help` that should only show on nightly builds). - Simplify the "explicit generic args with impl trait" diagnostic struct (from #96760) using support for `Option<()>` spanless subdiagnostics. - Change `DiagnosticBuilder::set_arg`, used to provide context for Fluent messages, so that it takes anything that implements `IntoDiagnosticArg`, rather than `DiagnosticArgValue` - this improves the ergonomics of manual implementations of `SessionDiagnostic` which are translatable. - Port "the type parameter `T` must be explicitly specified", "manual implementations of `X` are experimental", "could not resolve substs on overridden impl" diagnostics to diagnostic structs. - When testing macros from `rustc_macros` in `ui-fulldeps` tests, sometimes paths from the compiler source tree can be shown in error messages - these need to be normalized in `compiletest`. r? `@oli-obk` cc `@pvdrz`
This commit is contained in:
commit
18bd2dd5cd
14 changed files with 253 additions and 142 deletions
|
@ -99,6 +99,33 @@ typeck-explicit-generic-args-with-impl-trait =
|
||||||
cannot provide explicit generic arguments when `impl Trait` is used in argument position
|
cannot provide explicit generic arguments when `impl Trait` is used in argument position
|
||||||
.label = explicit generic argument not allowed
|
.label = explicit generic argument not allowed
|
||||||
.note = see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
|
.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-explicit-generic-args-with-impl-trait-feature =
|
typeck-missing-type-params =
|
||||||
add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
|
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
|
||||||
|
|
||||||
|
typeck-manual-implementation =
|
||||||
|
manual implementations of `{$trait_name}` are experimental
|
||||||
|
.label = manual implementations of `{$trait_name}` are experimental
|
||||||
|
.help = add `#![feature(unboxed_closures)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
typeck-substs-on-overridden-impl = could not resolve substs on overridden impl
|
||||||
|
|
|
@ -821,9 +821,9 @@ impl Diagnostic {
|
||||||
pub fn set_arg(
|
pub fn set_arg(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<Cow<'static, str>>,
|
name: impl Into<Cow<'static, str>>,
|
||||||
arg: DiagnosticArgValue<'static>,
|
arg: impl IntoDiagnosticArg,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.args.push((name.into(), arg));
|
self.args.push((name.into(), arg.into_diagnostic_arg()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::diagnostic::DiagnosticArgValue;
|
use crate::diagnostic::IntoDiagnosticArg;
|
||||||
use crate::{Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed};
|
use crate::{Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed};
|
||||||
use crate::{Handler, Level, MultiSpan, StashKey};
|
use crate::{Handler, Level, MultiSpan, StashKey};
|
||||||
use rustc_lint_defs::Applicability;
|
use rustc_lint_defs::Applicability;
|
||||||
|
@ -528,7 +528,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
||||||
forward!(pub fn set_arg(
|
forward!(pub fn set_arg(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<Cow<'static, str>>,
|
name: impl Into<Cow<'static, str>>,
|
||||||
arg: DiagnosticArgValue<'static>,
|
arg: impl IntoDiagnosticArg,
|
||||||
) -> &mut Self);
|
) -> &mut Self);
|
||||||
|
|
||||||
forward!(pub fn subdiagnostic(
|
forward!(pub fn subdiagnostic(
|
||||||
|
|
|
@ -5,10 +5,10 @@ use crate::diagnostics::error::{
|
||||||
SessionDiagnosticDeriveError,
|
SessionDiagnosticDeriveError,
|
||||||
};
|
};
|
||||||
use crate::diagnostics::utils::{
|
use crate::diagnostics::utils::{
|
||||||
report_error_if_not_applied_to_span, type_matches_path, Applicability, FieldInfo, FieldInnerTy,
|
report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
|
||||||
HasFieldMap, SetOnce,
|
Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::{Ident, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -113,7 +113,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
|
||||||
quote! {
|
quote! {
|
||||||
#diag.set_arg(
|
#diag.set_arg(
|
||||||
stringify!(#ident),
|
stringify!(#ident),
|
||||||
#field_binding.into_diagnostic_arg()
|
#field_binding
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -388,7 +388,8 @@ impl SessionDiagnosticDeriveBuilder {
|
||||||
) -> Result<TokenStream, SessionDiagnosticDeriveError> {
|
) -> Result<TokenStream, SessionDiagnosticDeriveError> {
|
||||||
let diag = &self.diag;
|
let diag = &self.diag;
|
||||||
|
|
||||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
let ident = &attr.path.segments.last().unwrap().ident;
|
||||||
|
let name = ident.to_string();
|
||||||
let name = name.as_str();
|
let name = name.as_str();
|
||||||
|
|
||||||
let meta = attr.parse_meta()?;
|
let meta = attr.parse_meta()?;
|
||||||
|
@ -405,9 +406,18 @@ impl SessionDiagnosticDeriveBuilder {
|
||||||
#diag.set_span(#binding);
|
#diag.set_span(#binding);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
"label" | "note" | "help" => {
|
"label" => {
|
||||||
report_error_if_not_applied_to_span(attr, &info)?;
|
report_error_if_not_applied_to_span(attr, &info)?;
|
||||||
Ok(self.add_subdiagnostic(binding, name, name))
|
Ok(self.add_spanned_subdiagnostic(binding, ident, name))
|
||||||
|
}
|
||||||
|
"note" | "help" => {
|
||||||
|
if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
|
||||||
|
Ok(self.add_spanned_subdiagnostic(binding, ident, name))
|
||||||
|
} else if type_is_unit(&info.ty) {
|
||||||
|
Ok(self.add_subdiagnostic(ident, name))
|
||||||
|
} else {
|
||||||
|
report_type_error(attr, "`Span` or `()`")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
|
"subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
|
||||||
_ => throw_invalid_attr!(attr, &meta, |diag| {
|
_ => throw_invalid_attr!(attr, &meta, |diag| {
|
||||||
|
@ -416,9 +426,18 @@ impl SessionDiagnosticDeriveBuilder {
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(ref s), .. }) => match name {
|
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(ref s), .. }) => match name {
|
||||||
"label" | "note" | "help" => {
|
"label" => {
|
||||||
report_error_if_not_applied_to_span(attr, &info)?;
|
report_error_if_not_applied_to_span(attr, &info)?;
|
||||||
Ok(self.add_subdiagnostic(binding, name, &s.value()))
|
Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value()))
|
||||||
|
}
|
||||||
|
"note" | "help" => {
|
||||||
|
if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
|
||||||
|
Ok(self.add_spanned_subdiagnostic(binding, ident, &s.value()))
|
||||||
|
} else if type_is_unit(&info.ty) {
|
||||||
|
Ok(self.add_subdiagnostic(ident, &s.value()))
|
||||||
|
} else {
|
||||||
|
report_type_error(attr, "`Span` or `()`")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => throw_invalid_attr!(attr, &meta, |diag| {
|
_ => throw_invalid_attr!(attr, &meta, |diag| {
|
||||||
diag.help("only `label`, `note` and `help` are valid field attributes")
|
diag.help("only `label`, `note` and `help` are valid field attributes")
|
||||||
|
@ -510,12 +529,12 @@ impl SessionDiagnosticDeriveBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug and
|
/// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug
|
||||||
/// `fluent_attr_identifier`.
|
/// and `fluent_attr_identifier`.
|
||||||
fn add_subdiagnostic(
|
fn add_spanned_subdiagnostic(
|
||||||
&self,
|
&self,
|
||||||
field_binding: TokenStream,
|
field_binding: TokenStream,
|
||||||
kind: &str,
|
kind: &Ident,
|
||||||
fluent_attr_identifier: &str,
|
fluent_attr_identifier: &str,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let diag = &self.diag;
|
let diag = &self.diag;
|
||||||
|
@ -531,6 +550,16 @@ impl SessionDiagnosticDeriveBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug
|
||||||
|
/// and `fluent_attr_identifier`.
|
||||||
|
fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: &str) -> TokenStream {
|
||||||
|
let diag = &self.diag;
|
||||||
|
let slug = self.slug.as_ref().map(|(slug, _)| slug.as_str()).unwrap_or("missing-slug");
|
||||||
|
quote! {
|
||||||
|
#diag.#kind(rustc_errors::DiagnosticMessage::fluent_attr(#slug, #fluent_attr_identifier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn span_and_applicability_of_ty(
|
fn span_and_applicability_of_ty(
|
||||||
&self,
|
&self,
|
||||||
info: FieldInfo<'_>,
|
info: FieldInfo<'_>,
|
||||||
|
|
|
@ -349,7 +349,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
|
||||||
let generated = quote! {
|
let generated = quote! {
|
||||||
#diag.set_arg(
|
#diag.set_arg(
|
||||||
stringify!(#ident),
|
stringify!(#ident),
|
||||||
#binding.into_diagnostic_arg()
|
#binding
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote, ToTokens};
|
use quote::{format_ident, quote, ToTokens};
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use syn::{spanned::Spanned, Attribute, Meta, Type, Visibility};
|
use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple, Visibility};
|
||||||
use synstructure::BindingInfo;
|
use synstructure::BindingInfo;
|
||||||
|
|
||||||
/// Checks whether the type name of `ty` matches `name`.
|
/// Checks whether the type name of `ty` matches `name`.
|
||||||
|
@ -25,7 +25,35 @@ pub(crate) fn type_matches_path(ty: &Type, name: &[&str]) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports an error if the field's type is not `Applicability`.
|
/// Checks whether the type `ty` is `()`.
|
||||||
|
pub(crate) fn type_is_unit(ty: &Type) -> bool {
|
||||||
|
if let Type::Tuple(TypeTuple { elems, .. }) = ty { elems.is_empty() } else { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reports a type error for field with `attr`.
|
||||||
|
pub(crate) fn report_type_error(
|
||||||
|
attr: &Attribute,
|
||||||
|
ty_name: &str,
|
||||||
|
) -> Result<!, SessionDiagnosticDeriveError> {
|
||||||
|
let name = attr.path.segments.last().unwrap().ident.to_string();
|
||||||
|
let meta = attr.parse_meta()?;
|
||||||
|
|
||||||
|
throw_span_err!(
|
||||||
|
attr.span().unwrap(),
|
||||||
|
&format!(
|
||||||
|
"the `#[{}{}]` attribute can only be applied to fields of type {}",
|
||||||
|
name,
|
||||||
|
match meta {
|
||||||
|
Meta::Path(_) => "",
|
||||||
|
Meta::NameValue(_) => " = ...",
|
||||||
|
Meta::List(_) => "(...)",
|
||||||
|
},
|
||||||
|
ty_name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reports an error if the field's type does not match `path`.
|
||||||
fn report_error_if_not_applied_to_ty(
|
fn report_error_if_not_applied_to_ty(
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
info: &FieldInfo<'_>,
|
info: &FieldInfo<'_>,
|
||||||
|
@ -33,23 +61,7 @@ fn report_error_if_not_applied_to_ty(
|
||||||
ty_name: &str,
|
ty_name: &str,
|
||||||
) -> Result<(), SessionDiagnosticDeriveError> {
|
) -> Result<(), SessionDiagnosticDeriveError> {
|
||||||
if !type_matches_path(&info.ty, path) {
|
if !type_matches_path(&info.ty, path) {
|
||||||
let name = attr.path.segments.last().unwrap().ident.to_string();
|
report_type_error(attr, ty_name)?;
|
||||||
let name = name.as_str();
|
|
||||||
let meta = attr.parse_meta()?;
|
|
||||||
|
|
||||||
throw_span_err!(
|
|
||||||
attr.span().unwrap(),
|
|
||||||
&format!(
|
|
||||||
"the `#[{}{}]` attribute can only be applied to fields of type `{}`",
|
|
||||||
name,
|
|
||||||
match meta {
|
|
||||||
Meta::Path(_) => "",
|
|
||||||
Meta::NameValue(_) => " = ...",
|
|
||||||
Meta::List(_) => "(...)",
|
|
||||||
},
|
|
||||||
ty_name
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -64,7 +76,7 @@ pub(crate) fn report_error_if_not_applied_to_applicability(
|
||||||
attr,
|
attr,
|
||||||
info,
|
info,
|
||||||
&["rustc_errors", "Applicability"],
|
&["rustc_errors", "Applicability"],
|
||||||
"Applicability",
|
"`Applicability`",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +85,7 @@ pub(crate) fn report_error_if_not_applied_to_span(
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
info: &FieldInfo<'_>,
|
info: &FieldInfo<'_>,
|
||||||
) -> Result<(), SessionDiagnosticDeriveError> {
|
) -> Result<(), SessionDiagnosticDeriveError> {
|
||||||
report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "Span")
|
report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "`Span`")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inner type of a field and type of wrapper.
|
/// Inner type of a field and type of wrapper.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![feature(allow_internal_unstable)]
|
#![feature(allow_internal_unstable)]
|
||||||
#![feature(let_else)]
|
#![feature(let_else)]
|
||||||
|
#![feature(never_type)]
|
||||||
#![feature(proc_macro_diagnostic)]
|
#![feature(proc_macro_diagnostic)]
|
||||||
#![allow(rustc::default_hash_types)]
|
#![allow(rustc::default_hash_types)]
|
||||||
#![recursion_limit = "128"]
|
#![recursion_limit = "128"]
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::astconv::AstConv;
|
use crate::astconv::AstConv;
|
||||||
|
use crate::errors::{ManualImplementation, MissingTypeParams};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, ErrorGuaranteed};
|
use rustc_errors::{pluralize, struct_span_err, Applicability, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -24,65 +25,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
if missing_type_params.is_empty() {
|
if missing_type_params.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let display =
|
|
||||||
missing_type_params.iter().map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", ");
|
self.tcx().sess.emit_err(MissingTypeParams {
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx().sess,
|
|
||||||
span,
|
span,
|
||||||
E0393,
|
def_span: self.tcx().def_span(def_id),
|
||||||
"the type parameter{} {} must be explicitly specified",
|
missing_type_params,
|
||||||
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.
|
|
||||||
empty_generic_args,
|
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
|
/// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
|
||||||
|
@ -172,19 +121,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
|
|
||||||
if is_impl {
|
if is_impl {
|
||||||
let trait_name = self.tcx().def_path_str(trait_def_id);
|
let trait_name = self.tcx().def_path_str(trait_def_id);
|
||||||
struct_span_err!(
|
self.tcx().sess.emit_err(ManualImplementation { span, trait_name });
|
||||||
self.tcx().sess,
|
|
||||||
span,
|
|
||||||
E0183,
|
|
||||||
"manual implementations of `{}` are experimental",
|
|
||||||
trait_name,
|
|
||||||
)
|
|
||||||
.span_label(
|
|
||||||
span,
|
|
||||||
format!("manual implementations of `{}` are experimental", trait_name),
|
|
||||||
)
|
|
||||||
.help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,7 @@ use crate::astconv::{
|
||||||
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
|
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
|
||||||
GenericArgCountResult, GenericArgPosition,
|
GenericArgCountResult, GenericArgPosition,
|
||||||
};
|
};
|
||||||
use crate::errors::{
|
use crate::errors::{AssocTypeBindingNotAllowed, ExplicitGenericArgsWithImplTrait};
|
||||||
AssocTypeBindingNotAllowed, ExplicitGenericArgsWithImplTrait,
|
|
||||||
ExplicitGenericArgsWithImplTraitFeature,
|
|
||||||
};
|
|
||||||
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
|
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
|
||||||
use rustc_ast::ast::ParamKindOrd;
|
use rustc_ast::ast::ParamKindOrd;
|
||||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan};
|
use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan};
|
||||||
|
@ -639,11 +636,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let mut err = tcx.sess.create_err(ExplicitGenericArgsWithImplTrait { spans });
|
tcx.sess.emit_err(ExplicitGenericArgsWithImplTrait {
|
||||||
if tcx.sess.is_nightly_build() {
|
spans,
|
||||||
err.subdiagnostic(ExplicitGenericArgsWithImplTraitFeature);
|
is_nightly_build: tcx.sess.is_nightly_build().then_some(()),
|
||||||
}
|
});
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_trait
|
impl_trait
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
//! Errors emitted by typeck.
|
//! Errors emitted by typeck.
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::{
|
||||||
|
error_code, Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
|
||||||
|
};
|
||||||
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
|
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
|
use rustc_session::{parse::ParseSess, SessionDiagnostic};
|
||||||
use rustc_span::{symbol::Ident, Span, Symbol};
|
use rustc_span::{symbol::Ident, Span, Symbol};
|
||||||
|
|
||||||
#[derive(SessionDiagnostic)]
|
#[derive(SessionDiagnostic)]
|
||||||
|
@ -247,8 +250,83 @@ pub struct ExplicitGenericArgsWithImplTrait {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label]
|
#[label]
|
||||||
pub spans: Vec<Span>,
|
pub spans: Vec<Span>,
|
||||||
|
#[help]
|
||||||
|
pub is_nightly_build: Option<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(SessionSubdiagnostic)]
|
pub struct MissingTypeParams {
|
||||||
#[help(slug = "typeck-explicit-generic-args-with-impl-trait-feature")]
|
pub span: Span,
|
||||||
pub struct ExplicitGenericArgsWithImplTraitFeature;
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0183", slug = "typeck-manual-implementation")]
|
||||||
|
#[help]
|
||||||
|
pub struct ManualImplementation {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
pub trait_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(slug = "typeck-substs-on-overridden-impl")]
|
||||||
|
pub struct SubstsOnOverriddenImpl {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
//! on traits with methods can.
|
//! on traits with methods can.
|
||||||
|
|
||||||
use crate::constrained_generic_params as cgp;
|
use crate::constrained_generic_params as cgp;
|
||||||
|
use crate::errors::SubstsOnOverriddenImpl;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
@ -165,7 +166,7 @@ fn get_impl_substs<'tcx>(
|
||||||
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
|
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
|
||||||
infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default());
|
infcx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env, RegionckMode::default());
|
||||||
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
|
let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
|
||||||
tcx.sess.struct_span_err(span, "could not resolve substs on overridden impl").emit();
|
tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
Some((impl1_substs, impl2_substs))
|
Some((impl1_substs, impl2_substs))
|
||||||
|
|
|
@ -327,7 +327,7 @@ struct ErrorWithDefaultLabelAttr<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(SessionDiagnostic)]
|
#[derive(SessionDiagnostic)]
|
||||||
//~^ ERROR no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
|
//~^ ERROR the trait bound `Hello: IntoDiagnosticArg` is not satisfied
|
||||||
#[error(code = "E0123", slug = "foo")]
|
#[error(code = "E0123", slug = "foo")]
|
||||||
struct ArgFieldWithoutSkip {
|
struct ArgFieldWithoutSkip {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
|
@ -482,3 +482,25 @@ struct VecField {
|
||||||
#[label]
|
#[label]
|
||||||
spans: Vec<Span>,
|
spans: Vec<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct UnitField {
|
||||||
|
#[primary_span]
|
||||||
|
spans: Span,
|
||||||
|
#[help]
|
||||||
|
foo: (),
|
||||||
|
#[help = "a"]
|
||||||
|
bar: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[error(code = "E0123", slug = "foo")]
|
||||||
|
struct OptUnitField {
|
||||||
|
#[primary_span]
|
||||||
|
spans: Span,
|
||||||
|
#[help]
|
||||||
|
foo: Option<()>,
|
||||||
|
#[help = "a"]
|
||||||
|
bar: Option<()>,
|
||||||
|
}
|
||||||
|
|
|
@ -349,17 +349,26 @@ error: cannot find attribute `nonsense` in this scope
|
||||||
LL | #[nonsense]
|
LL | #[nonsense]
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error[E0599]: no method named `into_diagnostic_arg` found for struct `Hello` in the current scope
|
error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
|
||||||
--> $DIR/diagnostic-derive.rs:329:10
|
--> $DIR/diagnostic-derive.rs:329:10
|
||||||
|
|
|
|
||||||
LL | struct Hello {}
|
|
||||||
| ------------ method `into_diagnostic_arg` not found for this
|
|
||||||
...
|
|
||||||
LL | #[derive(SessionDiagnostic)]
|
LL | #[derive(SessionDiagnostic)]
|
||||||
| ^^^^^^^^^^^^^^^^^ method not found in `Hello`
|
| ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
|
||||||
|
|
|
|
||||||
|
= help: the following other types implement trait `IntoDiagnosticArg`:
|
||||||
|
&'a str
|
||||||
|
Ident
|
||||||
|
String
|
||||||
|
Symbol
|
||||||
|
rustc_middle::ty::Ty<'tcx>
|
||||||
|
usize
|
||||||
|
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
||||||
|
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:531:19
|
||||||
|
|
|
||||||
|
LL | arg: impl IntoDiagnosticArg,
|
||||||
|
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
|
||||||
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 43 previous errors
|
error: aborting due to 43 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0599`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -3494,22 +3494,21 @@ impl<'test> TestCx<'test> {
|
||||||
normalize_path(parent_dir, "$DIR");
|
normalize_path(parent_dir, "$DIR");
|
||||||
|
|
||||||
// Paths into the libstd/libcore
|
// Paths into the libstd/libcore
|
||||||
let src_dir = self
|
let base_dir = self.config.src_base.parent().unwrap().parent().unwrap().parent().unwrap();
|
||||||
.config
|
let src_dir = base_dir.join("library");
|
||||||
.src_base
|
|
||||||
.parent()
|
|
||||||
.unwrap()
|
|
||||||
.parent()
|
|
||||||
.unwrap()
|
|
||||||
.parent()
|
|
||||||
.unwrap()
|
|
||||||
.join("library");
|
|
||||||
normalize_path(&src_dir, "$SRC_DIR");
|
normalize_path(&src_dir, "$SRC_DIR");
|
||||||
|
|
||||||
|
// `ui-fulldeps` tests can show paths to the compiler source when testing macros from
|
||||||
|
// `rustc_macros`
|
||||||
|
// eg. /home/user/rust/compiler
|
||||||
|
let compiler_src_dir = base_dir.join("compiler");
|
||||||
|
normalize_path(&compiler_src_dir, "$COMPILER_DIR");
|
||||||
|
|
||||||
if let Some(virtual_rust_source_base_dir) =
|
if let Some(virtual_rust_source_base_dir) =
|
||||||
option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
|
option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
|
||||||
{
|
{
|
||||||
normalize_path(&virtual_rust_source_base_dir.join("library"), "$SRC_DIR");
|
normalize_path(&virtual_rust_source_base_dir.join("library"), "$SRC_DIR");
|
||||||
|
normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$COMPILER_DIR");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paths into the build directory
|
// Paths into the build directory
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue