@@ -581,6 +581,55 @@ impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
581581 }
582582}
583583
584+ struct UsePlacementFinder {
585+ target_module : NodeId ,
586+ span : Option < Span > ,
587+ found_use : bool ,
588+ }
589+
590+ impl < ' tcx > Visitor < ' tcx > for UsePlacementFinder {
591+ fn visit_mod (
592+ & mut self ,
593+ module : & ' tcx ast:: Mod ,
594+ _: Span ,
595+ _: & [ ast:: Attribute ] ,
596+ node_id : NodeId ,
597+ ) {
598+ if self . span . is_some ( ) {
599+ return ;
600+ }
601+ if node_id != self . target_module {
602+ visit:: walk_mod ( self , module) ;
603+ return ;
604+ }
605+ // find a use statement
606+ for item in & module. items {
607+ match item. node {
608+ ItemKind :: Use ( ..) => {
609+ // don't suggest placing a use before the prelude
610+ // import or other generated ones
611+ if item. span == DUMMY_SP {
612+ let mut span = item. span ;
613+ span. hi = span. lo ;
614+ self . span = Some ( span) ;
615+ self . found_use = true ;
616+ return ;
617+ }
618+ } ,
619+ // don't place use before extern crate
620+ ItemKind :: ExternCrate ( _) => { }
621+ // but place them before the first other item
622+ _ => if self . span . map_or ( true , |span| item. span < span ) {
623+ let mut span = item. span ;
624+ span. hi = span. lo ;
625+ self . span = Some ( span) ;
626+ } ,
627+ }
628+ }
629+ assert ! ( self . span. is_some( ) , "a file can't have no items and emit suggestions" ) ;
630+ }
631+ }
632+
584633impl < ' a , ' tcx > Visitor < ' tcx > for Resolver < ' a > {
585634 fn visit_item ( & mut self , item : & ' tcx Item ) {
586635 self . resolve_item ( item) ;
@@ -990,6 +1039,16 @@ enum NameBindingKind<'a> {
9901039
9911040struct PrivacyError < ' a > ( Span , Name , & ' a NameBinding < ' a > ) ;
9921041
1042+ struct UseError < ' a > {
1043+ err : DiagnosticBuilder < ' a > ,
1044+ /// Attach `use` statements for these candidates
1045+ candidates : Vec < ImportSuggestion > ,
1046+ /// The node id of the module to place the use statements in
1047+ node_id : NodeId ,
1048+ /// Whether the diagnostic should state that it's "better"
1049+ better : bool ,
1050+ }
1051+
9931052struct AmbiguityError < ' a > {
9941053 span : Span ,
9951054 name : Name ,
@@ -1190,15 +1249,20 @@ pub struct Resolver<'a> {
11901249 extern_module_map : FxHashMap < ( DefId , bool /* MacrosOnly? */ ) , Module < ' a > > ,
11911250
11921251 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).
1252+ /// Maps imports to the names of items actually imported (this actually maps
1253+ /// all imports, but only glob imports are actually interesting).
11951254 pub glob_map : GlobMap ,
11961255
11971256 used_imports : FxHashSet < ( NodeId , Namespace ) > ,
11981257 pub maybe_unused_trait_imports : NodeSet ,
11991258
1259+ /// privacy errors are delayed until the end in order to deduplicate them
12001260 privacy_errors : Vec < PrivacyError < ' a > > ,
1261+ /// ambiguity errors are delayed for deduplication
12011262 ambiguity_errors : Vec < AmbiguityError < ' a > > ,
1263+ /// `use` injections are delayed for better placement and deduplication
1264+ use_injections : Vec < UseError < ' a > > ,
1265+
12021266 gated_errors : FxHashSet < Span > ,
12031267 disallowed_shadowing : Vec < & ' a LegacyBinding < ' a > > ,
12041268
@@ -1401,6 +1465,7 @@ impl<'a> Resolver<'a> {
14011465
14021466 privacy_errors : Vec :: new ( ) ,
14031467 ambiguity_errors : Vec :: new ( ) ,
1468+ use_injections : Vec :: new ( ) ,
14041469 gated_errors : FxHashSet ( ) ,
14051470 disallowed_shadowing : Vec :: new ( ) ,
14061471
@@ -1465,10 +1530,11 @@ impl<'a> Resolver<'a> {
14651530 ImportResolver { resolver : self } . finalize_imports ( ) ;
14661531 self . current_module = self . graph_root ;
14671532 self . finalize_current_module_macro_resolutions ( ) ;
1533+
14681534 visit:: walk_crate ( self , krate) ;
14691535
14701536 check_unused:: check_crate ( self , krate) ;
1471- self . report_errors ( ) ;
1537+ self . report_errors ( krate ) ;
14721538 self . crate_loader . postprocess ( krate) ;
14731539 }
14741540
@@ -2413,25 +2479,20 @@ impl<'a> Resolver<'a> {
24132479 __diagnostic_used ! ( E0411 ) ;
24142480 err. code ( "E0411" . into ( ) ) ;
24152481 err. span_label ( span, "`Self` is only available in traits and impls" ) ;
2416- return err;
2482+ return ( err, Vec :: new ( ) ) ;
24172483 }
24182484 if is_self_value ( path, ns) {
24192485 __diagnostic_used ! ( E0424 ) ;
24202486 err. code ( "E0424" . into ( ) ) ;
24212487 err. span_label ( span, format ! ( "`self` value is only available in \
24222488 methods with `self` parameter") ) ;
2423- return err;
2489+ return ( err, Vec :: new ( ) ) ;
24242490 }
24252491
24262492 // Try to lookup the name in more relaxed fashion for better error reporting.
24272493 let ident = * path. last ( ) . unwrap ( ) ;
24282494 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 ) ) ) {
2495+ if candidates. is_empty ( ) && is_expected ( Def :: Enum ( DefId :: local ( CRATE_DEF_INDEX ) ) ) {
24352496 let enum_candidates =
24362497 this. lookup_import_candidates ( ident. node . name , ns, is_enum_variant) ;
24372498 let mut enum_candidates = enum_candidates. iter ( )
@@ -2471,7 +2532,7 @@ impl<'a> Resolver<'a> {
24712532 format ! ( "Self::{}" , path_str) ) ;
24722533 }
24732534 }
2474- return err;
2535+ return ( err, candidates ) ;
24752536 }
24762537 }
24772538
@@ -2488,22 +2549,22 @@ impl<'a> Resolver<'a> {
24882549 match ( def, source) {
24892550 ( Def :: Macro ( ..) , _) => {
24902551 err. span_label ( span, format ! ( "did you mean `{}!(...)`?" , path_str) ) ;
2491- return err;
2552+ return ( err, candidates ) ;
24922553 }
24932554 ( Def :: TyAlias ( ..) , PathSource :: Trait ) => {
24942555 err. span_label ( span, "type aliases cannot be used for traits" ) ;
2495- return err;
2556+ return ( err, candidates ) ;
24962557 }
24972558 ( Def :: Mod ( ..) , PathSource :: Expr ( Some ( parent) ) ) => match parent. node {
24982559 ExprKind :: Field ( _, ident) => {
24992560 err. span_label ( parent. span , format ! ( "did you mean `{}::{}`?" ,
25002561 path_str, ident. node) ) ;
2501- return err;
2562+ return ( err, candidates ) ;
25022563 }
25032564 ExprKind :: MethodCall ( ref segment, ..) => {
25042565 err. span_label ( parent. span , format ! ( "did you mean `{}::{}(...)`?" ,
25052566 path_str, segment. identifier) ) ;
2506- return err;
2567+ return ( err, candidates ) ;
25072568 }
25082569 _ => { }
25092570 } ,
@@ -2519,7 +2580,7 @@ impl<'a> Resolver<'a> {
25192580 }
25202581 err. span_label ( span, format ! ( "did you mean `{} {{ /* fields */ }}`?" ,
25212582 path_str) ) ;
2522- return err;
2583+ return ( err, candidates ) ;
25232584 }
25242585 _ => { }
25252586 }
@@ -2530,10 +2591,14 @@ impl<'a> Resolver<'a> {
25302591 err. span_label ( base_span, fallback_label) ;
25312592 this. type_ascription_suggestion ( & mut err, base_span) ;
25322593 }
2533- err
2594+ ( err, candidates )
25342595 } ;
25352596 let report_errors = |this : & mut Self , def : Option < Def > | {
2536- report_errors ( this, def) . emit ( ) ;
2597+ let ( err, candidates) = report_errors ( this, def) ;
2598+ let def_id = this. current_module . normal_ancestor_id ;
2599+ let node_id = this. definitions . as_local_node_id ( def_id) . unwrap ( ) ;
2600+ let better = def. is_some ( ) ;
2601+ this. use_injections . push ( UseError { err, candidates, node_id, better } ) ;
25372602 err_path_resolution ( )
25382603 } ;
25392604
@@ -3458,8 +3523,9 @@ impl<'a> Resolver<'a> {
34583523 vis. is_accessible_from ( module. normal_ancestor_id , self )
34593524 }
34603525
3461- fn report_errors ( & mut self ) {
3526+ fn report_errors ( & mut self , krate : & Crate ) {
34623527 self . report_shadowing_errors ( ) ;
3528+ self . report_with_use_injections ( krate) ;
34633529 let mut reported_spans = FxHashSet ( ) ;
34643530
34653531 for & AmbiguityError { span, name, b1, b2, lexical, legacy } in & self . ambiguity_errors {
@@ -3507,6 +3573,22 @@ impl<'a> Resolver<'a> {
35073573 }
35083574 }
35093575
3576+ fn report_with_use_injections ( & mut self , krate : & Crate ) {
3577+ for UseError { mut err, candidates, node_id, better } in self . use_injections . drain ( ..) {
3578+ let mut finder = UsePlacementFinder {
3579+ target_module : node_id,
3580+ span : None ,
3581+ found_use : false ,
3582+ } ;
3583+ visit:: walk_crate ( & mut finder, krate) ;
3584+ if !candidates. is_empty ( ) {
3585+ let span = finder. span . expect ( "did not find module" ) ;
3586+ show_candidates ( & mut err, span, & candidates, better, finder. found_use ) ;
3587+ }
3588+ err. emit ( ) ;
3589+ }
3590+ }
3591+
35103592 fn report_shadowing_errors ( & mut self ) {
35113593 for ( ident, scope) in replace ( & mut self . lexical_macro_resolutions , Vec :: new ( ) ) {
35123594 self . resolve_legacy_scope ( scope, ident, true ) ;
@@ -3697,7 +3779,8 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St
36973779fn show_candidates ( err : & mut DiagnosticBuilder ,
36983780 span : Span ,
36993781 candidates : & [ ImportSuggestion ] ,
3700- better : bool ) {
3782+ better : bool ,
3783+ found_use : bool ) {
37013784
37023785 // we want consistent results across executions, but candidates are produced
37033786 // by iterating through a hash map, so make sure they are ordered:
@@ -3713,7 +3796,14 @@ fn show_candidates(err: &mut DiagnosticBuilder,
37133796 let msg = format ! ( "possible {}candidate{} into scope" , better, msg_diff) ;
37143797
37153798 for candidate in & mut path_strings {
3716- * candidate = format ! ( "use {};\n " , candidate) ;
3799+ // produce an additional newline to separate the new use statement
3800+ // from the directly following item.
3801+ let additional_newline = if found_use {
3802+ ""
3803+ } else {
3804+ "\n "
3805+ } ;
3806+ * candidate = format ! ( "use {};\n {}" , candidate, additional_newline) ;
37173807 }
37183808
37193809 err. span_suggestions ( span, & msg, path_strings) ;
0 commit comments