Skip to content

Commit a626da4

Browse files
committed
Split out ItemFragment from UrlFragment
This allows eliminating branches in the code where a user-written fragment is impossible.
1 parent a69e15c commit a626da4

File tree

1 file changed

+49
-39
lines changed

1 file changed

+49
-39
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

+49-39
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,23 @@ enum AnchorFailure {
236236

237237
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
238238
crate enum UrlFragment {
239-
Def(FragmentKind, DefId),
239+
Item(ItemFragment),
240240
UserWritten(String),
241241
}
242242

243+
impl UrlFragment {
244+
/// Render the fragment, including the leading `#`.
245+
crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result {
246+
match self {
247+
UrlFragment::Item(frag) => frag.render(s, tcx),
248+
UrlFragment::UserWritten(raw) => write!(s, "#{}", raw),
249+
}
250+
}
251+
}
252+
253+
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
254+
crate struct ItemFragment(FragmentKind, DefId);
255+
243256
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
244257
crate enum FragmentKind {
245258
Method,
@@ -252,7 +265,7 @@ crate enum FragmentKind {
252265
VariantField,
253266
}
254267

255-
impl UrlFragment {
268+
impl ItemFragment {
256269
/// Create a fragment for an associated item.
257270
///
258271
/// `is_prototype` is whether this associated item is a trait method
@@ -261,21 +274,21 @@ impl UrlFragment {
261274
match kind {
262275
ty::AssocKind::Fn => {
263276
if is_prototype {
264-
UrlFragment::Def(FragmentKind::TyMethod, def_id)
277+
ItemFragment(FragmentKind::TyMethod, def_id)
265278
} else {
266-
UrlFragment::Def(FragmentKind::Method, def_id)
279+
ItemFragment(FragmentKind::Method, def_id)
267280
}
268281
}
269-
ty::AssocKind::Const => UrlFragment::Def(FragmentKind::AssociatedConstant, def_id),
270-
ty::AssocKind::Type => UrlFragment::Def(FragmentKind::AssociatedType, def_id),
282+
ty::AssocKind::Const => ItemFragment(FragmentKind::AssociatedConstant, def_id),
283+
ty::AssocKind::Type => ItemFragment(FragmentKind::AssociatedType, def_id),
271284
}
272285
}
273286

274287
/// Render the fragment, including the leading `#`.
275288
crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result {
276289
write!(s, "#")?;
277290
match *self {
278-
UrlFragment::Def(kind, def_id) => {
291+
ItemFragment(kind, def_id) => {
279292
let name = tcx.item_name(def_id);
280293
match kind {
281294
FragmentKind::Method => write!(s, "method.{}", name),
@@ -290,7 +303,6 @@ impl UrlFragment {
290303
}
291304
}
292305
}
293-
UrlFragment::UserWritten(ref raw) => write!(s, "{}", raw),
294306
}
295307
}
296308
}
@@ -300,7 +312,7 @@ struct ResolutionInfo {
300312
module_id: DefId,
301313
dis: Option<Disambiguator>,
302314
path_str: String,
303-
extra_fragment: Option<UrlFragment>,
315+
extra_fragment: Option<String>,
304316
}
305317

306318
#[derive(Clone)]
@@ -339,7 +351,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
339351
&self,
340352
path_str: &'path str,
341353
module_id: DefId,
342-
) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
354+
) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
343355
let tcx = self.cx.tcx;
344356
let no_res = || ResolutionFailure::NotResolved {
345357
module_id,
@@ -389,10 +401,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
389401
if let Some(field) =
390402
def.all_fields().find(|f| f.ident.name == variant_field_name)
391403
{
392-
Ok((
393-
ty_res,
394-
Some(UrlFragment::Def(FragmentKind::VariantField, field.did)),
395-
))
404+
Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did))))
396405
} else {
397406
Err(ResolutionFailure::NotResolved {
398407
module_id,
@@ -420,15 +429,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
420429
prim_ty: PrimitiveType,
421430
ns: Namespace,
422431
item_name: Symbol,
423-
) -> Option<(Res, UrlFragment)> {
432+
) -> Option<(Res, ItemFragment)> {
424433
let tcx = self.cx.tcx;
425434

426435
prim_ty.impls(tcx).into_iter().find_map(|&impl_| {
427436
tcx.associated_items(impl_)
428437
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
429438
.map(|item| {
430439
let kind = item.kind;
431-
let fragment = UrlFragment::from_assoc_item(item.def_id, kind, false);
440+
let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
432441
(Res::Primitive(prim_ty), fragment)
433442
})
434443
})
@@ -503,21 +512,19 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
503512
path_str: &'path str,
504513
ns: Namespace,
505514
module_id: DefId,
506-
user_fragment: &Option<UrlFragment>,
515+
user_fragment: &Option<String>,
507516
) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
508517
let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, module_id)?;
509518
let chosen_fragment = match (user_fragment, rustdoc_fragment) {
510519
(Some(_), Some(r_frag)) => {
511520
let diag_res = match r_frag {
512-
UrlFragment::Def(_, did) => Res::Def(self.cx.tcx.def_kind(did), did),
513-
// FIXME: eliminate this branch somehow
514-
UrlFragment::UserWritten(_) => unreachable!(),
521+
ItemFragment(_, did) => Res::Def(self.cx.tcx.def_kind(did), did),
515522
};
516523
let failure = AnchorFailure::RustdocAnchorConflict(diag_res);
517524
return Err(ErrorKind::AnchorFailure(failure));
518525
}
519-
(Some(u_frag), None) => Some(u_frag.clone()),
520-
(None, Some(r_frag)) => Some(r_frag),
526+
(Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())),
527+
(None, Some(r_frag)) => Some(UrlFragment::Item(r_frag)),
521528
(None, None) => None,
522529
};
523530
Ok((res, chosen_fragment))
@@ -528,7 +535,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
528535
path_str: &'path str,
529536
ns: Namespace,
530537
module_id: DefId,
531-
) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
538+
) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
532539
if let Some(res) = self.resolve_path(path_str, ns, module_id) {
533540
match res {
534541
// FIXME(#76467): make this fallthrough to lookup the associated
@@ -670,7 +677,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
670677
item_name: Symbol,
671678
ns: Namespace,
672679
module_id: DefId,
673-
) -> Option<(Res, UrlFragment)> {
680+
) -> Option<(Res, ItemFragment)> {
674681
let tcx = self.cx.tcx;
675682

676683
match root_res {
@@ -685,7 +692,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
685692

686693
assoc_item.map(|item| {
687694
let kind = item.kind;
688-
let fragment = UrlFragment::from_assoc_item(item.def_id, kind, false);
695+
let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
689696
(root_res, fragment)
690697
})
691698
})
@@ -736,7 +743,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
736743

737744
if let Some(item) = assoc_item {
738745
let kind = item.kind;
739-
let fragment = UrlFragment::from_assoc_item(item.def_id, kind, false);
746+
let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
740747
return Some((root_res, fragment));
741748
}
742749

@@ -768,13 +775,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
768775
.fields
769776
.iter()
770777
.find(|item| item.ident.name == item_name)?;
771-
Some((root_res, UrlFragment::Def(FragmentKind::StructField, field.did)))
778+
Some((root_res, ItemFragment(FragmentKind::StructField, field.did)))
772779
}
773780
Res::Def(DefKind::Trait, did) => tcx
774781
.associated_items(did)
775782
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did)
776783
.map(|item| {
777-
let fragment = UrlFragment::from_assoc_item(
784+
let fragment = ItemFragment::from_assoc_item(
778785
item.def_id,
779786
item.kind,
780787
!item.defaultness.has_value(),
@@ -797,7 +804,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
797804
ns: Namespace,
798805
path_str: &str,
799806
module_id: DefId,
800-
extra_fragment: &Option<UrlFragment>,
807+
extra_fragment: &Option<String>,
801808
) -> Option<Res> {
802809
// resolve() can't be used for macro namespace
803810
let result = match ns {
@@ -812,7 +819,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
812819

813820
let res = match result {
814821
Ok((res, frag)) => {
815-
if let Some(UrlFragment::Def(_, id)) = frag {
822+
if let Some(UrlFragment::Item(ItemFragment(_, id))) = frag {
816823
Some(Res::Def(self.cx.tcx.def_kind(id), id))
817824
} else {
818825
Some(res)
@@ -1039,7 +1046,7 @@ impl From<AnchorFailure> for PreprocessingError<'_> {
10391046
struct PreprocessingInfo {
10401047
path_str: String,
10411048
disambiguator: Option<Disambiguator>,
1042-
extra_fragment: Option<UrlFragment>,
1049+
extra_fragment: Option<String>,
10431050
link_text: String,
10441051
}
10451052

@@ -1125,7 +1132,7 @@ fn preprocess_link<'a>(
11251132
Some(Ok(PreprocessingInfo {
11261133
path_str,
11271134
disambiguator,
1128-
extra_fragment: extra_fragment.map(|frag| UrlFragment::UserWritten(frag.to_owned())),
1135+
extra_fragment: extra_fragment.map(|frag| frag.to_owned()),
11291136
link_text: link_text.to_owned(),
11301137
}))
11311138
}
@@ -1292,7 +1299,7 @@ impl LinkCollector<'_, '_> {
12921299
};
12931300

12941301
let verify = |kind: DefKind, id: DefId| {
1295-
let (kind, id) = if let Some(UrlFragment::Def(_, id)) = fragment {
1302+
let (kind, id) = if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
12961303
(self.cx.tcx.def_kind(id), id)
12971304
} else {
12981305
(kind, id)
@@ -1340,7 +1347,7 @@ impl LinkCollector<'_, '_> {
13401347

13411348
match res {
13421349
Res::Primitive(prim) => {
1343-
if let Some(UrlFragment::Def(_, id)) = fragment {
1350+
if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
13441351
let kind = self.cx.tcx.def_kind(id);
13451352

13461353
// We're actually resolving an associated item of a primitive, so we need to
@@ -1488,7 +1495,7 @@ impl LinkCollector<'_, '_> {
14881495
let mut candidates = PerNS {
14891496
macro_ns: self
14901497
.resolve_macro(path_str, base_node)
1491-
.map(|res| (res, extra_fragment.clone())),
1498+
.map(|res| (res, extra_fragment.clone().map(UrlFragment::UserWritten))),
14921499
type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) {
14931500
Ok(res) => {
14941501
debug!("got res in TypeNS: {:?}", res);
@@ -1520,7 +1527,10 @@ impl LinkCollector<'_, '_> {
15201527
// Shouldn't happen but who knows?
15211528
Ok((res, Some(fragment)))
15221529
}
1523-
(fragment, None) | (None, fragment) => Ok((res, fragment)),
1530+
(fragment, None) => Ok((res, fragment)),
1531+
(None, fragment) => {
1532+
Ok((res, fragment.map(UrlFragment::UserWritten)))
1533+
}
15241534
}
15251535
}
15261536
}
@@ -1557,7 +1567,7 @@ impl LinkCollector<'_, '_> {
15571567
}
15581568
Some(MacroNS) => {
15591569
match self.resolve_macro(path_str, base_node) {
1560-
Ok(res) => Some((res, extra_fragment.clone())),
1570+
Ok(res) => Some((res, extra_fragment.clone().map(UrlFragment::UserWritten))),
15611571
Err(mut kind) => {
15621572
// `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
15631573
for ns in [TypeNS, ValueNS] {
@@ -2276,13 +2286,13 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str:
22762286
fn handle_variant(
22772287
cx: &DocContext<'_>,
22782288
res: Res,
2279-
) -> Result<(Res, Option<UrlFragment>), ErrorKind<'static>> {
2289+
) -> Result<(Res, Option<ItemFragment>), ErrorKind<'static>> {
22802290
cx.tcx
22812291
.parent(res.def_id(cx.tcx))
22822292
.map(|parent| {
22832293
let parent_def = Res::Def(DefKind::Enum, parent);
22842294
let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
2285-
(parent_def, Some(UrlFragment::Def(FragmentKind::Variant, variant.def_id)))
2295+
(parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id)))
22862296
})
22872297
.ok_or_else(|| ResolutionFailure::NoParentItem.into())
22882298
}

0 commit comments

Comments
 (0)