@@ -12,7 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath};
1212use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
1313use rustc_middle:: ty:: fast_reject:: { simplify_type, SimplifyParams , StripReferences } ;
1414use 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 } ;
1616use rustc_span:: lev_distance;
1717use rustc_span:: symbol:: { kw, sym, Ident } ;
1818use 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 "\n candidate #{}: `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+ "\n candidate #{}: `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 ! ( "\n and {} others" , candidates. len( ) - limit) ) ;
1406+ msg. push_str ( & format ! ( "\n and {} others" , candidates. len( ) + globs . len ( ) - limit) ) ;
13461407 }
13471408 err. note ( & msg) ;
13481409 }
0 commit comments