Skip to content

Commit a209539

Browse files
committed
Auto merge of #43849 - QuietMisdreavus:foreign-impls, r=steveklabnik
rustdoc: add new "Implementations on Foreign Types" section to traits Demo screenshot: ![image](https://user-images.githubusercontent.com/5217170/29281219-c547f758-80e3-11e7-808f-49f592c65c5b.png) Full demo available at https://tonberry.quietmisdreavus.net/foreign-test/foreign_test/trait.CheckIt.html This PR splits the "Implementors" section on trait pages into two: First, for impls on types local to the crate, their impls are kept as-is, printing one line for the impl line, and any additional lines for associated types. However, for types external to the crate, they are now pulled up over the others and are printed (almost) like the summary impl on the type page itself. This gives any doc comments on these impls or methods to be exposed in the documentation. There's just one small problem, though: [libstd docs apparently surface impls for libc and rand, possibly among others](https://tonberry.quietmisdreavus.net/foreign-std/std/marker/trait.Copy.html#foreign-impls). This adds this section to pages in the std docs where we might not want them to show up in the first place. I think this is a bug distinct from this PR, but it does make it drastically apparent. ~~My question, then, is this: Do we want this here? Taking it out involves fixing which impls are visible to rustdoc, possibly specifically when rendering the std facade. I'm convinced this is fine to land as-is, since it adds a feature specifically for non-std crates (i'm thinking of things like `num` or related crates that implement things on primitives or std types as part of their functionality).~~ (EDIT: I have an open PR to fix this: #44026)
2 parents f83d20e + a9f0f6d commit a209539

File tree

2 files changed

+86
-14
lines changed

2 files changed

+86
-14
lines changed

src/librustdoc/clean/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,16 @@ impl GetDefId for Type {
16511651
fn def_id(&self) -> Option<DefId> {
16521652
match *self {
16531653
ResolvedPath { did, .. } => Some(did),
1654+
Primitive(p) => ::html::render::cache().primitive_locations.get(&p).cloned(),
1655+
BorrowedRef { type_: box Generic(..), .. } =>
1656+
Primitive(PrimitiveType::Reference).def_id(),
1657+
BorrowedRef { ref type_, .. } => type_.def_id(),
1658+
Tuple(..) => Primitive(PrimitiveType::Tuple).def_id(),
1659+
BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
1660+
Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
1661+
Array(..) => Primitive(PrimitiveType::Array).def_id(),
1662+
RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(),
1663+
QPath { ref self_type, .. } => self_type.def_id(),
16541664
_ => None,
16551665
}
16561666
}

src/librustdoc/html/render.rs

+76-14
Original file line numberDiff line numberDiff line change
@@ -2416,12 +2416,12 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
24162416
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
24172417

24182418
let cache = cache();
2419-
write!(w, "
2419+
let impl_header = "
24202420
<h2 id='implementors' class='small-section-header'>
24212421
Implementors<a href='#implementors' class='anchor'></a>
24222422
</h2>
24232423
<ul class='item-list' id='implementors-list'>
2424-
")?;
2424+
";
24252425
if let Some(implementors) = cache.implementors.get(&it.def_id) {
24262426
// The DefId is for the first Type found with that name. The bool is
24272427
// if any Types with the same name but different DefId have been found.
@@ -2443,7 +2443,38 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
24432443
}
24442444
}
24452445

2446-
for implementor in implementors {
2446+
let (local, foreign) = implementors.iter()
2447+
.partition::<Vec<_>, _>(|i| i.impl_.for_.def_id()
2448+
.map_or(true, |d| cache.paths.contains_key(&d)));
2449+
2450+
if !foreign.is_empty() {
2451+
write!(w, "
2452+
<h2 id='foreign-impls' class='section-header'>
2453+
Implementations on Foreign Types<a href='#foreign-impls' class='anchor'></a>
2454+
</h2>
2455+
")?;
2456+
2457+
for implementor in foreign {
2458+
// need to get from a clean::Impl to a clean::Item so i can use render_impl
2459+
if let Some(t_did) = implementor.impl_.for_.def_id() {
2460+
if let Some(impl_item) = cache.impls.get(&t_did).and_then(|i| i.iter()
2461+
.find(|i| i.impl_item.def_id == implementor.def_id))
2462+
{
2463+
let i = &impl_item.impl_item;
2464+
let impl_ = Impl { impl_item: i.clone() };
2465+
let assoc_link = AssocItemLink::GotoSource(
2466+
i.def_id, &implementor.impl_.provided_trait_methods
2467+
);
2468+
render_impl(w, cx, &impl_, assoc_link,
2469+
RenderMode::Normal, i.stable_since(), false)?;
2470+
}
2471+
}
2472+
}
2473+
}
2474+
2475+
write!(w, "{}", impl_header)?;
2476+
2477+
for implementor in local {
24472478
write!(w, "<li><code>")?;
24482479
// If there's already another implementor that has the same abbridged name, use the
24492480
// full path, for example in `std::iter::ExactSizeIterator`
@@ -2465,6 +2496,10 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
24652496
}
24662497
writeln!(w, "</code></li>")?;
24672498
}
2499+
} else {
2500+
// even without any implementations to write in, we still want the heading and list, so the
2501+
// implementors javascript file pulled in below has somewhere to write the impls into
2502+
write!(w, "{}", impl_header)?;
24682503
}
24692504
write!(w, "</ul>")?;
24702505
write!(w, r#"<script type="text/javascript" async
@@ -3069,7 +3104,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
30693104
};
30703105
for i in &non_trait {
30713106
render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode,
3072-
containing_item.stable_since())?;
3107+
containing_item.stable_since(), true)?;
30733108
}
30743109
}
30753110
if let AssocItemRender::DerefFor { .. } = what {
@@ -3094,7 +3129,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
30943129
let did = i.trait_did().unwrap();
30953130
let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
30963131
render_impl(w, cx, i, assoc_link,
3097-
RenderMode::Normal, containing_item.stable_since())?;
3132+
RenderMode::Normal, containing_item.stable_since(), true)?;
30983133
}
30993134
}
31003135
Ok(())
@@ -3124,7 +3159,8 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
31243159
}
31253160

