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

rustdoc: avoid including impl blocks with filled-in generics #97130

Merged
merged 3 commits into from
Jun 2, 2022
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
31 changes: 29 additions & 2 deletions src/librustdoc/passes/collect_trait_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::visit::DocVisitor;

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::DefId;
use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::{self, DefIdTree};
use rustc_span::symbol::sym;

crate const COLLECT_TRAIT_IMPLS: Pass = Pass {
Expand Down Expand Up @@ -81,8 +81,35 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
// Do not calculate blanket impl list for docs that are not going to be rendered.
// While the `impl` blocks themselves are only in `libcore`, the module with `doc`
// attached is directly included in `libstd` as well.
let tcx = cx.tcx;
if did.is_local() {
for def_id in prim.impls(cx.tcx) {
for def_id in prim.impls(tcx).filter(|def_id| {
// Avoid including impl blocks with filled-in generics.
// https://github.com/rust-lang/rust/issues/94937
//
// FIXME(notriddle): https://github.com/rust-lang/rust/issues/97129
//
// This tactic of using inherent impl blocks for getting
// auto traits and blanket impls is a hack. What we really
// want is to check if `[T]` impls `Send`, which has
// nothing to do with the inherent impl.
//
// Rustdoc currently uses these `impl` block as a source of
// the `Ty`, as well as the `ParamEnv`, `SubstsRef`, and
// `Generics`. To avoid relying on the `impl` block, these
// things would need to be created from wholecloth, in a
// form that is valid for use in type inference.
let ty = tcx.type_of(def_id);
match ty.kind() {
ty::Slice(ty)
| ty::Ref(_, ty, _)
| ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
matches!(ty.kind(), ty::Param(..))
}
ty::Tuple(tys) => tys.iter().all(|ty| matches!(ty.kind(), ty::Param(..))),
_ => true,
}
}) {
let impls = get_auto_trait_and_blanket_impls(cx, def_id);
new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
}
Expand Down
14 changes: 14 additions & 0 deletions src/test/rustdoc/primitive-slice-auto-trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// compile-flags: --crate-type lib --edition 2018

#![crate_name = "foo"]
#![feature(rustdoc_internals)]

// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
// @has - '//span[@class="in-band"]' 'Primitive Type slice'
// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send'
// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync'
#[doc(primitive = "slice")]
/// this is a test!
mod slice_prim {}