1
Fork 0

Tweak output of import suggestions

When both `std::` and `core::` items are available, only suggest the
`std::` ones. We ensure that in `no_std` crates we suggest `core::`
items.

Ensure that the list of items suggested to be imported are always in the
order of local crate items, `std`/`core` items and finally foreign crate
items.

Tweak wording of import suggestion: if there are multiple items but they
are all of the same kind, we use the kind name and not the generic "items".

Fix #83564.
This commit is contained in:
Esteban Küber 2024-06-12 23:51:31 +00:00
parent f1586001ac
commit 5de8e6edfc
30 changed files with 159 additions and 80 deletions

View file

@ -2783,33 +2783,65 @@ fn show_candidates(
// by iterating through a hash map, so make sure they are ordered:
for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] {
path_strings.sort_by(|a, b| a.0.cmp(&b.0));
path_strings.dedup_by(|a, b| a.0 == b.0);
let core_path_strings =
path_strings.extract_if(|p| p.0.starts_with("core::")).collect::<Vec<_>>();
path_strings.extend(core_path_strings);
path_strings.dedup_by(|a, b| a.0 == b.0);
let std_path_strings =
path_strings.extract_if(|p| p.0.starts_with("std::")).collect::<Vec<_>>();
let foreign_crate_path_strings =
path_strings.extract_if(|p| !p.0.starts_with("crate::")).collect::<Vec<_>>();
// We list the `crate` local paths first.
// Then we list the `std`/`core` paths.
if std_path_strings.len() == core_path_strings.len() {
// Do not list `core::` paths if we are already listing the `std::` ones.
path_strings.extend(std_path_strings);
} else {
path_strings.extend(std_path_strings);
path_strings.extend(core_path_strings);
}
// List all paths from foreign crates last.
path_strings.extend(foreign_crate_path_strings);
}
accessible_path_strings.sort();
if !accessible_path_strings.is_empty() {
let (determiner, kind, name, through) =
let (determiner, kind, s, name, through) =
if let [(name, descr, _, _, via_import)] = &accessible_path_strings[..] {
(
"this",
*descr,
"",
format!(" `{name}`"),
if *via_import { " through its public re-export" } else { "" },
)
} else {
("one of these", "items", String::new(), "")
// Get the unique item kinds and if there's only one, we use the right kind name
// instead of the more generic "items".
let mut kinds = accessible_path_strings
.iter()
.map(|(_, descr, _, _, _)| *descr)
.collect::<FxHashSet<&str>>()
.into_iter();
let kind = if let Some(kind) = kinds.next()
&& let None = kinds.next()
{
kind
} else {
"item"
};
let s = if kind.ends_with('s') { "es" } else { "s" };
("one of these", kind, s, String::new(), "")
};
let instead = if let Instead::Yes = instead { " instead" } else { "" };
let mut msg = if let DiagMode::Pattern = mode {
format!(
"if you meant to match on {kind}{instead}{name}, use the full path in the pattern",
"if you meant to match on {kind}{s}{instead}{name}, use the full path in the \
pattern",
)
} else {
format!("consider importing {determiner} {kind}{through}{instead}")
format!("consider importing {determiner} {kind}{s}{through}{instead}")
};
for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {