@@ -60,8 +60,8 @@ enum ResolutionFailure<'a> {
60
60
/// This has a partial resolution, but is not in the TypeNS and so cannot
61
61
/// have associated items or fields.
62
62
CannotHaveAssociatedItems ( Res , Namespace ) ,
63
- /// `String ` is the base name of the path (not necessarily the whole link)
64
- NotInScope ( Cow < ' a , str > ) ,
63
+ /// `name ` is the base name of the path (not necessarily the whole link)
64
+ NotInScope { module_id : DefId , name : Cow < ' a , str > } ,
65
65
/// this is a primitive type without an impls (no associated methods)
66
66
/// when will this actually happen?
67
67
/// the `Res` is the primitive it resolved to
@@ -92,7 +92,7 @@ impl ResolutionFailure<'a> {
92
92
| NotAVariant ( res, _)
93
93
| WrongNamespace ( res, _)
94
94
| CannotHaveAssociatedItems ( res, _) => Some ( * res) ,
95
- NotInScope ( _ ) | NoParentItem | Dummy => None ,
95
+ NotInScope { .. } | NoParentItem | Dummy => None ,
96
96
}
97
97
}
98
98
@@ -142,7 +142,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
142
142
. expect ( "fold_item should ensure link is non-empty" ) ;
143
143
let variant_name =
144
144
// we're not sure this is a variant at all, so use the full string
145
- split. next ( ) . map ( |f| Symbol :: intern ( f) ) . ok_or ( ErrorKind :: Resolve ( ResolutionFailure :: NotInScope ( path_str. into ( ) ) ) ) ?;
145
+ split. next ( ) . map ( |f| Symbol :: intern ( f) ) . ok_or ( ErrorKind :: Resolve ( ResolutionFailure :: NotInScope {
146
+ module_id,
147
+ name : path_str. into ( ) ,
148
+ } ) ) ?;
146
149
let path = split
147
150
. next ( )
148
151
. map ( |f| {
@@ -153,38 +156,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
153
156
}
154
157
f. to_owned ( )
155
158
} )
156
- . ok_or ( ErrorKind :: Resolve ( ResolutionFailure :: NotInScope (
157
- variant_name. to_string ( ) . into ( ) ,
158
- ) ) ) ?;
159
+ . ok_or ( ErrorKind :: Resolve ( ResolutionFailure :: NotInScope {
160
+ module_id,
161
+ name : variant_name. to_string ( ) . into ( ) ,
162
+ } ) ) ?;
159
163
let ty_res = cx
160
164
. enter_resolver ( |resolver| {
161
165
resolver. resolve_str_path_error ( DUMMY_SP , & path, TypeNS , module_id)
162
166
} )
163
167
. map ( |( _, res) | res)
164
168
. unwrap_or ( Res :: Err ) ;
165
- // This code only gets hit if three path segments in a row don't get resolved.
166
- // It's a good time to check if _any_ parent of the path gets resolved.
167
- // If so, report it and say the first which failed; if not, say the first path segment didn't resolve.
168
169
if let Res :: Err = ty_res {
169
- let mut current = path. as_str ( ) ;
170
- while let Some ( parent) = current. rsplitn ( 2 , "::" ) . nth ( 1 ) {
171
- current = parent;
172
- if let Some ( res) = self . check_full_res (
173
- TypeNS ,
174
- & current,
175
- Some ( module_id) ,
176
- current_item,
177
- extra_fragment,
178
- ) {
179
- return Err ( ErrorKind :: Resolve ( ResolutionFailure :: NoAssocItem (
180
- res,
181
- Symbol :: intern ( & path) ,
182
- ) ) ) ;
183
- }
184
- }
185
- return Err ( ErrorKind :: Resolve ( ResolutionFailure :: NotInScope (
186
- current. to_string ( ) . into ( ) ,
187
- ) ) ) ;
170
+ return Err ( ErrorKind :: Resolve ( ResolutionFailure :: NotInScope {
171
+ module_id,
172
+ name : path. into ( ) ,
173
+ } ) ) ;
188
174
}
189
175
let ty_res = ty_res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
190
176
match ty_res {
@@ -301,7 +287,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
301
287
} ) ;
302
288
}
303
289
}
304
- Err ( ResolutionFailure :: NotInScope ( path_str. into ( ) ) )
290
+ Err ( ResolutionFailure :: NotInScope {
291
+ module_id : parent_id. expect ( "already saw `Some` when resolving as a macro" ) ,
292
+ name : path_str. into ( ) ,
293
+ } )
305
294
} )
306
295
}
307
296
/// Resolves a string as a path within a particular namespace. Also returns an optional
@@ -384,7 +373,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
384
373
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
385
374
. ok_or_else ( || {
386
375
debug ! ( "found no `::`, assumming {} was correctly not in scope" , item_name) ;
387
- ErrorKind :: Resolve ( ResolutionFailure :: NotInScope ( item_name. to_string ( ) . into ( ) ) )
376
+ ErrorKind :: Resolve ( ResolutionFailure :: NotInScope {
377
+ module_id,
378
+ name : item_name. to_string ( ) . into ( ) ,
379
+ } )
388
380
} ) ?;
389
381
390
382
if let Some ( ( path, prim) ) = is_primitive ( & path_root, TypeNS ) {
@@ -451,7 +443,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
451
443
}
452
444
}
453
445
}
454
- ResolutionFailure :: NotInScope ( path_root. into ( ) )
446
+ ResolutionFailure :: NotInScope { module_id , name : path_root. into ( ) }
455
447
} ) ;
456
448
Err ( ErrorKind :: Resolve ( kind) )
457
449
} ;
@@ -996,7 +988,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
996
988
}
997
989
}
998
990
resolution_failure (
999
- cx ,
991
+ self ,
1000
992
& item,
1001
993
path_str,
1002
994
disambiguator,
@@ -1076,7 +1068,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
1076
1068
if len == 0 {
1077
1069
drop ( candidates_iter) ;
1078
1070
resolution_failure (
1079
- cx ,
1071
+ self ,
1080
1072
& item,
1081
1073
path_str,
1082
1074
disambiguator,
@@ -1096,8 +1088,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
1096
1088
} else {
1097
1089
drop ( candidates_iter) ;
1098
1090
if is_derive_trait_collision ( & candidates) {
1099
- candidates. macro_ns =
1100
- Err ( ResolutionFailure :: NotInScope ( path_str. into ( ) ) ) ;
1091
+ candidates. macro_ns = Err ( ResolutionFailure :: Dummy ) ;
1101
1092
}
1102
1093
// If we're reporting an ambiguity, don't mention the namespaces that failed
1103
1094
let candidates =
@@ -1131,7 +1122,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
1131
1122
}
1132
1123
}
1133
1124
resolution_failure (
1134
- cx ,
1125
+ self ,
1135
1126
& item,
1136
1127
path_str,
1137
1128
disambiguator,
@@ -1507,7 +1498,7 @@ fn report_diagnostic(
1507
1498
}
1508
1499
1509
1500
fn resolution_failure (
1510
- cx : & DocContext < ' _ > ,
1501
+ collector : & LinkCollector < ' _ , ' _ > ,
1511
1502
item : & Item ,
1512
1503
path_str : & str ,
1513
1504
disambiguator : Option < Disambiguator > ,
@@ -1516,19 +1507,23 @@ fn resolution_failure(
1516
1507
kinds : SmallVec < [ ResolutionFailure < ' _ > ; 3 ] > ,
1517
1508
) {
1518
1509
report_diagnostic (
1519
- cx,
1510
+ collector . cx ,
1520
1511
& format ! ( "unresolved link to `{}`" , path_str) ,
1521
1512
item,
1522
1513
dox,
1523
1514
& link_range,
1524
1515
|diag, sp| {
1525
1516
let in_scope = kinds. iter ( ) . any ( |kind| kind. res ( ) . is_some ( ) ) ;
1526
1517
let item = |res : Res | {
1527
- format ! ( "the {} `{}`" , res. descr( ) , cx. tcx. item_name( res. def_id( ) ) . to_string( ) )
1518
+ format ! (
1519
+ "the {} `{}`" ,
1520
+ res. descr( ) ,
1521
+ collector. cx. tcx. item_name( res. def_id( ) ) . to_string( )
1522
+ )
1528
1523
} ;
1529
1524
let assoc_item_not_allowed = |res : Res , diag : & mut DiagnosticBuilder < ' _ > | {
1530
1525
let def_id = res. def_id ( ) ;
1531
- let name = cx. tcx . item_name ( def_id) ;
1526
+ let name = collector . cx . tcx . item_name ( def_id) ;
1532
1527
let note = format ! (
1533
1528
"`{}` is {} {}, not a module or type, and cannot have associated items" ,
1534
1529
name,
@@ -1539,18 +1534,42 @@ fn resolution_failure(
1539
1534
} ;
1540
1535
// ignore duplicates
1541
1536
let mut variants_seen = SmallVec :: < [ _ ; 3 ] > :: new ( ) ;
1542
- for failure in kinds {
1537
+ for mut failure in kinds {
1538
+ // Check if _any_ parent of the path gets resolved.
1539
+ // If so, report it and say the first which failed; if not, say the first path segment didn't resolve.
1540
+ if let ResolutionFailure :: NotInScope { module_id, name } = & mut failure {
1541
+ let mut current = name. as_ref ( ) ;
1542
+ loop {
1543
+ current = match current. rsplitn ( 2 , "::" ) . nth ( 1 ) {
1544
+ Some ( p) => p,
1545
+ None => {
1546
+ * name = current. to_owned ( ) . into ( ) ;
1547
+ break ;
1548
+ }
1549
+ } ;
1550
+ if let Some ( res) = collector. check_full_res (
1551
+ TypeNS ,
1552
+ & current,
1553
+ Some ( * module_id) ,
1554
+ & None ,
1555
+ & None ,
1556
+ ) {
1557
+ failure = ResolutionFailure :: NoAssocItem ( res, Symbol :: intern ( current) ) ;
1558
+ break ;
1559
+ }
1560
+ }
1561
+ }
1543
1562
let variant = std:: mem:: discriminant ( & failure) ;
1544
1563
if variants_seen. contains ( & variant) {
1545
1564
continue ;
1546
1565
}
1547
1566
variants_seen. push ( variant) ;
1548
1567
match failure {
1549
- ResolutionFailure :: NotInScope ( base ) => {
1568
+ ResolutionFailure :: NotInScope { name , .. } => {
1550
1569
if in_scope {
1551
1570
continue ;
1552
1571
}
1553
- diag. note ( & format ! ( "no item named `{}` is in scope" , base ) ) ;
1572
+ diag. note ( & format ! ( "no item named `{}` is in scope" , name ) ) ;
1554
1573
// If the link has `::` in the path, assume it's meant to be an intra-doc link
1555
1574
if !path_str. contains ( "::" ) {
1556
1575
// Otherwise, the `[]` might be unrelated.
@@ -1608,7 +1627,7 @@ fn resolution_failure(
1608
1627
x,
1609
1628
) ,
1610
1629
} ;
1611
- let name = cx. tcx . item_name ( def_id) ;
1630
+ let name = collector . cx . tcx . item_name ( def_id) ;
1612
1631
let path_description = if let Some ( disambiguator) = disambiguator {
1613
1632
disambiguator. descr ( )
1614
1633
} else {
0 commit comments