@@ -60,8 +60,8 @@ enum ResolutionFailure<'a> {
6060 /// This has a partial resolution, but is not in the TypeNS and so cannot
6161 /// have associated items or fields.
6262 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 > } ,
6565 /// this is a primitive type without an impls (no associated methods)
6666 /// when will this actually happen?
6767 /// the `Res` is the primitive it resolved to
@@ -92,7 +92,7 @@ impl ResolutionFailure<'a> {
9292 | NotAVariant ( res, _)
9393 | WrongNamespace ( res, _)
9494 | CannotHaveAssociatedItems ( res, _) => Some ( * res) ,
95- NotInScope ( _ ) | NoParentItem | Dummy => None ,
95+ NotInScope { .. } | NoParentItem | Dummy => None ,
9696 }
9797 }
9898
@@ -142,7 +142,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
142142 . expect ( "fold_item should ensure link is non-empty" ) ;
143143 let variant_name =
144144 // 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+ } ) ) ?;
146149 let path = split
147150 . next ( )
148151 . map ( |f| {
@@ -153,38 +156,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
153156 }
154157 f. to_owned ( )
155158 } )
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+ } ) ) ?;
159163 let ty_res = cx
160164 . enter_resolver ( |resolver| {
161165 resolver. resolve_str_path_error ( DUMMY_SP , & path, TypeNS , module_id)
162166 } )
163167 . map ( |( _, res) | res)
164168 . 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.
168169 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+ } ) ) ;
188174 }
189175 let ty_res = ty_res. map_id ( |_| panic ! ( "unexpected node_id" ) ) ;
190176 match ty_res {
@@ -301,7 +287,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
301287 } ) ;
302288 }
303289 }
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+ } )
305294 } )
306295 }
307296 /// Resolves a string as a path within a particular namespace. Also returns an optional
@@ -384,7 +373,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
384373 // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
385374 . ok_or_else ( || {
386375 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+ } )
388380 } ) ?;
389381
390382 if let Some ( ( path, prim) ) = is_primitive ( & path_root, TypeNS ) {
@@ -451,7 +443,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
451443 }
452444 }
453445 }
454- ResolutionFailure :: NotInScope ( path_root. into ( ) )
446+ ResolutionFailure :: NotInScope { module_id , name : path_root. into ( ) }
455447 } ) ;
456448 Err ( ErrorKind :: Resolve ( kind) )
457449 } ;
@@ -996,7 +988,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
996988 }
997989 }
998990 resolution_failure (
999- cx ,
991+ self ,
1000992 & item,
1001993 path_str,
1002994 disambiguator,
@@ -1076,7 +1068,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
10761068 if len == 0 {
10771069 drop ( candidates_iter) ;
10781070 resolution_failure (
1079- cx ,
1071+ self ,
10801072 & item,
10811073 path_str,
10821074 disambiguator,
@@ -1096,8 +1088,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
10961088 } else {
10971089 drop ( candidates_iter) ;
10981090 if is_derive_trait_collision ( & candidates) {
1099- candidates. macro_ns =
1100- Err ( ResolutionFailure :: NotInScope ( path_str. into ( ) ) ) ;
1091+ candidates. macro_ns = Err ( ResolutionFailure :: Dummy ) ;
11011092 }
11021093 // If we're reporting an ambiguity, don't mention the namespaces that failed
11031094 let candidates =
@@ -1131,7 +1122,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
11311122 }
11321123 }
11331124 resolution_failure (
1134- cx ,
1125+ self ,
11351126 & item,
11361127 path_str,
11371128 disambiguator,
@@ -1507,7 +1498,7 @@ fn report_diagnostic(
15071498}
15081499
15091500fn resolution_failure (
1510- cx : & DocContext < ' _ > ,
1501+ collector : & LinkCollector < ' _ , ' _ > ,
15111502 item : & Item ,
15121503 path_str : & str ,
15131504 disambiguator : Option < Disambiguator > ,
@@ -1516,19 +1507,23 @@ fn resolution_failure(
15161507 kinds : SmallVec < [ ResolutionFailure < ' _ > ; 3 ] > ,
15171508) {
15181509 report_diagnostic (
1519- cx,
1510+ collector . cx ,
15201511 & format ! ( "unresolved link to `{}`" , path_str) ,
15211512 item,
15221513 dox,
15231514 & link_range,
15241515 |diag, sp| {
15251516 let in_scope = kinds. iter ( ) . any ( |kind| kind. res ( ) . is_some ( ) ) ;
15261517 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+ )
15281523 } ;
15291524 let assoc_item_not_allowed = |res : Res , diag : & mut DiagnosticBuilder < ' _ > | {
15301525 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) ;
15321527 let note = format ! (
15331528 "`{}` is {} {}, not a module or type, and cannot have associated items" ,
15341529 name,
@@ -1539,18 +1534,42 @@ fn resolution_failure(
15391534 } ;
15401535 // ignore duplicates
15411536 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+ }
15431562 let variant = std:: mem:: discriminant ( & failure) ;
15441563 if variants_seen. contains ( & variant) {
15451564 continue ;
15461565 }
15471566 variants_seen. push ( variant) ;
15481567 match failure {
1549- ResolutionFailure :: NotInScope ( base ) => {
1568+ ResolutionFailure :: NotInScope { name , .. } => {
15501569 if in_scope {
15511570 continue ;
15521571 }
1553- diag. note ( & format ! ( "no item named `{}` is in scope" , base ) ) ;
1572+ diag. note ( & format ! ( "no item named `{}` is in scope" , name ) ) ;
15541573 // If the link has `::` in the path, assume it's meant to be an intra-doc link
15551574 if !path_str. contains ( "::" ) {
15561575 // Otherwise, the `[]` might be unrelated.
@@ -1608,7 +1627,7 @@ fn resolution_failure(
16081627 x,
16091628 ) ,
16101629 } ;
1611- let name = cx. tcx . item_name ( def_id) ;
1630+ let name = collector . cx . tcx . item_name ( def_id) ;
16121631 let path_description = if let Some ( disambiguator) = disambiguator {
16131632 disambiguator. descr ( )
16141633 } else {
0 commit comments