31263161
fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink,
3127-
render_mode: RenderMode, outer_version: Option<&str>) -> fmt::Result {
3162+
render_mode: RenderMode, outer_version: Option<&str>,
3163+
show_def_docs: bool) -> fmt::Result {
31283164
if render_mode == RenderMode::Normal {
31293165
let id = derive_id(match i.inner_impl().trait_ {
31303166
Some(ref t) => format!("impl-{}", Escape(&format!("{:#}", t))),
@@ -3153,7 +3189,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
31533189
fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
31543190
link: AssocItemLink, render_mode: RenderMode,
31553191
is_default_item: bool, outer_version: Option<&str>,
3156-
trait_: Option<&clean::Trait>) -> fmt::Result {
3192+
trait_: Option<&clean::Trait>, show_def_docs: bool) -> fmt::Result {
31573193
let item_type = item.type_();
31583194
let name = item.name.as_ref().unwrap();
31593195

@@ -3248,19 +3284,23 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
32483284
document_stability(w, cx, it)?;
32493285
if item.doc_value().is_some() {
32503286
document_full(w, item, cx, &prefix)?;
3251-
} else {
3287+
} else if show_def_docs {
32523288
// In case the item isn't documented,
32533289
// provide short documentation from the trait.
32543290
document_short(w, it, link, cx, &prefix)?;
32553291
}
32563292
}
32573293
} else {
32583294
document_stability(w, cx, item)?;
3259-
document_full(w, item, cx, &prefix)?;
3295+
if show_def_docs {
3296+
document_full(w, item, cx, &prefix)?;
3297+
}
32603298
}
32613299
} else {
32623300
document_stability(w, cx, item)?;
3263-
document_short(w, item, link, cx, &prefix)?;
3301+
if show_def_docs {
3302+
document_short(w, item, link, cx, &prefix)?;
3303+
}
32643304
}
32653305
}
32663306
Ok(())
@@ -3269,18 +3309,23 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
32693309
let traits = &cache().traits;
32703310
let trait_ = i.trait_did().and_then(|did| traits.get(&did));
32713311

3312+
if !show_def_docs {
3313+
write!(w, "<span class='docblock autohide'>")?;
3314+
}
3315+
32723316
write!(w, "<div class='impl-items'>")?;
32733317
for trait_item in &i.inner_impl().items {
32743318
doc_impl_item(w, cx, trait_item, link, render_mode,
3275-
false, outer_version, trait_)?;
3319+
false, outer_version, trait_, show_def_docs)?;
32763320
}
32773321

32783322
fn render_default_items(w: &mut fmt::Formatter,
32793323
cx: &Context,
32803324
t: &clean::Trait,
32813325
i: &clean::Impl,
32823326
render_mode: RenderMode,
3283-
outer_version: Option<&str>) -> fmt::Result {
3327+
outer_version: Option<&str>,
3328+
show_def_docs: bool) -> fmt::Result {
32843329
for trait_item in &t.items {
32853330
let n = trait_item.name.clone();
32863331
if i.items.iter().find(|m| m.name == n).is_some() {
@@ -3290,17 +3335,23 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
32903335
let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
32913336

32923337
doc_impl_item(w, cx, trait_item, assoc_link, render_mode, true,
3293-
outer_version, None)?;
3338+
outer_version, None, show_def_docs)?;
32943339
}
32953340
Ok(())
32963341
}
32973342

32983343
// If we've implemented a trait, then also emit documentation for all
32993344
// default items which weren't overridden in the implementation block.
33003345
if let Some(t) = trait_ {
3301-
render_default_items(w, cx, t, &i.inner_impl(), render_mode, outer_version)?;
3346+
render_default_items(w, cx, t, &i.inner_impl(),
3347+
render_mode, outer_version, show_def_docs)?;
33023348
}
33033349
write!(w, "</div>")?;
3350+
3351+
if !show_def_docs {
3352+
write!(w, "</span>")?;
3353+
}
3354+
33043355
Ok(())
33053356
}
33063357

@@ -3484,6 +3535,17 @@ fn sidebar_trait(fmt: &mut fmt::Formatter, it: &clean::Item,
34843535

34853536
sidebar.push_str(&sidebar_assoc_items(it));
34863537

3538+
let c = cache();
3539+
3540+
if let Some(implementors) = c.implementors.get(&it.def_id) {
3541+
if implementors.iter().any(|i| i.impl_.for_.def_id()
3542+
.map_or(false, |d| !c.paths.contains_key(&d)))
3543+
{
3544+
sidebar.push_str("<li><a href=\"#foreign-impls\">\
3545+
Implementations on Foreign Types</a></li>");
3546+
}
3547+
}
3548+
34873549
sidebar.push_str("<li><a href=\"#implementors\">Implementors</a></li>");
34883550

34893551
write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)

0 commit comments

Comments
 (0)