Skip to content

Commit

Permalink
Auto merge of rust-lang#93539 - petrochenkov:doclink, r=camelid,micha…
Browse files Browse the repository at this point in the history
…elwoerister

rustdoc: Collect traits in scope for foreign inherent impls

Inherent impls can be inlined for variety of reasons (impls of reexported types, impls available through `Deref`, impls inlined for unclear reasons like in rust-lang#88679 (comment)).
If an impl is inlined, then doc links in its comments are resolved and we may need the set of traits that are in scope at that impl's definition point.
So in this PR we simply collect traits in scope for *all* inherent impls from other crates if their `Self` type is public, which is very similar for the strategy for trait impls previously used in rust-lang#88679.

Fixes rust-lang#93476
Fixes rust-lang#88679 (comment)
Fixes rust-lang#88679 (comment)
  • Loading branch information
bors committed Feb 5, 2022
2 parents 291bf94 + afc0030 commit 88fb06a
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 0 deletions.
17 changes: 17 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1369,10 +1369,27 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
)
}

/// Decodes all inherent impls in the crate (for rustdoc).
fn get_inherent_impls(self) -> impl Iterator<Item = (DefId, DefId)> + 'a {
(0..self.root.tables.inherent_impls.size()).flat_map(move |i| {
let ty_index = DefIndex::from_usize(i);
let ty_def_id = self.local_def_id(ty_index);
self.root
.tables
.inherent_impls
.get(self, ty_index)
.unwrap_or_else(Lazy::empty)
.decode(self)
.map(move |impl_index| (ty_def_id, self.local_def_id(impl_index)))
})
}

/// Decodes all traits in the crate (for rustdoc and rustc diagnostics).
fn get_traits(self) -> impl Iterator<Item = DefId> + 'a {
self.root.traits.decode(self).map(move |index| self.local_def_id(index))
}

/// Decodes all trait impls in the crate (for rustdoc).
fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a {
self.cdata.trait_impls.iter().flat_map(move |((trait_cnum_raw, trait_index), impls)| {
let trait_def_id = DefId {
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,16 +486,26 @@ impl CStore {
self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
}

/// Decodes all traits in the crate (for rustdoc).
pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
self.get_crate_data(cnum).get_traits()
}

/// Decodes all trait impls in the crate (for rustdoc).
pub fn trait_impls_in_crate_untracked(
&self,
cnum: CrateNum,
) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + '_ {
self.get_crate_data(cnum).get_trait_impls()
}

/// Decodes all inherent impls in the crate (for rustdoc).
pub fn inherent_impls_in_crate_untracked(
&self,
cnum: CrateNum,
) -> impl Iterator<Item = (DefId, DefId)> + '_ {
self.get_crate_data(cnum).get_inherent_impls()
}
}

impl CrateStore for CStore {
Expand Down
7 changes: 7 additions & 0 deletions src/librustdoc/passes/collect_intra_doc_links/early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ impl IntraLinkCrateLoader<'_, '_> {
let all_traits = Vec::from_iter(self.resolver.cstore().traits_in_crate_untracked(cnum));
let all_trait_impls =
Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum));
let all_inherent_impls =
Vec::from_iter(self.resolver.cstore().inherent_impls_in_crate_untracked(cnum));

// Querying traits in scope is expensive so we try to prune the impl and traits lists
// using privacy, private traits and impls from other crates are never documented in
Expand All @@ -134,6 +136,11 @@ impl IntraLinkCrateLoader<'_, '_> {
self.add_traits_in_parent_scope(impl_def_id);
}
}
for (ty_def_id, impl_def_id) in all_inherent_impls {
if self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public {
self.add_traits_in_parent_scope(impl_def_id);
}
}

self.all_traits.extend(all_traits);
self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id));
Expand Down
11 changes: 11 additions & 0 deletions src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#[derive(Clone)]
pub struct PublicStruct;

mod inner {
use super::PublicStruct;

impl PublicStruct {
/// [PublicStruct::clone]
pub fn method() {}
}
}
8 changes: 8 additions & 0 deletions src/test/rustdoc/intra-doc/extern-inherent-impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Reexport of a structure with public inherent impls having doc links in their comments. The doc
// link points to an associated item, so we check that traits in scope for that link are populated.

// aux-build:extern-inherent-impl-dep.rs

extern crate extern_inherent_impl_dep;

pub use extern_inherent_impl_dep::PublicStruct;

0 comments on commit 88fb06a

Please sign in to comment.