Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve type aliases to the type they point to in intra-doc links #86334

Merged
merged 1 commit into from
Jun 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,44 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
})
}

/// Convert a DefId to a Res, where possible.
///
/// This is used for resolving type aliases.
fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
use PrimitiveType::*;
Some(match *self.cx.tcx.type_of(ty_id).kind() {
ty::Bool => Res::Primitive(Bool),
ty::Char => Res::Primitive(Char),
ty::Int(ity) => Res::Primitive(ity.into()),
ty::Uint(uty) => Res::Primitive(uty.into()),
ty::Float(fty) => Res::Primitive(fty.into()),
ty::Str => Res::Primitive(Str),
ty::Tuple(ref tys) if tys.is_empty() => Res::Primitive(Unit),
ty::Tuple(_) => Res::Primitive(Tuple),
ty::Array(..) => Res::Primitive(Array),
ty::Slice(_) => Res::Primitive(Slice),
ty::RawPtr(_) => Res::Primitive(RawPointer),
ty::Ref(..) => Res::Primitive(Reference),
ty::FnDef(..) => panic!("type alias to a function definition"),
ty::FnPtr(_) => Res::Primitive(Fn),
ty::Never => Res::Primitive(Never),
ty::Adt(&ty::AdtDef { did, .. }, _) | ty::Foreign(did) => {
Res::Def(self.cx.tcx.def_kind(did), did)
}
ty::Projection(_)
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(_)
| ty::Opaque(..)
| ty::Dynamic(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(_)
| ty::Error(_) => return None,
})
}

/// Returns:
/// - None if no associated item was found
/// - Some((_, _, Some(_))) if an item was found and should go through a side channel
Expand All @@ -559,12 +597,15 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {

match root_res {
Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name),
Res::Def(DefKind::TyAlias, did) => {
// Resolve the link on the type the alias points to.
// FIXME: if the associated item is defined directly on the type alias,
// it will show up on its documentation page, we should link there instead.
Comment on lines +602 to +603
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do that by checking inherent_impls(did) before calling resolve_associated_item?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm right in #86334 (comment), inherent_impls won't return anything for a type alias. I think rustdoc is able to display the implementations for type aliases because it does its own visit of the HIR to collect them. Maybe there's a way to use that here, but when I tried the cache was still empty, I'm assuming it gets populated later in the process.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. As long as the link works I'm not super concerned about whether it goes to the type alias or not.

let res = self.def_id_to_res(did)?;
self.resolve_associated_item(res, item_name, ns, module_id)
}
Res::Def(
DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::TyAlias
| DefKind::ForeignTy,
DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::ForeignTy,
did,
) => {
debug!("looking for associated item named {} for item {:?}", item_name, did);
Expand Down
19 changes: 19 additions & 0 deletions src/test/rustdoc/intra-doc/type-alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Regression test for issue #86120.

#![deny(broken_intra_doc_links)]
#![crate_name = "foo"]

pub struct Foo;

/// You should really try [`Self::bar`]!
pub type Bar = Foo;

impl Bar {
pub fn bar() {}
}

/// The minimum is [`Self::MIN`].
pub type Int = i32;

// @has foo/type.Bar.html '//a[@href="struct.Foo.html#method.bar"]' 'Self::bar'
// @has foo/type.Int.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MIN"]' 'Self::MIN'