@@ -581,6 +581,55 @@ impl<T> ::std::ops::IndexMut<Namespace> for PerNS<T> {
581
581
}
582
582
}
583
583
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
+
584
633
impl < ' a , ' tcx > Visitor < ' tcx > for Resolver < ' a > {
585
634
fn visit_item ( & mut self , item : & ' tcx Item ) {
586
635
self . resolve_item ( item) ;
@@ -990,6 +1039,16 @@ enum NameBindingKind<'a> {
990
1039
991
1040
struct PrivacyError < ' a > ( Span , Name , & ' a NameBinding < ' a > ) ;
992
1041
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
+
993
1052
struct AmbiguityError < ' a > {
994
1053
span : Span ,
995
1054
name : Name ,
@@ -1190,15 +1249,20 @@ pub struct Resolver<'a> {
1190
1249
extern_module_map : FxHashMap < ( DefId , bool /* MacrosOnly? */ ) , Module < ' a > > ,
1191
1250
1192
1251
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).
1195
1254
pub glob_map : GlobMap ,
1196
1255
1197
1256
used_imports : FxHashSet < ( NodeId , Namespace ) > ,
1198
1257
pub maybe_unused_trait_imports : NodeSet ,
1199
1258
1259
+ /// privacy errors are delayed until the end in order to deduplicate them
1200
1260
privacy_errors : Vec < PrivacyError < ' a > > ,
1261
+ /// ambiguity errors are delayed for deduplication
1201
1262
ambiguity_errors : Vec < AmbiguityError < ' a > > ,
1263
+ /// `use` injections are delayed for better placement and deduplication
1264
+ use_injections : Vec < UseError < ' a > > ,
1265
+
1202
1266
gated_errors : FxHashSet < Span > ,
1203
1267
disallowed_shadowing : Vec < & ' a LegacyBinding < ' a > > ,
1204
1268
@@ -1401,6 +1465,7 @@ impl<'a> Resolver<'a> {
1401
1465
1402
1466
privacy_errors : Vec :: new ( ) ,
1403
1467
ambiguity_errors : Vec :: new ( ) ,
1468
+ use_injections : Vec :: new ( ) ,
1404
1469
gated_errors : FxHashSet ( ) ,
1405
1470
disallowed_shadowing : Vec :: new ( ) ,
1406
1471
@@ -1465,10 +1530,11 @@ impl<'a> Resolver<'a> {
1465
1530
ImportResolver { resolver : self } . finalize_imports ( ) ;
1466
1531
self . current_module = self . graph_root ;
1467
1532
self . finalize_current_module_macro_resolutions ( ) ;
1533
+
1468
1534
visit:: walk_crate ( self , krate) ;
1469
1535
1470
1536
check_unused:: check_crate ( self , krate) ;
1471
- self . report_errors ( ) ;
1537
+ self . report_errors ( krate ) ;
1472
1538
self . crate_loader . postprocess ( krate) ;
1473
1539
}
1474
1540
@@ -2413,25 +2479,20 @@ impl<'a> Resolver<'a> {
2413
2479
__diagnostic_used ! ( E0411 ) ;
2414
2480
err. code ( "E0411" . into ( ) ) ;
2415
2481
err. span_label ( span, "`Self` is only available in traits and impls" ) ;
2416
- return err;
2482
+ return ( err, Vec :: new ( ) ) ;
2417
2483
}
2418
2484
if is_self_value ( path, ns) {
2419
2485
__diagnostic_used ! ( E0424 ) ;
2420
2486
err. code ( "E0424" . into ( ) ) ;
2421
2487
err. span_label ( span, format ! ( "`self` value is only available in \
2422
2488
methods with `self` parameter") ) ;
2423
- return err;
2489
+ return ( err, Vec :: new ( ) ) ;
2424
2490
}
2425
2491
2426
2492
// Try to lookup the name in more relaxed fashion for better error reporting.
2427
2493
let ident = * path. last ( ) . unwrap ( ) ;
2428
2494
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 ) ) ) {
2435
2496
let enum_candidates =
2436
2497
this. lookup_import_candidates ( ident. node . name , ns, is_enum_variant) ;
2437
2498
let mut enum_candidates = enum_candidates. iter ( )
@@ -2471,7 +2532,7 @@ impl<'a> Resolver<'a> {
2471
2532
format ! ( "Self::{}" , path_str) ) ;
2472
2533
}
2473
2534
}
2474
- return err;
2535
+ return ( err, candidates ) ;
2475
2536
}
2476
2537
}
2477
2538
@@ -2488,22 +2549,22 @@ impl<'a> Resolver<'a> {
2488
2549
match ( def, source) {
2489
2550
( Def :: Macro ( ..) , _) => {
2490
2551
err. span_label ( span, format ! ( "did you mean `{}!(...)`?" , path_str) ) ;
2491
- return err;
2552
+ return ( err, candidates ) ;
2492
2553
}
2493
2554
( Def :: TyAlias ( ..) , PathSource :: Trait ) => {
2494
2555
err. span_label ( span, "type aliases cannot be used for traits" ) ;
2495
- return err;
2556
+ return ( err, candidates ) ;
2496
2557
}
2497
2558
( Def :: Mod ( ..) , PathSource :: Expr ( Some ( parent) ) ) => match parent. node {
2498
2559
ExprKind :: Field ( _, ident) => {
2499
2560
err. span_label ( parent. span , format ! ( "did you mean `{}::{}`?" ,
2500
2561
path_str, ident. node) ) ;
2501
- return err;
2562
+ return ( err, candidates ) ;
2502
2563
}
2503
2564
ExprKind :: MethodCall ( ref segment, ..) => {
2504
2565
err. span_label ( parent. span , format ! ( "did you mean `{}::{}(...)`?" ,
2505
2566
path_str, segment. identifier) ) ;
2506
- return err;
2567
+ return ( err, candidates ) ;
2507
2568
}
2508
2569
_ => { }
2509
2570
} ,
@@ -2519,7 +2580,7 @@ impl<'a> Resolver<'a> {
2519
2580
}
2520
2581
err. span_label ( span, format ! ( "did you mean `{} {{ /* fields */ }}`?" ,
2521
2582
path_str) ) ;
2522
- return err;
2583
+ return ( err, candidates ) ;
2523
2584
}
2524
2585
_ => { }
2525
2586
}
@@ -2530,10 +2591,14 @@ impl<'a> Resolver<'a> {
2530
2591
err. span_label ( base_span, fallback_label) ;
2531
2592
this. type_ascription_suggestion ( & mut err, base_span) ;
2532
2593
}
2533
- err
2594
+ ( err, candidates )
2534
2595
} ;
2535
2596
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 } ) ;
2537
2602
err_path_resolution ( )
2538
2603
} ;
2539
2604
@@ -3458,8 +3523,9 @@ impl<'a> Resolver<'a> {
3458
3523
vis. is_accessible_from ( module. normal_ancestor_id , self )
3459
3524
}
3460
3525
3461
- fn report_errors ( & mut self ) {
3526
+ fn report_errors ( & mut self , krate : & Crate ) {
3462
3527
self . report_shadowing_errors ( ) ;
3528
+ self . report_with_use_injections ( krate) ;
3463
3529
let mut reported_spans = FxHashSet ( ) ;
3464
3530
3465
3531
for & AmbiguityError { span, name, b1, b2, lexical, legacy } in & self . ambiguity_errors {
@@ -3507,6 +3573,22 @@ impl<'a> Resolver<'a> {
3507
3573
}
3508
3574
}
3509
3575
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
+
3510
3592
fn report_shadowing_errors ( & mut self ) {
3511
3593
for ( ident, scope) in replace ( & mut self . lexical_macro_resolutions , Vec :: new ( ) ) {
3512
3594
self . resolve_legacy_scope ( scope, ident, true ) ;
@@ -3697,7 +3779,8 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St
3697
3779
fn show_candidates ( err : & mut DiagnosticBuilder ,
3698
3780
span : Span ,
3699
3781
candidates : & [ ImportSuggestion ] ,
3700
- better : bool ) {
3782
+ better : bool ,
3783
+ found_use : bool ) {
3701
3784
3702
3785
// we want consistent results across executions, but candidates are produced
3703
3786
// by iterating through a hash map, so make sure they are ordered:
@@ -3713,7 +3796,14 @@ fn show_candidates(err: &mut DiagnosticBuilder,
3713
3796
let msg = format ! ( "possible {}candidate{} into scope" , better, msg_diff) ;
3714
3797
3715
3798
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) ;
3717
3807
}
3718
3808
3719
3809
err. span_suggestions ( span, & msg, path_strings) ;
0 commit comments