@@ -581,6 +581,53 @@ impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
581581 }
582582}
583583
584+ struct UsePlacementFinder {
585+ target_module : NodeId ,
586+ span : Option < Span > ,
587+ }
588+
589+ impl < ' tcx > Visitor < ' tcx > for UsePlacementFinder {
590+ fn visit_mod (
591+ & mut self ,
592+ module : & ' tcx ast:: Mod ,
593+ _: Span ,
594+ _: & [ ast:: Attribute ] ,
595+ node_id : NodeId ,
596+ ) {
597+ if self . span . is_some ( ) {
598+ return ;
599+ }
600+ if node_id != self . target_module {
601+ visit:: walk_mod ( self , module) ;
602+ return ;
603+ }
604+ // find a use statement
605+ for item in & module. items {
606+ match item. node {
607+ ItemKind :: Use ( ..) => {
608+ // don't suggest placing a use before the prelude
609+ // import or other generated ones
610+ if item. span == DUMMY_SP {
611+ let mut span = item. span ;
612+ span. hi = span. lo ;
613+ self . span = Some ( span) ;
614+ return ;
615+ }
616+ } ,
617+ // don't place use before extern crate
618+ ItemKind :: ExternCrate ( _) => { }
619+ // but place them before the first other item
620+ _ => if self . span . map_or ( true , |span| item. span < span ) {
621+ let mut span = item. span ;
622+ span. hi = span. lo ;
623+ self . span = Some ( span) ;
624+ } ,
625+ }
626+ }
627+ assert ! ( self . span. is_some( ) , "a file can't have no items and emit suggestions" ) ;
628+ }
629+ }
630+
584631impl < ' a , ' tcx > Visitor < ' tcx > for Resolver < ' a > {
585632 fn visit_item ( & mut self , item : & ' tcx Item ) {
586633 self . resolve_item ( item) ;
@@ -990,6 +1037,16 @@ enum NameBindingKind<'a> {
9901037
9911038struct PrivacyError < ' a > ( Span , Name , & ' a NameBinding < ' a > ) ;
9921039
1040+ struct UseError < ' a > {
1041+ err : DiagnosticBuilder < ' a > ,
1042+ /// Attach `use` statements for these candidates
1043+ candidates : Vec < ImportSuggestion > ,
1044+ /// The node id of the module to place the use statements in
1045+ node_id : NodeId ,
1046+ /// Whether the diagnostic should state that it's "better"
1047+ better : bool ,
1048+ }
1049+
9931050struct AmbiguityError < ' a > {
9941051 span : Span ,
9951052 name : Name ,
@@ -1190,15 +1247,20 @@ pub struct Resolver<'a> {
11901247 extern_module_map : FxHashMap < ( DefId , bool /* MacrosOnly? */ ) , Module < ' a > > ,
11911248
11921249 pub make_glob_map : bool ,
1193- // Maps imports to the names of items actually imported (this actually maps
1194- // all imports, but only glob imports are actually interesting).
1250+ /// Maps imports to the names of items actually imported (this actually maps
1251+ /// all imports, but only glob imports are actually interesting).
11951252 pub glob_map : GlobMap ,
11961253
11971254 used_imports : FxHashSet < ( NodeId , Namespace ) > ,
11981255 pub maybe_unused_trait_imports : NodeSet ,
11991256
1257+ /// privacy errors are delayed until the end in order to deduplicate them
12001258 privacy_errors : Vec < PrivacyError < ' a > > ,
1259+ /// ambiguity errors are delayed for deduplication
12011260 ambiguity_errors : Vec < AmbiguityError < ' a > > ,
1261+ /// `use` injections are delayed for better placement and deduplication
1262+ use_injections : Vec < UseError < ' a > > ,
1263+
12021264 gated_errors : FxHashSet < Span > ,
12031265 disallowed_shadowing : Vec < & ' a LegacyBinding < ' a > > ,
12041266
@@ -1401,6 +1463,7 @@ impl<'a> Resolver<'a> {
14011463
14021464 privacy_errors : Vec :: new ( ) ,
14031465 ambiguity_errors : Vec :: new ( ) ,
1466+ use_injections : Vec :: new ( ) ,
14041467 gated_errors : FxHashSet ( ) ,
14051468 disallowed_shadowing : Vec :: new ( ) ,
14061469
@@ -1465,10 +1528,11 @@ impl<'a> Resolver<'a> {
14651528 ImportResolver { resolver : self } . finalize_imports ( ) ;
14661529 self . current_module = self . graph_root ;
14671530 self . finalize_current_module_macro_resolutions ( ) ;
1531+
14681532 visit:: walk_crate ( self , krate) ;
14691533
14701534 check_unused:: check_crate ( self , krate) ;
1471- self . report_errors ( ) ;
1535+ self . report_errors ( krate ) ;
14721536 self . crate_loader . postprocess ( krate) ;
14731537 }
14741538
@@ -2413,25 +2477,20 @@ impl<'a> Resolver<'a> {
24132477 __diagnostic_used ! ( E0411 ) ;
24142478 err. code ( "E0411" . into ( ) ) ;
24152479 err. span_label ( span, "`Self` is only available in traits and impls" ) ;
2416- return err;
2480+ return ( err, Vec :: new ( ) ) ;
24172481 }
24182482 if is_self_value ( path, ns) {
24192483 __diagnostic_used ! ( E0424 ) ;
24202484 err. code ( "E0424" . into ( ) ) ;
24212485 err. span_label ( span, format ! ( "`self` value is only available in \
24222486 methods with `self` parameter") ) ;
2423- return err;
2487+ return ( err, Vec :: new ( ) ) ;
24242488 }
24252489
24262490 // Try to lookup the name in more relaxed fashion for better error reporting.
24272491 let ident = * path. last ( ) . unwrap ( ) ;
24282492 let candidates = this. lookup_import_candidates ( ident. node . name , ns, is_expected) ;
2429- if !candidates. is_empty ( ) {
2430- let mut module_span = this. current_module . span ;
2431- module_span. hi = module_span. lo ;
2432- // Report import candidates as help and proceed searching for labels.
2433- show_candidates ( & mut err, module_span, & candidates, def. is_some ( ) ) ;
2434- } else if is_expected ( Def :: Enum ( DefId :: local ( CRATE_DEF_INDEX ) ) ) {
2493+ if candidates. is_empty ( ) && is_expected ( Def :: Enum ( DefId :: local ( CRATE_DEF_INDEX ) ) ) {
24352494 let enum_candidates =
24362495 this. lookup_import_candidates ( ident. node . name , ns, is_enum_variant) ;
24372496 let mut enum_candidates = enum_candidates. iter ( )
@@ -2471,7 +2530,7 @@ impl<'a> Resolver<'a> {
24712530 format ! ( "Self::{}" , path_str) ) ;
24722531 }
24732532 }
2474- return err;
2533+ return ( err, candidates ) ;
24752534 }
24762535 }
24772536
@@ -2488,22 +2547,22 @@ impl<'a> Resolver<'a> {
24882547 match ( def, source) {
24892548 ( Def :: Macro ( ..) , _) => {
24902549 err. span_label ( span, format ! ( "did you mean `{}!(...)`?" , path_str) ) ;
2491- return err;
2550+ return ( err, candidates ) ;
24922551 }
24932552 ( Def :: TyAlias ( ..) , PathSource :: Trait ) => {
24942553 err. span_label ( span, "type aliases cannot be used for traits" ) ;
2495- return err;
2554+ return ( err, candidates ) ;
24962555 }
24972556 ( Def :: Mod ( ..) , PathSource :: Expr ( Some ( parent) ) ) => match parent. node {
24982557 ExprKind :: Field ( _, ident) => {
24992558 err. span_label ( parent. span , format ! ( "did you mean `{}::{}`?" ,
25002559 path_str, ident. node) ) ;
2501- return err;
2560+ return ( err, candidates ) ;
25022561 }
25032562 ExprKind :: MethodCall ( ref segment, ..) => {
25042563 err. span_label ( parent. span , format ! ( "did you mean `{}::{}(...)`?" ,
25052564 path_str, segment. identifier) ) ;
2506- return err;
2565+ return ( err, candidates ) ;
25072566 }
25082567 _ => { }
25092568 } ,
@@ -2519,7 +2578,7 @@ impl<'a> Resolver<'a> {
25192578 }
25202579 err. span_label ( span, format ! ( "did you mean `{} {{ /* fields */ }}`?" ,
25212580 path_str) ) ;
2522- return err;
2581+ return ( err, candidates ) ;
25232582 }
25242583 _ => { }
25252584 }
@@ -2530,10 +2589,14 @@ impl<'a> Resolver<'a> {
25302589 err. span_label ( base_span, fallback_label) ;
25312590 this. type_ascription_suggestion ( & mut err, base_span) ;
25322591 }
2533- err
2592+ ( err, candidates )
25342593 } ;
25352594 let report_errors = |this : & mut Self , def : Option < Def > | {
2536- report_errors ( this, def) . emit ( ) ;
2595+ let ( err, candidates) = report_errors ( this, def) ;
2596+ let def_id = this. current_module . normal_ancestor_id ;
2597+ let node_id = this. definitions . as_local_node_id ( def_id) . unwrap ( ) ;
2598+ let better = def. is_some ( ) ;
2599+ this. use_injections . push ( UseError { err, candidates, node_id, better } ) ;
25372600 err_path_resolution ( )
25382601 } ;
25392602
@@ -3458,8 +3521,9 @@ impl<'a> Resolver<'a> {
34583521 vis. is_accessible_from ( module. normal_ancestor_id , self )
34593522 }
34603523
3461- fn report_errors ( & mut self ) {
3524+ fn report_errors ( & mut self , krate : & Crate ) {
34623525 self . report_shadowing_errors ( ) ;
3526+ self . report_with_use_injections ( krate) ;
34633527 let mut reported_spans = FxHashSet ( ) ;
34643528
34653529 for & AmbiguityError { span, name, b1, b2, lexical, legacy } in & self . ambiguity_errors {
@@ -3507,6 +3571,21 @@ impl<'a> Resolver<'a> {
35073571 }
35083572 }
35093573
3574+ fn report_with_use_injections ( & mut self , krate : & Crate ) {
3575+ for UseError { mut err, candidates, node_id, better } in self . use_injections . drain ( ..) {
3576+ let mut finder = UsePlacementFinder {
3577+ target_module : node_id,
3578+ span : None ,
3579+ } ;
3580+ visit:: walk_crate ( & mut finder, krate) ;
3581+ if !candidates. is_empty ( ) {
3582+ let span = finder. span . expect ( "did not find module" ) ;
3583+ show_candidates ( & mut err, span, & candidates, better) ;
3584+ }
3585+ err. emit ( ) ;
3586+ }
3587+ }
3588+
35103589 fn report_shadowing_errors ( & mut self ) {
35113590 for ( ident, scope) in replace ( & mut self . lexical_macro_resolutions , Vec :: new ( ) ) {
35123591 self . resolve_legacy_scope ( scope, ident, true ) ;
0 commit comments