@@ -581,6 +581,53 @@ 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
+ }
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
+
584
631
impl < ' a , ' tcx > Visitor < ' tcx > for Resolver < ' a > {
585
632
fn visit_item ( & mut self , item : & ' tcx Item ) {
586
633
self . resolve_item ( item) ;
@@ -990,6 +1037,16 @@ enum NameBindingKind<'a> {
990
1037
991
1038
struct PrivacyError < ' a > ( Span , Name , & ' a NameBinding < ' a > ) ;
992
1039
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
+
993
1050
struct AmbiguityError < ' a > {
994
1051
span : Span ,
995
1052
name : Name ,
@@ -1190,15 +1247,20 @@ pub struct Resolver<'a> {
1190
1247
extern_module_map : FxHashMap < ( DefId , bool /* MacrosOnly? */ ) , Module < ' a > > ,
1191
1248
1192
1249
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).
1195
1252
pub glob_map : GlobMap ,
1196
1253
1197
1254
used_imports : FxHashSet < ( NodeId , Namespace ) > ,
1198
1255
pub maybe_unused_trait_imports : NodeSet ,
1199
1256
1257
+ /// privacy errors are delayed until the end in order to deduplicate them
1200
1258
privacy_errors : Vec < PrivacyError < ' a > > ,
1259
+ /// ambiguity errors are delayed for deduplication
1201
1260
ambiguity_errors : Vec < AmbiguityError < ' a > > ,
1261
+ /// `use` injections are delayed for better placement and deduplication
1262
+ use_injections : Vec < UseError < ' a > > ,
1263
+
1202
1264
gated_errors : FxHashSet < Span > ,
1203
1265
disallowed_shadowing : Vec < & ' a LegacyBinding < ' a > > ,
1204
1266
@@ -1401,6 +1463,7 @@ impl<'a> Resolver<'a> {
1401
1463
1402
1464
privacy_errors : Vec :: new ( ) ,
1403
1465
ambiguity_errors : Vec :: new ( ) ,
1466
+ use_injections : Vec :: new ( ) ,
1404
1467
gated_errors : FxHashSet ( ) ,
1405
1468
disallowed_shadowing : Vec :: new ( ) ,
1406
1469
@@ -1465,10 +1528,11 @@ impl<'a> Resolver<'a> {
1465
1528
ImportResolver { resolver : self } . finalize_imports ( ) ;
1466
1529
self . current_module = self . graph_root ;
1467
1530
self . finalize_current_module_macro_resolutions ( ) ;
1531
+
1468
1532
visit:: walk_crate ( self , krate) ;
1469
1533
1470
1534
check_unused:: check_crate ( self , krate) ;
1471
- self . report_errors ( ) ;
1535
+ self . report_errors ( krate ) ;
1472
1536
self . crate_loader . postprocess ( krate) ;
1473
1537
}
1474
1538
@@ -2413,25 +2477,20 @@ impl<'a> Resolver<'a> {
2413
2477
__diagnostic_used ! ( E0411 ) ;
2414
2478
err. code ( "E0411" . into ( ) ) ;
2415
2479
err. span_label ( span, "`Self` is only available in traits and impls" ) ;
2416
- return err;
2480
+ return ( err, Vec :: new ( ) ) ;
2417
2481
}
2418
2482
if is_self_value ( path, ns) {
2419
2483
__diagnostic_used ! ( E0424 ) ;
2420
2484
err. code ( "E0424" . into ( ) ) ;
2421
2485
err. span_label ( span, format ! ( "`self` value is only available in \
2422
2486
methods with `self` parameter") ) ;
2423
- return err;
2487
+ return ( err, Vec :: new ( ) ) ;
2424
2488
}
2425
2489
2426
2490
// Try to lookup the name in more relaxed fashion for better error reporting.
2427
2491
let ident = * path. last ( ) . unwrap ( ) ;
2428
2492
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 ) ) ) {
2435
2494
let enum_candidates =
2436
2495
this. lookup_import_candidates ( ident. node . name , ns, is_enum_variant) ;
2437
2496
let mut enum_candidates = enum_candidates. iter ( )
@@ -2471,7 +2530,7 @@ impl<'a> Resolver<'a> {
2471
2530
format ! ( "Self::{}" , path_str) ) ;
2472
2531
}
2473
2532
}
2474
- return err;
2533
+ return ( err, candidates ) ;
2475
2534
}
2476
2535
}
2477
2536
@@ -2488,22 +2547,22 @@ impl<'a> Resolver<'a> {
2488
2547
match ( def, source) {
2489
2548
( Def :: Macro ( ..) , _) => {
2490
2549
err. span_label ( span, format ! ( "did you mean `{}!(...)`?" , path_str) ) ;
2491
- return err;
2550
+ return ( err, candidates ) ;
2492
2551
}
2493
2552
( Def :: TyAlias ( ..) , PathSource :: Trait ) => {
2494
2553
err. span_label ( span, "type aliases cannot be used for traits" ) ;
2495
- return err;
2554
+ return ( err, candidates ) ;
2496
2555
}
2497
2556
( Def :: Mod ( ..) , PathSource :: Expr ( Some ( parent) ) ) => match parent. node {
2498
2557
ExprKind :: Field ( _, ident) => {
2499
2558
err. span_label ( parent. span , format ! ( "did you mean `{}::{}`?" ,
2500
2559
path_str, ident. node) ) ;
2501
- return err;
2560
+ return ( err, candidates ) ;
2502
2561
}
2503
2562
ExprKind :: MethodCall ( ref segment, ..) => {
2504
2563
err. span_label ( parent. span , format ! ( "did you mean `{}::{}(...)`?" ,
2505
2564
path_str, segment. identifier) ) ;
2506
- return err;
2565
+ return ( err, candidates ) ;
2507
2566
}
2508
2567
_ => { }
2509
2568
} ,
@@ -2519,7 +2578,7 @@ impl<'a> Resolver<'a> {
2519
2578
}
2520
2579
err. span_label ( span, format ! ( "did you mean `{} {{ /* fields */ }}`?" ,
2521
2580
path_str) ) ;
2522
- return err;
2581
+ return ( err, candidates ) ;
2523
2582
}
2524
2583
_ => { }
2525
2584
}
@@ -2530,10 +2589,14 @@ impl<'a> Resolver<'a> {
2530
2589
err. span_label ( base_span, fallback_label) ;
2531
2590
this. type_ascription_suggestion ( & mut err, base_span) ;
2532
2591
}
2533
- err
2592
+ ( err, candidates )
2534
2593
} ;
2535
2594
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 } ) ;
2537
2600
err_path_resolution ( )
2538
2601
} ;
2539
2602
@@ -3458,8 +3521,9 @@ impl<'a> Resolver<'a> {
3458
3521
vis. is_accessible_from ( module. normal_ancestor_id , self )
3459
3522
}
3460
3523
3461
- fn report_errors ( & mut self ) {
3524
+ fn report_errors ( & mut self , krate : & Crate ) {
3462
3525
self . report_shadowing_errors ( ) ;
3526
+ self . report_with_use_injections ( krate) ;
3463
3527
let mut reported_spans = FxHashSet ( ) ;
3464
3528
3465
3529
for & AmbiguityError { span, name, b1, b2, lexical, legacy } in & self . ambiguity_errors {
@@ -3507,6 +3571,21 @@ impl<'a> Resolver<'a> {
3507
3571
}
3508
3572
}
3509
3573
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
+
3510
3589
fn report_shadowing_errors ( & mut self ) {
3511
3590
for ( ident, scope) in replace ( & mut self . lexical_macro_resolutions , Vec :: new ( ) ) {
3512
3591
self . resolve_legacy_scope ( scope, ident, true ) ;
0 commit comments