@@ -106,15 +106,13 @@ impl Res {
106106            Res :: Primitive ( _)  => return  Suggestion :: Prefix ( "prim" ) , 
107107            Res :: Def ( kind,  _)  => kind, 
108108        } ; 
109-         if  kind == DefKind :: Macro ( MacroKind :: Bang )  { 
110-             return  Suggestion :: Macro ; 
111-         }  else  if  kind == DefKind :: Fn  || kind == DefKind :: AssocFn  { 
112-             return  Suggestion :: Function ; 
113-         }  else  if  kind == DefKind :: Field  { 
114-             return  Suggestion :: RemoveDisambiguator ; 
115-         } 
116109
117110        let  prefix = match  kind { 
111+             DefKind :: Fn  | DefKind :: AssocFn  => return  Suggestion :: Function , 
112+             DefKind :: Field  => return  Suggestion :: RemoveDisambiguator , 
113+             DefKind :: Macro ( MacroKind :: Bang )  => return  Suggestion :: Macro , 
114+ 
115+             DefKind :: Macro ( MacroKind :: Derive )  => "derive" , 
118116            DefKind :: Struct  => "struct" , 
119117            DefKind :: Enum  => "enum" , 
120118            DefKind :: Trait  => "trait" , 
@@ -124,7 +122,6 @@ impl Res {
124122                "const" 
125123            } 
126124            DefKind :: Static ( _)  => "static" , 
127-             DefKind :: Macro ( MacroKind :: Derive )  => "derive" , 
128125            // Now handle things that don't have a specific disambiguator 
129126            _ => match  kind
130127                . ns ( ) 
@@ -281,20 +278,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
281278
282279        debug ! ( "looking for enum variant {path_str}" ) ; 
283280        let  mut  split = path_str. rsplitn ( 3 ,  "::" ) ; 
284-         let  variant_field_name = split
285-             . next ( ) 
286-             . map ( |f| Symbol :: intern ( f) ) 
287-             . expect ( "fold_item should ensure link is non-empty" ) ; 
288-         let  variant_name =
289-             // we're not sure this is a variant at all, so use the full string 
290-             // If there's no second component, the link looks like `[path]`. 
291-             // So there's no partial res and we should say the whole link failed to resolve. 
292-             split. next ( ) . map ( |f|  Symbol :: intern ( f) ) . ok_or_else ( no_res) ?; 
293-         let  path = split
294-             . next ( ) 
295-             // If there's no third component, we saw `[a::b]` before and it failed to resolve. 
296-             // So there's no partial res. 
297-             . ok_or_else ( no_res) ?; 
281+         let  variant_field_name = Symbol :: intern ( split. next ( ) . unwrap ( ) ) ; 
282+         // We're not sure this is a variant at all, so use the full string. 
283+         // If there's no second component, the link looks like `[path]`. 
284+         // So there's no partial res and we should say the whole link failed to resolve. 
285+         let  variant_name = Symbol :: intern ( split. next ( ) . ok_or_else ( no_res) ?) ; 
286+ 
287+         // If there's no third component, we saw `[a::b]` before and it failed to resolve. 
288+         // So there's no partial res. 
289+         let  path = split. next ( ) . ok_or_else ( no_res) ?; 
298290        let  ty_res = self . resolve_path ( & path,  TypeNS ,  item_id,  module_id) . ok_or_else ( no_res) ?; 
299291
300292        match  ty_res { 
@@ -443,41 +435,29 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
443435        } 
444436
445437        // Try looking for methods and associated items. 
446-         let  mut  split = path_str. rsplitn ( 2 ,  "::" ) ; 
447-         // NB: `split`'s first element is always defined, even if the delimiter was not present. 
448-         // NB: `item_str` could be empty when resolving in the root namespace (e.g. `::std`). 
449-         let  item_str = split. next ( ) . unwrap ( ) ; 
450-         let  item_name = Symbol :: intern ( item_str) ; 
451-         let  path_root = split
452-             . next ( ) 
438+         // NB: `path_root` could be empty when resolving in the root namespace (e.g. `::std`). 
439+         let  ( path_root,  item_str)  = path_str. rsplit_once ( "::" ) . ok_or_else ( || { 
453440            // If there's no `::`, it's not an associated item. 
454441            // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. 
455-             . ok_or_else ( || { 
456-                 debug ! ( "found no `::`, assuming {item_name} was correctly not in scope" ) ; 
457-                 UnresolvedPath  { 
458-                     item_id, 
459-                     module_id, 
460-                     partial_res :  None , 
461-                     unresolved :  item_str. into ( ) , 
462-                 } 
463-             } ) ?; 
442+             debug ! ( "found no `::`, assuming {path_str} was correctly not in scope" ) ; 
443+             UnresolvedPath  {  item_id,  module_id,  partial_res :  None ,  unresolved :  path_str. into ( )  } 
444+         } ) ?; 
445+         let  item_name = Symbol :: intern ( item_str) ; 
464446
465447        // FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support 
466448        // links to primitives when `#[rustc_doc_primitive]` is present. It should give an ambiguity 
467449        // error instead and special case *only* modules with `#[rustc_doc_primitive]`, not all 
468450        // primitives. 
469-         match  resolve_primitive ( & path_root,  TypeNS ) 
470-             . or_else ( || self . resolve_path ( & path_root,  TypeNS ,  item_id,  module_id) ) 
471-             . and_then ( |ty_res| { 
472-                 let  candidates = self 
473-                     . resolve_associated_item ( ty_res,  item_name,  ns,  module_id) 
451+         match  resolve_primitive ( path_root,  TypeNS ) 
452+             . or_else ( || self . resolve_path ( path_root,  TypeNS ,  item_id,  module_id) ) 
453+             . map ( |ty_res| { 
454+                 self . resolve_associated_item ( ty_res,  item_name,  ns,  module_id) 
474455                    . into_iter ( ) 
475456                    . map ( |( res,  def_id) | ( res,  Some ( def_id) ) ) 
476-                     . collect :: < Vec < _ > > ( ) ; 
477-                 if  !candidates. is_empty ( )  {  Some ( candidates)  }  else  {  None  } 
457+                     . collect :: < Vec < _ > > ( ) 
478458            } )  { 
479-             Some ( r)  => Ok ( r) , 
480-             None  => { 
459+             Some ( r)  if  !r . is_empty ( )   => Ok ( r) , 
460+             _  => { 
481461                if  ns == Namespace :: ValueNS  { 
482462                    self . variant_field ( path_str,  item_id,  module_id) 
483463                        . map ( |( res,  def_id) | vec ! [ ( res,  Some ( def_id) ) ] ) 
@@ -1257,16 +1237,18 @@ impl LinkCollector<'_, '_> {
12571237                self . report_rawptr_assoc_feature_gate ( diag. dox ,  & diag. link_range ,  diag. item ) ; 
12581238                return  None ; 
12591239            }  else  { 
1260-                 candidates = vec ! [ candidates [ 0 ] ] ; 
1240+                 candidates = vec ! [ * candidate ] ; 
12611241            } 
12621242        } 
12631243
12641244        // If there are multiple items with the same "kind" (for example, both "associated types") 
12651245        // and after removing duplicated kinds, only one remains, the `ambiguity_error` function 
12661246        // won't emit an error. So at this point, we can just take the first candidate as it was 
12671247        // the first retrieved and use it to generate the link. 
1268-         if  candidates. len ( )  > 1  && !ambiguity_error ( self . cx ,  & diag,  & key. path_str ,  & candidates)  { 
1269-             candidates = vec ! [ candidates[ 0 ] ] ; 
1248+         if  let  [ candidate,  _candidate2,  ..]  = * candidates
1249+             && !ambiguity_error ( self . cx ,  & diag,  & key. path_str ,  & candidates) 
1250+         { 
1251+             candidates = vec ! [ candidate] ; 
12701252        } 
12711253
12721254        if  let  & [ ( res,  def_id) ]  = candidates. as_slice ( )  { 
@@ -1316,12 +1298,11 @@ impl LinkCollector<'_, '_> {
13161298                        let  mut  err = ResolutionFailure :: NotResolved ( err) ; 
13171299                        for  other_ns in  [ TypeNS ,  ValueNS ,  MacroNS ]  { 
13181300                            if  other_ns != expected_ns { 
1319-                                 if  let  Ok ( res)  =
1320-                                     self . resolve ( path_str,  other_ns,  item_id,  module_id)  &&
1321-                                     !res. is_empty ( ) 
1301+                                 if  let  Ok ( & [ res,  ..] )  =
1302+                                     self . resolve ( path_str,  other_ns,  item_id,  module_id) . as_deref ( ) 
13221303                                { 
13231304                                    err = ResolutionFailure :: WrongNamespace  { 
1324-                                         res :  full_res ( self . cx . tcx ,  res[ 0 ] ) , 
1305+                                         res :  full_res ( self . cx . tcx ,  res) , 
13251306                                        expected_ns, 
13261307                                    } ; 
13271308                                    break ; 
@@ -1746,7 +1727,6 @@ fn report_diagnostic(
17461727            lint. note ( format ! ( 
17471728                "the link appears in this line:\n \n {line}\n \  
17481729                      {indicator: <before$}{indicator:^<found$}", 
1749-                 line = line, 
17501730                indicator = "" , 
17511731                before = md_range. start - last_new_line_offset, 
17521732                found = md_range. len( ) , 
@@ -1807,18 +1787,13 @@ fn resolution_failure(
18071787
18081788                    let  item_id = * item_id; 
18091789                    let  module_id = * module_id; 
1810-                     // FIXME(jynelson): this might conflict with my `Self` fix in #76467 
1811-                     // FIXME: maybe use itertools `collect_tuple` instead? 
1812-                     fn  split ( path :  & str )  -> Option < ( & str ,  & str ) >  { 
1813-                         let  mut  splitter = path. rsplitn ( 2 ,  "::" ) ; 
1814-                         splitter. next ( ) . and_then ( |right| splitter. next ( ) . map ( |left| ( left,  right) ) ) 
1815-                     } 
18161790
18171791                    // Check if _any_ parent of the path gets resolved. 
18181792                    // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. 
18191793                    let  mut  name = path_str; 
18201794                    ' outer:  loop  { 
1821-                         let  Some ( ( start,  end) )  = split ( name)  else  { 
1795+                         // FIXME(jynelson): this might conflict with my `Self` fix in #76467 
1796+                         let  Some ( ( start,  end) )  = name. rsplit_once ( "::" )  else  { 
18221797                            // avoid bug that marked [Quux::Z] as missing Z, not Quux 
18231798                            if  partial_res. is_none ( )  { 
18241799                                * unresolved = name. into ( ) ; 
@@ -1829,8 +1804,8 @@ fn resolution_failure(
18291804                        for  ns in  [ TypeNS ,  ValueNS ,  MacroNS ]  { 
18301805                            if  let  Ok ( v_res)  = collector. resolve ( start,  ns,  item_id,  module_id)  { 
18311806                                debug ! ( "found partial_res={v_res:?}" ) ; 
1832-                                 if  ! v_res. is_empty ( )  { 
1833-                                     * partial_res = Some ( full_res ( tcx,  v_res [ 0 ] ) ) ; 
1807+                                 if  let   Some ( & res )  =  v_res. first ( )  { 
1808+                                     * partial_res = Some ( full_res ( tcx,  res ) ) ; 
18341809                                    * unresolved = end. into ( ) ; 
18351810                                    break  ' outer; 
18361811                                } 
0 commit comments