Skip to content

Commit f835085

Browse files
Suggest glob-import if we need to import a trait, but it has no visible name
1 parent c327627 commit f835085

File tree

1 file changed

+68
-7
lines changed

1 file changed

+68
-7
lines changed

compiler/rustc_typeck/src/check/method/suggest.rs

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath};
1212
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1313
use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
1414
use rustc_middle::ty::print::with_crate_prefix;
15-
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
15+
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
1616
use rustc_span::lev_distance;
1717
use rustc_span::symbol::{kw, sym, Ident};
1818
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
@@ -1310,25 +1310,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13101310
mut msg: String,
13111311
candidates: Vec<DefId>,
13121312
) {
1313+
let parent_map = self.tcx.visible_parent_map(());
1314+
1315+
// Separate out candidates that must be imported with a glob, because they are named `_`
1316+
// and cannot be referred with their identifier.
1317+
let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
1318+
if let Some(parent_did) = parent_map.get(trait_did) {
1319+
// If the item is re-exported as `_`, we should suggest a glob-import instead.
1320+
if Some(*parent_did) != self.tcx.parent(*trait_did)
1321+
&& self
1322+
.tcx
1323+
.item_children(*parent_did)
1324+
.iter()
1325+
.filter(|child| child.res.opt_def_id() == Some(*trait_did))
1326+
.all(|child| child.ident.name == kw::Underscore)
1327+
{
1328+
return false;
1329+
}
1330+
}
1331+
1332+
true
1333+
});
1334+
13131335
let module_did = self.tcx.parent_module(self.body_id);
13141336
let (span, found_use) = find_use_placement(self.tcx, module_did);
13151337
if let Some(span) = span {
1316-
let path_strings = candidates.iter().map(|did| {
1338+
let path_strings = candidates.iter().map(|trait_did| {
13171339
// Produce an additional newline to separate the new use statement
13181340
// from the directly following item.
13191341
let additional_newline = if found_use { "" } else { "\n" };
13201342
format!(
13211343
"use {};\n{}",
1322-
with_crate_prefix(|| self.tcx.def_path_str(*did)),
1344+
with_crate_prefix(|| self.tcx.def_path_str(*trait_did)),
13231345
additional_newline
13241346
)
13251347
});
13261348

1327-
err.span_suggestions(span, &msg, path_strings, Applicability::MaybeIncorrect);
1349+
let glob_path_strings = globs.iter().map(|trait_did| {
1350+
let parent_did = parent_map.get(trait_did).unwrap();
1351+
1352+
// Produce an additional newline to separate the new use statement
1353+
// from the directly following item.
1354+
let additional_newline = if found_use { "" } else { "\n" };
1355+
format!(
1356+
"use {}::*; // trait {}\n{}",
1357+
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
1358+
self.tcx.item_name(*trait_did),
1359+
additional_newline
1360+
)
1361+
});
1362+
1363+
err.span_suggestions(
1364+
span,
1365+
&msg,
1366+
path_strings.chain(glob_path_strings),
1367+
Applicability::MaybeIncorrect,
1368+
);
13281369
} else {
1329-
let limit = if candidates.len() == 5 { 5 } else { 4 };
1370+
let limit = if candidates.len() + globs.len() == 5 { 5 } else { 4 };
13301371
for (i, trait_did) in candidates.iter().take(limit).enumerate() {
1331-
if candidates.len() > 1 {
1372+
if candidates.len() + globs.len() > 1 {
13321373
msg.push_str(&format!(
13331374
"\ncandidate #{}: `use {};`",
13341375
i + 1,
@@ -1341,8 +1382,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13411382
));
13421383
}
13431384
}
1385+
for (i, trait_did) in
1386+
globs.iter().take(limit.saturating_sub(candidates.len())).enumerate()
1387+
{
1388+
let parent_did = parent_map.get(trait_did).unwrap();
1389+
1390+
if candidates.len() + globs.len() > 1 {
1391+
msg.push_str(&format!(
1392+
"\ncandidate #{}: `use {}::*; // trait {}`",
1393+
candidates.len() + i + 1,
1394+
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
1395+
self.tcx.item_name(*trait_did),
1396+
));
1397+
} else {
1398+
msg.push_str(&format!(
1399+
"\n`use {}::*; // trait {}`",
1400+
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
1401+
self.tcx.item_name(*trait_did),
1402+
));
1403+
}
1404+
}
13441405
if candidates.len() > limit {
1345-
msg.push_str(&format!("\nand {} others", candidates.len() - limit));
1406+
msg.push_str(&format!("\nand {} others", candidates.len() + globs.len() - limit));
13461407
}
13471408
err.note(&msg);
13481409
}

0 commit comments

Comments
 (0)