@@ -34,42 +34,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
34
34
/// [enum struct variant]: hir::VariantData::Struct
35
35
fn variant_field (
36
36
& self ,
37
- path_str : & ' path str ,
38
- module_id : DefId ,
39
- ) -> Result < ( Res , Option < String > ) , ErrorKind < ' path > > {
37
+ ( variant_res , variant_name , variant_field_name ) : ( Res , Symbol , Symbol ) ,
38
+ module_id : DefId ,
39
+ ) -> Result < ( Res , String ) , ErrorKind < ' path > > {
40
40
let tcx = self . cx . tcx ;
41
- let no_res = || ResolutionFailure :: NotResolved {
42
- module_id,
43
- partial_res : None ,
44
- unresolved : path_str. into ( ) ,
45
- } ;
46
41
47
- debug ! ( "looking for enum variant {}" , path_str) ;
48
- let mut split = path_str. rsplitn ( 3 , "::" ) ;
49
- let ( variant_field_str, variant_field_name) = split
50
- . next ( )
51
- . map ( |f| ( f, Symbol :: intern ( f) ) )
52
- . expect ( "fold_item should ensure link is non-empty" ) ;
53
- let ( variant_str, variant_name) =
54
- // we're not sure this is a variant at all, so use the full string
55
- // If there's no second component, the link looks like `[path]`.
56
- // So there's no partial res and we should say the whole link failed to resolve.
57
- split. next ( ) . map ( |f| ( f, Symbol :: intern ( f) ) ) . ok_or_else ( no_res) ?;
58
- let path = split
59
- . next ( )
60
- . map ( |f| f. to_owned ( ) )
61
- // If there's no third component, we saw `[a::b]` before and it failed to resolve.
62
- // So there's no partial res.
63
- . ok_or_else ( no_res) ?;
64
- let ty_res = self
65
- . cx
66
- . enter_resolver ( |resolver| {
67
- resolver. resolve_str_path_error ( DUMMY_SP , & path, TypeNS , module_id)
68
- } )
69
- . and_then ( |( _, res) | res. try_into ( ) )
70
- . map_err ( |( ) | no_res ( ) ) ?;
71
-
72
- match ty_res {
42
+ match variant_res {
73
43
Res :: Def ( DefKind :: Enum , did) => {
74
44
if tcx
75
45
. inherent_impls ( did)
@@ -85,17 +55,17 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
85
55
ty:: Adt ( def, _) if def. is_enum ( ) => {
86
56
if def. all_fields ( ) . any ( |item| item. ident . name == variant_field_name) {
87
57
Ok ( (
88
- ty_res ,
89
- Some ( format ! (
58
+ variant_res ,
59
+ format ! (
90
60
"variant.{}.field.{}" ,
91
- variant_str , variant_field_name
92
- ) ) ,
61
+ variant_name , variant_field_name
62
+ ) ,
93
63
) )
94
64
} else {
95
65
Err ( ResolutionFailure :: NotResolved {
96
66
module_id,
97
67
partial_res : Some ( Res :: Def ( DefKind :: Enum , def. did ) ) ,
98
- unresolved : variant_field_str . into ( ) ,
68
+ unresolved : variant_field_name . into ( ) ,
99
69
}
100
70
. into ( ) )
101
71
}
@@ -105,8 +75,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
105
75
}
106
76
_ => Err ( ResolutionFailure :: NotResolved {
107
77
module_id,
108
- partial_res : Some ( ty_res ) ,
109
- unresolved : variant_str . into ( ) ,
78
+ partial_res : Some ( variant_res ) ,
79
+ unresolved : variant_name . into ( ) ,
110
80
}
111
81
. into ( ) ) ,
112
82
}
@@ -183,88 +153,47 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
183
153
/// optional URL fragment in the case of variants and methods.
184
154
fn resolve < ' path > (
185
155
& mut self ,
186
- path_str : & ' path str ,
156
+ early_result : EarlyResult ,
157
+ path_str : & ' path str ,
187
158
ns : Namespace ,
188
159
module_id : DefId ,
189
160
extra_fragment : & Option < String > ,
190
161
) -> Result < ( Res , Option < String > ) , ErrorKind < ' path > > {
191
- if let Some ( res) = self . resolve_path ( path_str, ns, module_id) {
192
- match res {
193
- // FIXME(#76467): make this fallthrough to lookup the associated
194
- // item a separate function.
195
- Res :: Def ( DefKind :: AssocFn | DefKind :: AssocConst , _) => assert_eq ! ( ns, ValueNS ) ,
196
- Res :: Def ( DefKind :: AssocTy , _) => assert_eq ! ( ns, TypeNS ) ,
197
- Res :: Def ( DefKind :: Variant , _) => {
198
- return handle_variant ( self . cx , res, extra_fragment) ;
199
- }
200
- // Not a trait item; just return what we found.
201
- Res :: Primitive ( ty) => {
202
- if extra_fragment. is_some ( ) {
203
- return Err ( ErrorKind :: AnchorFailure (
204
- AnchorFailure :: RustdocAnchorConflict ( res) ,
205
- ) ) ;
206
- }
207
- return Ok ( ( res, Some ( ty. as_str ( ) . to_owned ( ) ) ) ) ;
208
- }
209
- _ => return Ok ( ( res, extra_fragment. clone ( ) ) ) ,
210
- }
211
- }
212
-
213
- // Try looking for methods and associated items.
214
- let mut split = path_str. rsplitn ( 2 , "::" ) ;
215
- // NB: `split`'s first element is always defined, even if the delimiter was not present.
216
- // NB: `item_str` could be empty when resolving in the root namespace (e.g. `::std`).
217
- let item_str = split. next ( ) . unwrap ( ) ;
218
- let item_name = Symbol :: intern ( item_str) ;
219
- let path_root = split
220
- . next ( )
221
- . map ( |f| f. to_owned ( ) )
222
- // If there's no `::`, it's not an associated item.
223
- // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
224
- . ok_or_else ( || {
225
- debug ! ( "found no `::`, assumming {} was correctly not in scope" , item_name) ;
226
- ResolutionFailure :: NotResolved {
227
- module_id,
228
- partial_res : None ,
229
- unresolved : item_str. into ( ) ,
230
- }
231
- } ) ?;
232
-
233
- // FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
234
- // links to primitives when `#[doc(primitive)]` is present. It should give an ambiguity
235
- // error instead and special case *only* modules with `#[doc(primitive)]`, not all
236
- // primitives.
237
- resolve_primitive ( & path_root, TypeNS )
238
- . or_else ( || self . resolve_path ( & path_root, TypeNS , module_id) )
239
- . and_then ( |ty_res| {
240
- let ( res, fragment, side_channel) =
241
- self . resolve_associated_item ( ty_res, item_name, ns, module_id) ?;
242
- let result = if extra_fragment. is_some ( ) {
243
- let diag_res = side_channel. map_or ( res, |( k, r) | Res :: Def ( k, r) ) ;
244
- Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( diag_res) ) )
245
- } else {
246
- // HACK(jynelson): `clean` expects the type, not the associated item
247
- // but the disambiguator logic expects the associated item.
248
- // Store the kind in a side channel so that only the disambiguator logic looks at it.
249
- if let Some ( ( kind, id) ) = side_channel {
250
- self . kind_side_channel . set ( Some ( ( kind, id) ) ) ;
251
- }
252
- Ok ( ( res, Some ( fragment) ) )
253
- } ;
254
- Some ( result)
255
- } )
256
- . unwrap_or_else ( || {
257
- if ns == Namespace :: ValueNS {
258
- self . variant_field ( path_str, module_id)
259
- } else {
260
- Err ( ResolutionFailure :: NotResolved {
261
- module_id,
262
- partial_res : None ,
263
- unresolved : path_root. into ( ) ,
264
- }
265
- . into ( ) )
266
- }
267
- } )
162
+ use EarlyResult :: * ;
163
+ let link = match early_result {
164
+ // easy cases
165
+ Resolved ( res, fragment) => return Ok ( ( res, fragment) ) ,
166
+ Error ( err) => return Err ( err) ,
167
+ // the actual work
168
+ UnresolvedVariant ( res) => return handle_variant ( self . cx , res, extra_fragment) ,
169
+ Unresolved ( link) => link,
170
+ } ;
171
+
172
+ if let Some ( ( res, fragment, side_channel) ) = link. ty_res . and_then ( |( ty_res, item_name) | {
173
+ self . resolve_associated_item ( ty_res, item_name, ns, module_id)
174
+ } ) {
175
+ if extra_fragment. is_some ( ) {
176
+ let diag_res = side_channel. map_or ( res, |( k, r) | Res :: Def ( k, r) ) ;
177
+ Err ( ErrorKind :: AnchorFailure ( AnchorFailure :: RustdocAnchorConflict ( diag_res) ) )
178
+ } else {
179
+ // HACK(jynelson): `clean` expects the type, not the associated item
180
+ // but the disambiguator logic expects the associated item.
181
+ // Store the kind in a side channel so that only the disambiguator logic looks at it.
182
+ if let Some ( ( kind, id) ) = side_channel {
183
+ self . kind_side_channel . set ( Some ( ( kind, id) ) ) ;
184
+ }
185
+ Ok ( ( res, Some ( fragment) ) )
186
+ }
187
+ } else if let Some ( variant_res) = link. variant_res {
188
+ debug_assert_eq ! ( ns, ValueNS ) ;
189
+ self . variant_field ( variant_res, module_id) . map ( |( res, fragment) | ( res, Some ( fragment) ) )
190
+ } else {
191
+ Err ( ResolutionFailure :: NotResolved {
192
+ module_id,
193
+ partial_res : None ,
194
+ unresolved : path_str. into ( ) ,
195
+ } . into ( ) )
196
+ }
268
197
}
269
198
270
199
/// Returns:
0 commit comments