Make comma separated lists of anything easier to make for errors
Provide a new function `listify`, meant to be used in cases similar to `pluralize!`. When you have a slice of arbitrary elements that need to be presented to the user, `listify` allows you to turn that into a list of comma separated strings. This reduces a lot of redundant logic that happens often in diagnostics.
This commit is contained in:
parent
7f36543a48
commit
8e9422f94e
11 changed files with 88 additions and 148 deletions
|
@ -4,7 +4,7 @@ use std::collections::BTreeMap;
|
||||||
|
|
||||||
use rustc_abi::{FieldIdx, VariantIdx};
|
use rustc_abi::{FieldIdx, VariantIdx};
|
||||||
use rustc_data_structures::fx::FxIndexMap;
|
use rustc_data_structures::fx::FxIndexMap;
|
||||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan};
|
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
|
||||||
use rustc_hir::def::{CtorKind, Namespace};
|
use rustc_hir::def::{CtorKind, Namespace};
|
||||||
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
||||||
use rustc_index::IndexSlice;
|
use rustc_index::IndexSlice;
|
||||||
|
@ -29,7 +29,7 @@ use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||||
use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
|
use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::{
|
use rustc_trait_selection::traits::{
|
||||||
FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
|
FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions,
|
||||||
};
|
};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
@ -1436,17 +1436,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||||
error.obligation.predicate,
|
error.obligation.predicate,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
[errors @ .., last] => {
|
_ => {
|
||||||
format!(
|
format!(
|
||||||
"you could `clone` the value and consume it, if the \
|
"you could `clone` the value and consume it, if the \
|
||||||
following trait bounds could be satisfied: \
|
following trait bounds could be satisfied: {}",
|
||||||
{} and `{}`",
|
listify(&errors, |e: &FulfillmentError<'tcx>| format!(
|
||||||
errors
|
"`{}`",
|
||||||
.iter()
|
e.obligation.predicate
|
||||||
.map(|e| format!("`{}`", e.obligation.predicate))
|
))
|
||||||
.collect::<Vec<_>>()
|
.unwrap(),
|
||||||
.join(", "),
|
|
||||||
last.obligation.predicate,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,7 +8,9 @@ use rustc_ast::{
|
||||||
token,
|
token,
|
||||||
};
|
};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
|
use rustc_errors::{
|
||||||
|
Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize,
|
||||||
|
};
|
||||||
use rustc_expand::base::*;
|
use rustc_expand::base::*;
|
||||||
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
|
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
|
||||||
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
|
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
|
||||||
|
@ -975,15 +977,11 @@ fn report_invalid_references(
|
||||||
} else {
|
} else {
|
||||||
MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
|
MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
|
||||||
};
|
};
|
||||||
let arg_list = if let &[index] = &indexes[..] {
|
let arg_list = format!(
|
||||||
format!("argument {index}")
|
"argument{} {}",
|
||||||
} else {
|
pluralize!(indexes.len()),
|
||||||
let tail = indexes.pop().unwrap();
|
listify(&indexes, |i: &usize| i.to_string()).unwrap_or_default()
|
||||||
format!(
|
);
|
||||||
"arguments {head} and {tail}",
|
|
||||||
head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
|
|
||||||
)
|
|
||||||
};
|
|
||||||
e = ecx.dcx().struct_span_err(
|
e = ecx.dcx().struct_span_err(
|
||||||
span,
|
span,
|
||||||
format!("invalid reference to positional {arg_list} ({num_args_desc})"),
|
format!("invalid reference to positional {arg_list} ({num_args_desc})"),
|
||||||
|
|
|
@ -65,7 +65,7 @@ pub use rustc_error_messages::{
|
||||||
SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
|
SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
|
||||||
};
|
};
|
||||||
use rustc_lint_defs::LintExpectationId;
|
use rustc_lint_defs::LintExpectationId;
|
||||||
pub use rustc_lint_defs::{Applicability, pluralize};
|
pub use rustc_lint_defs::{Applicability, listify, pluralize};
|
||||||
use rustc_macros::{Decodable, Encodable};
|
use rustc_macros::{Decodable, Encodable};
|
||||||
pub use rustc_span::ErrorGuaranteed;
|
pub use rustc_span::ErrorGuaranteed;
|
||||||
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
|
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
|
||||||
|
@ -1999,18 +1999,6 @@ pub fn a_or_an(s: &str) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grammatical tool for displaying messages to end users in a nice form.
|
|
||||||
///
|
|
||||||
/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c"
|
|
||||||
pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String {
|
|
||||||
match v {
|
|
||||||
[] => "".to_string(),
|
|
||||||
[a] => a.to_string(),
|
|
||||||
[a, b] => format!("{a} and {b}"),
|
|
||||||
[a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||||
pub enum TerminalUrl {
|
pub enum TerminalUrl {
|
||||||
No,
|
No,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap;
|
||||||
use rustc_data_structures::unord::UnordMap;
|
use rustc_data_structures::unord::UnordMap;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err,
|
Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
@ -808,14 +808,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
.map(|(trait_, mut assocs)| {
|
.map(|(trait_, mut assocs)| {
|
||||||
assocs.sort();
|
assocs.sort();
|
||||||
let trait_ = trait_.print_trait_sugared();
|
let trait_ = trait_.print_trait_sugared();
|
||||||
format!("{} in `{trait_}`", match &assocs[..] {
|
format!(
|
||||||
[] => String::new(),
|
"{} in `{trait_}`",
|
||||||
[only] => format!("`{only}`"),
|
listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default()
|
||||||
[assocs @ .., last] => format!(
|
)
|
||||||
"{} and `{last}`",
|
|
||||||
assocs.iter().map(|a| format!("`{a}`")).collect::<Vec<_>>().join(", ")
|
|
||||||
),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
names.sort();
|
names.sort();
|
||||||
|
@ -1075,18 +1071,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let this_type = match &types_and_spans[..] {
|
let this_type = listify(&types_and_spans, |(t, _)| t.to_string())
|
||||||
[.., _, (last, _)] => format!(
|
.expect("expected one segment to deny");
|
||||||
"{} and {last}",
|
|
||||||
types_and_spans[..types_and_spans.len() - 1]
|
|
||||||
.iter()
|
|
||||||
.map(|(x, _)| x.as_str())
|
|
||||||
.intersperse(", ")
|
|
||||||
.collect::<String>()
|
|
||||||
),
|
|
||||||
[(only, _)] => only.to_string(),
|
|
||||||
[] => bug!("expected one segment to deny"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let arg_spans: Vec<Span> = segments
|
let arg_spans: Vec<Span> = segments
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -1102,21 +1088,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
ProhibitGenericsArg::Infer => kinds.push("generic"),
|
ProhibitGenericsArg::Infer => kinds.push("generic"),
|
||||||
});
|
});
|
||||||
|
|
||||||
let (kind, s) = match kinds[..] {
|
let s = pluralize!(kinds.len());
|
||||||
[.., _, last] => (
|
let kind =
|
||||||
format!(
|
listify(&kinds, |k| k.to_string()).expect("expected at least one generic to prohibit");
|
||||||
"{} and {last}",
|
|
||||||
kinds[..kinds.len() - 1]
|
|
||||||
.iter()
|
|
||||||
.map(|&x| x)
|
|
||||||
.intersperse(", ")
|
|
||||||
.collect::<String>()
|
|
||||||
),
|
|
||||||
"s",
|
|
||||||
),
|
|
||||||
[only] => (only.to_string(), ""),
|
|
||||||
[] => bug!("expected at least one generic to prohibit"),
|
|
||||||
};
|
|
||||||
let last_span = *arg_spans.last().unwrap();
|
let last_span = *arg_spans.last().unwrap();
|
||||||
let span: MultiSpan = arg_spans.into();
|
let span: MultiSpan = arg_spans.into();
|
||||||
let mut err = struct_span_code_err!(
|
let mut err = struct_span_code_err!(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
use rustc_errors::{Applicability, Diag, MultiSpan, listify};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
|
@ -1016,18 +1016,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
},
|
},
|
||||||
self.tcx.def_path_str(candidate.item.container_id(self.tcx))
|
self.tcx.def_path_str(candidate.item.container_id(self.tcx))
|
||||||
),
|
),
|
||||||
[.., last] if other_methods_in_scope.len() < 5 => {
|
_ if other_methods_in_scope.len() < 5 => {
|
||||||
format!(
|
format!(
|
||||||
"the methods of the same name on {} and `{}`",
|
"the methods of the same name on {}",
|
||||||
other_methods_in_scope[..other_methods_in_scope.len() - 1]
|
listify(
|
||||||
.iter()
|
&other_methods_in_scope[..other_methods_in_scope.len() - 1],
|
||||||
.map(|c| format!(
|
|c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx)))
|
||||||
"`{}`",
|
)
|
||||||
self.tcx.def_path_str(c.item.container_id(self.tcx))
|
.unwrap_or_default(),
|
||||||
))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(", "),
|
|
||||||
self.tcx.def_path_str(last.item.container_id(self.tcx))
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => format!(
|
_ => format!(
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_data_structures::unord::UnordMap;
|
use rustc_data_structures::unord::UnordMap;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize,
|
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize,
|
||||||
struct_span_code_err,
|
struct_span_code_err,
|
||||||
};
|
};
|
||||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||||
|
@ -2190,13 +2190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
if !missing_mandatory_fields.is_empty() {
|
if !missing_mandatory_fields.is_empty() {
|
||||||
let s = pluralize!(missing_mandatory_fields.len());
|
let s = pluralize!(missing_mandatory_fields.len());
|
||||||
let fields: Vec<_> =
|
let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap();
|
||||||
missing_mandatory_fields.iter().map(|f| format!("`{f}`")).collect();
|
|
||||||
let fields = match &fields[..] {
|
|
||||||
[] => unreachable!(),
|
|
||||||
[only] => only.to_string(),
|
|
||||||
[start @ .., last] => format!("{} and {last}", start.join(", ")),
|
|
||||||
};
|
|
||||||
self.dcx()
|
self.dcx()
|
||||||
.struct_span_err(
|
.struct_span_err(
|
||||||
span.shrink_to_hi(),
|
span.shrink_to_hi(),
|
||||||
|
@ -2553,25 +2547,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.partition(|field| field.2);
|
.partition(|field| field.2);
|
||||||
err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
|
err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field");
|
||||||
if !remaining_private_fields.is_empty() {
|
if !remaining_private_fields.is_empty() {
|
||||||
let remaining_private_fields_len = remaining_private_fields.len();
|
let names = if remaining_private_fields.len() > 6 {
|
||||||
let names = match &remaining_private_fields
|
String::new()
|
||||||
.iter()
|
} else {
|
||||||
.map(|(name, _, _)| name)
|
format!(
|
||||||
.collect::<Vec<_>>()[..]
|
"{} ",
|
||||||
{
|
listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`"))
|
||||||
_ if remaining_private_fields_len > 6 => String::new(),
|
.expect("expected at least one private field to report")
|
||||||
[name] => format!("`{name}` "),
|
)
|
||||||
[names @ .., last] => {
|
|
||||||
let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
|
|
||||||
format!("{} and `{last}` ", names.join(", "))
|
|
||||||
}
|
|
||||||
[] => bug!("expected at least one private field to report"),
|
|
||||||
};
|
};
|
||||||
err.note(format!(
|
err.note(format!(
|
||||||
"{}private field{s} {names}that {were} not provided",
|
"{}private field{s} {names}that {were} not provided",
|
||||||
if used_fields.is_empty() { "" } else { "...and other " },
|
if used_fields.is_empty() { "" } else { "...and other " },
|
||||||
s = pluralize!(remaining_private_fields_len),
|
s = pluralize!(remaining_private_fields.len()),
|
||||||
were = pluralize!("was", remaining_private_fields_len),
|
were = pluralize!("was", remaining_private_fields.len()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,7 @@ use itertools::Itertools;
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an,
|
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, listify, pluralize,
|
||||||
display_list_with_comma_and, pluralize,
|
|
||||||
};
|
};
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
@ -2462,7 +2461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
param.span,
|
param.span,
|
||||||
format!(
|
format!(
|
||||||
"{} need{} to match the {} type of this parameter",
|
"{} need{} to match the {} type of this parameter",
|
||||||
display_list_with_comma_and(&other_param_matched_names),
|
listify(&other_param_matched_names, |n| n.to_string())
|
||||||
|
.unwrap_or_default(),
|
||||||
pluralize!(if other_param_matched_names.len() == 1 {
|
pluralize!(if other_param_matched_names.len() == 1 {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
|
@ -2477,7 +2477,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
format!(
|
format!(
|
||||||
"this parameter needs to match the {} type of {}",
|
"this parameter needs to match the {} type of {}",
|
||||||
matched_ty,
|
matched_ty,
|
||||||
display_list_with_comma_and(&other_param_matched_names),
|
listify(&other_param_matched_names, |n| n.to_string())
|
||||||
|
.unwrap_or_default(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2523,7 +2524,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
generic_param.span,
|
generic_param.span,
|
||||||
format!(
|
format!(
|
||||||
"{} {} reference this parameter `{}`",
|
"{} {} reference this parameter `{}`",
|
||||||
display_list_with_comma_and(¶m_idents_matching),
|
listify(¶m_idents_matching, |n| n.to_string())
|
||||||
|
.unwrap_or_default(),
|
||||||
if param_idents_matching.len() == 2 { "both" } else { "all" },
|
if param_idents_matching.len() == 2 { "both" } else { "all" },
|
||||||
generic_param.name.ident().name,
|
generic_param.name.ident().name,
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,7 +4,7 @@ use core::iter;
|
||||||
use hir::def_id::LocalDefId;
|
use hir::def_id::LocalDefId;
|
||||||
use rustc_ast::util::parser::ExprPrecedence;
|
use rustc_ast::util::parser::ExprPrecedence;
|
||||||
use rustc_data_structures::packed::Pu128;
|
use rustc_data_structures::packed::Pu128;
|
||||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
use rustc_errors::{Applicability, Diag, MultiSpan, listify};
|
||||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
|
@ -1836,16 +1836,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
error.obligation.predicate,
|
error.obligation.predicate,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
[errors @ .., last] => {
|
_ => {
|
||||||
diag.help(format!(
|
diag.help(format!(
|
||||||
"`Clone` is not implemented because the following trait bounds \
|
"`Clone` is not implemented because the following trait bounds \
|
||||||
could not be satisfied: {} and `{}`",
|
could not be satisfied: {}",
|
||||||
errors
|
listify(&errors, |e| format!("`{}`", e.obligation.predicate))
|
||||||
.iter()
|
.unwrap(),
|
||||||
.map(|e| format!("`{}`", e.obligation.predicate))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(", "),
|
|
||||||
last.obligation.predicate,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,23 @@ macro_rules! pluralize {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Grammatical tool for displaying messages to end users in a nice form.
|
||||||
|
///
|
||||||
|
/// Take a list of items and a function to turn those items into a `String`, and output a display
|
||||||
|
/// friendly comma separated list of those items.
|
||||||
|
// FIXME(estebank): this needs to be changed to go through the translation machinery.
|
||||||
|
pub fn listify<T>(list: &[T], fmt: impl Fn(&T) -> String) -> Option<String> {
|
||||||
|
Some(match list {
|
||||||
|
[only] => fmt(&only),
|
||||||
|
[others @ .., last] => format!(
|
||||||
|
"{} and {}",
|
||||||
|
others.iter().map(|i| fmt(i)).collect::<Vec<_>>().join(", "),
|
||||||
|
fmt(&last),
|
||||||
|
),
|
||||||
|
[] => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Indicates the confidence in the correctness of a suggestion.
|
/// Indicates the confidence in the correctness of a suggestion.
|
||||||
///
|
///
|
||||||
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
|
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::ops::ControlFlow;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, pluralize,
|
Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize,
|
||||||
};
|
};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
@ -362,11 +362,8 @@ pub fn suggest_constraining_type_params<'a>(
|
||||||
let n = trait_names.len();
|
let n = trait_names.len();
|
||||||
let stable = if all_stable { "" } else { "unstable " };
|
let stable = if all_stable { "" } else { "unstable " };
|
||||||
let trait_ = if all_known { format!("trait{}", pluralize!(n)) } else { String::new() };
|
let trait_ = if all_known { format!("trait{}", pluralize!(n)) } else { String::new() };
|
||||||
format!("{stable}{trait_}{}", match &trait_names[..] {
|
let Some(trait_names) = listify(&trait_names, |n| n.to_string()) else { return false };
|
||||||
[t] => format!(" {t}"),
|
format!("{stable}{trait_} {trait_names}")
|
||||||
[ts @ .., last] => format!(" {} and {last}", ts.join(", ")),
|
|
||||||
[] => return false,
|
|
||||||
},)
|
|
||||||
} else {
|
} else {
|
||||||
// We're more explicit when there's a mix of stable and unstable traits.
|
// We're more explicit when there's a mix of stable and unstable traits.
|
||||||
let mut trait_names = constraints
|
let mut trait_names = constraints
|
||||||
|
@ -378,10 +375,9 @@ pub fn suggest_constraining_type_params<'a>(
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
trait_names.sort();
|
trait_names.sort();
|
||||||
trait_names.dedup();
|
trait_names.dedup();
|
||||||
match &trait_names[..] {
|
match listify(&trait_names, |t| t.to_string()) {
|
||||||
[t] => t.to_string(),
|
Some(names) => names,
|
||||||
[ts @ .., last] => format!("{} and {last}", ts.join(", ")),
|
None => return false,
|
||||||
[] => return false,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let constraint = constraint.join(" + ");
|
let constraint = constraint.join(" + ");
|
||||||
|
|
|
@ -24,7 +24,7 @@ use rustc_ast::MacroDef;
|
||||||
use rustc_ast::visit::{VisitorResult, try_visit};
|
use rustc_ast::visit::{VisitorResult, try_visit};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::intern::Interned;
|
use rustc_data_structures::intern::Interned;
|
||||||
use rustc_errors::MultiSpan;
|
use rustc_errors::{MultiSpan, listify};
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
|
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
|
||||||
use rustc_hir::intravisit::{self, InferKind, Visitor};
|
use rustc_hir::intravisit::{self, InferKind, Visitor};
|
||||||
|
@ -958,29 +958,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
|
||||||
// | ^^ field `gamma` is private # `fields.2` is `false`
|
// | ^^ field `gamma` is private # `fields.2` is `false`
|
||||||
|
|
||||||
// Get the list of all private fields for the main message.
|
// Get the list of all private fields for the main message.
|
||||||
let field_names: Vec<_> = fields.iter().map(|(name, _, _)| name).collect();
|
let Some(field_names) = listify(&fields[..], |(n, _, _)| format!("`{n}`")) else { return };
|
||||||
let field_names = match &field_names[..] {
|
|
||||||
[] => return,
|
|
||||||
[name] => format!("`{name}`"),
|
|
||||||
[fields @ .., last] => format!(
|
|
||||||
"{} and `{last}`",
|
|
||||||
fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
|
let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
|
||||||
|
|
||||||
// Get the list of all private fields when pointing at the `..rest`.
|
// Get the list of all private fields when pointing at the `..rest`.
|
||||||
let rest_field_names: Vec<_> =
|
let rest_field_names: Vec<_> =
|
||||||
fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
|
fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
|
||||||
let rest_len = rest_field_names.len();
|
let rest_len = rest_field_names.len();
|
||||||
let rest_field_names = match &rest_field_names[..] {
|
let rest_field_names =
|
||||||
[] => String::new(),
|
listify(&rest_field_names[..], |n| format!("`{n}`")).unwrap_or_default();
|
||||||
[name] => format!("`{name}`"),
|
|
||||||
[fields @ .., last] => format!(
|
|
||||||
"{} and `{last}`",
|
|
||||||
fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
// Get all the labels for each field or `..rest` in the primary MultiSpan.
|
// Get all the labels for each field or `..rest` in the primary MultiSpan.
|
||||||
let labels = fields
|
let labels = fields
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1005,7 +991,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
field_names: field_names.clone(),
|
field_names,
|
||||||
variant_descr: def.variant_descr(),
|
variant_descr: def.variant_descr(),
|
||||||
def_path_str: self.tcx.def_path_str(def.did()),
|
def_path_str: self.tcx.def_path_str(def.did()),
|
||||||
labels,
|
labels,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue