Skip to content

Commit 35de890

Browse files
committed
Greatly simplify the types of resolve_associated_item
Previously, the types looked like this: - None means this is not an associated item (but may be a variant field) - Some(Err) means this is known to be an error. I think the only way that can happen is if it resolved and but you had your own anchor. - Some(Ok(_, None)) was impossible. Now, this returns a simple Option and does the error handling in the caller. As a side-effect, it also removes duplicate error handling. This has one small change in behavior, which is that `resolve_primitive_associated_item` now goes through `variant_field` if it fails to resolve something. This is not ideal, but since it will be quickly rejected anyway, I think the performance hit is worth the cleanup.
1 parent 30bfcf6 commit 35de890

File tree

1 file changed

+58
-83
lines changed

1 file changed

+58
-83
lines changed

src/librustdoc/passes/collect_intra_doc_links.rs

+58-83
Original file line numberDiff line numberDiff line change
@@ -368,54 +368,30 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
368368
}
369369

370370
/// Given a primitive type, try to resolve an associated item.
371-
///
372-
/// HACK(jynelson): `item_str` is passed in instead of derived from `item_name` so the
373-
/// lifetimes on `&'path` will work.
374371
fn resolve_primitive_associated_item(
375372
&self,
376373
prim_ty: PrimitiveType,
377374
ns: Namespace,
378-
module_id: DefId,
379375
item_name: Symbol,
380-
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
376+
) -> Option<(Res, String)> {
381377
let tcx = self.cx.tcx;
382378

383-
prim_ty
384-
.impls(tcx)
385-
.into_iter()
386-
.find_map(|&impl_| {
387-
tcx.associated_items(impl_)
388-
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
389-
.map(|item| {
390-
let kind = item.kind;
391-
self.kind_side_channel.set(Some((kind.as_def_kind(), item.def_id)));
392-
match kind {
393-
ty::AssocKind::Fn => "method",
394-
ty::AssocKind::Const => "associatedconstant",
395-
ty::AssocKind::Type => "associatedtype",
396-
}
397-
})
398-
.map(|out| {
399-
(
400-
Res::Primitive(prim_ty),
401-
Some(format!("{}#{}.{}", prim_ty.as_str(), out, item_name)),
402-
)
403-
})
404-
})
405-
.ok_or_else(|| {
406-
debug!(
407-
"returning primitive error for {}::{} in {} namespace",
408-
prim_ty.as_str(),
409-
item_name,
410-
ns.descr()
411-
);
412-
ResolutionFailure::NotResolved {
413-
module_id,
414-
partial_res: Some(Res::Primitive(prim_ty)),
415-
unresolved: item_name.to_string().into(),
416-
}
417-
.into()
418-
})
379+
prim_ty.impls(tcx).into_iter().find_map(|&impl_| {
380+
tcx.associated_items(impl_)
381+
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
382+
.map(|item| {
383+
let kind = item.kind;
384+
self.kind_side_channel.set(Some((kind.as_def_kind(), item.def_id)));
385+
match kind {
386+
ty::AssocKind::Fn => "method",
387+
ty::AssocKind::Const => "associatedconstant",
388+
ty::AssocKind::Type => "associatedtype",
389+
}
390+
})
391+
.map(|out| {
392+
(Res::Primitive(prim_ty), format!("{}#{}.{}", prim_ty.as_str(), out, item_name))
393+
})
394+
})
419395
}
420396

421397
/// Resolves a string as a macro.
@@ -533,7 +509,20 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
533509

534510
self.resolve_path(&path_root, TypeNS, module_id)
535511
.and_then(|ty_res| {
536-
self.resolve_associated_item(ty_res, item_name, ns, module_id, extra_fragment)
512+
let (res, fragment, side_channel) =
513+
self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
514+
let result = if extra_fragment.is_some() {
515+
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res)))
516+
} else {
517+
// HACK(jynelson): `clean` expects the type, not the associated item
518+
// but the disambiguator logic expects the associated item.
519+
// Store the kind in a side channel so that only the disambiguator logic looks at it.
520+
if let Some((kind, id)) = side_channel {
521+
self.kind_side_channel.set(Some((kind, id)));
522+
}
523+
Ok((res, Some(fragment)))
524+
};
525+
Some(result)
537526
})
538527
.unwrap_or_else(|| {
539528
if ns == Namespace::ValueNS {
@@ -549,21 +538,23 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
549538
})
550539
}
551540

541+
/// Returns:
542+
/// - None if no associated item was found
543+
/// - Some((_, _, Some(_))) if an item was found and should go through a side channel
544+
/// - Some((_, _, None)) otherwise
552545
fn resolve_associated_item(
553546
&mut self,
554547
root_res: Res,
555548
item_name: Symbol,
556549
ns: Namespace,
557550
module_id: DefId,
558-
extra_fragment: &Option<String>,
559-
// lol this is so bad
560-
) -> Option<Result<(Res, Option<String>), ErrorKind<'static>>> {
551+
) -> Option<(Res, String, Option<(DefKind, DefId)>)> {
561552
let tcx = self.cx.tcx;
562553

563554
match root_res {
564-
Res::Primitive(prim) => {
565-
Some(self.resolve_primitive_associated_item(prim, ns, module_id, item_name))
566-
}
555+
Res::Primitive(prim) => self
556+
.resolve_primitive_associated_item(prim, ns, item_name)
557+
.map(|(x, y)| (x, y, None)),
567558
Res::Def(
568559
DefKind::Struct
569560
| DefKind::Union
@@ -606,17 +597,14 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
606597
ty::AssocKind::Const => "associatedconstant",
607598
ty::AssocKind::Type => "associatedtype",
608599
};
609-
return Some(if extra_fragment.is_some() {
610-
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(
611-
root_res,
612-
)))
613-
} else {
614-
// HACK(jynelson): `clean` expects the type, not the associated item
615-
// but the disambiguator logic expects the associated item.
616-
// Store the kind in a side channel so that only the disambiguator logic looks at it.
617-
self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
618-
Ok((root_res, Some(format!("{}.{}", out, item_name))))
619-
});
600+
// HACK(jynelson): `clean` expects the type, not the associated item
601+
// but the disambiguator logic expects the associated item.
602+
// Store the kind in a side channel so that only the disambiguator logic looks at it.
603+
return Some((
604+
root_res,
605+
format!("{}.{}", out, item_name),
606+
Some((kind.as_def_kind(), id)),
607+
));
620608
}
621609

622610
if ns != Namespace::ValueNS {
@@ -635,22 +623,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
635623
} else {
636624
def.non_enum_variant().fields.iter().find(|item| item.ident.name == item_name)
637625
}?;
638-
Some(if extra_fragment.is_some() {
639-
let res = Res::Def(
640-
if def.is_enum() { DefKind::Variant } else { DefKind::Field },
641-
field.did,
642-
);
643-
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res)))
644-
} else {
645-
Ok((
646-
root_res,
647-
Some(format!(
648-
"{}.{}",
649-
if def.is_enum() { "variant" } else { "structfield" },
650-
field.ident
651-
)),
652-
))
653-
})
626+
Some((
627+
root_res,
628+
format!(
629+
"{}.{}",
630+
if def.is_enum() { "variant" } else { "structfield" },
631+
field.ident
632+
),
633+
None,
634+
))
654635
}
655636
Res::Def(DefKind::Trait, did) => tcx
656637
.associated_items(did)
@@ -668,14 +649,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
668649
}
669650
};
670651

671-
if extra_fragment.is_some() {
672-
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(
673-
root_res,
674-
)))
675-
} else {
676-
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
677-
Ok((res, Some(format!("{}.{}", kind, item_name))))
678-
}
652+
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
653+
(res, format!("{}.{}", kind, item_name), None)
679654
}),
680655
_ => None,
681656
}

0 commit comments

Comments
 (0)