diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 51cc836cd15..3cf166a3e43 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -55,7 +55,6 @@
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
use rustc_middle::ty::{self, TyCtxt};
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_span::{
symbol::{sym, Symbol},
BytePos, FileName, RealFileName,
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 4054281f346..3e58dd96ed9 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -530,7 +530,11 @@ fn serialize(&self, serializer: S) -> Result
.values()
.flat_map(|AliasedTypeImpl { impl_, type_aliases }| {
let mut ret = Vec::new();
- let trait_ = impl_.inner_impl().trait_.as_ref().map(|path| path.last().to_string());
+ let trait_ = impl_
+ .inner_impl()
+ .trait_
+ .as_ref()
+ .map(|trait_| format!("{:#}", trait_.print(cx)));
// render_impl will filter out "impossible-to-call" methods
// to make that functionality work here, it needs to be called with
// each type alias, and if it gives a different result, split the impl
@@ -538,12 +542,25 @@ fn serialize(&self, serializer: S) -> Result
let mut buf = Buffer::html();
cx.id_map = Default::default();
cx.deref_id_map = Default::default();
+ let target_did = impl_
+ .inner_impl()
+ .trait_
+ .as_ref()
+ .map(|trait_| trait_.def_id())
+ .or_else(|| impl_.inner_impl().for_.def_id(cache));
+ let provided_methods;
+ let assoc_link = if let Some(target_did) = target_did {
+ provided_methods = impl_.inner_impl().provided_trait_methods(cx.tcx());
+ AssocItemLink::GotoSource(ItemId::DefId(target_did), &provided_methods)
+ } else {
+ AssocItemLink::Anchor(None)
+ };
super::render_impl(
&mut buf,
cx,
*impl_,
&type_alias_item,
- AssocItemLink::Anchor(None),
+ assoc_link,
RenderMode::Normal,
None,
&[],
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 6f0bcb8e6d0..7c052606aba 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -680,12 +680,14 @@ function preLoadCss(cssUrl) {
let implementations = document.getElementById("implementations-list");
let trait_implementations = document.getElementById("trait-implementations-list");
+ let trait_implementations_header = document.getElementById("trait-implementations");
// We want to include the current type alias's impls, and no others.
const script = document.querySelector("script[data-self-path]");
const selfPath = script ? script.getAttribute("data-self-path") : null;
// These sidebar blocks need filled in, too.
+ const mainContent = document.querySelector("#main-content");
const sidebarSection = document.querySelector(".sidebar section");
let methods = document.querySelector(".sidebar .block.method");
let associatedTypes = document.querySelector(".sidebar .block.associatedtype");
@@ -719,18 +721,18 @@ function preLoadCss(cssUrl) {
const h = document.createElement("h3");
h.appendChild(link);
trait_implementations = outputList;
+ trait_implementations_header = outputListHeader;
sidebarSection.appendChild(h);
sidebarTraitList = document.createElement("ul");
sidebarTraitList.className = "block trait-implementation";
sidebarSection.appendChild(sidebarTraitList);
- const mainContent = document.querySelector("#main-content");
mainContent.appendChild(outputListHeader);
mainContent.appendChild(outputList);
} else {
implementations = outputList;
if (trait_implementations) {
- document.insertBefore(outputListHeader, trait_implementations);
- document.insertBefore(outputList, trait_implementations);
+ mainContent.insertBefore(outputListHeader, trait_implementations_header);
+ mainContent.insertBefore(outputList, trait_implementations_header);
} else {
const mainContent = document.querySelector("#main-content");
mainContent.appendChild(outputListHeader);
@@ -762,7 +764,14 @@ function preLoadCss(cssUrl) {
}
}
if (i !== 0) {
+ const oldHref = `#${el.id}`;
+ const newHref = `#${el.id}-${i}`;
el.id = `${el.id}-${i}`;
+ onEachLazy(template.content.querySelectorAll("a[href]"), link => {
+ if (link.getAttribute("href") === oldHref) {
+ link.href = newHref;
+ }
+ });
}
idMap.set(el.id, i + 1);
});
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index 5b6d5435b35..138a1b302fd 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -167,6 +167,26 @@ impl SomeOtherTypeWithMethodsAndInlining {
pub fn some_other_method_directly(&self) {}
}
+/// Another type alias, this time with methods.
+pub struct UnderlyingFooBarBaz;
+pub type SomeOtherTypeWithMethodsAndInliningAndTraits = UnderlyingFooBarBaz;
+
+impl AsRef for UnderlyingFooBarBaz {
+ fn as_ref(&self) -> &str {
+ "hello"
+ }
+}
+
+impl UnderlyingFooBarBaz {
+ pub fn inherent_fn(&self) {}
+}
+
+impl AsRef for SomeOtherTypeWithMethodsAndInliningAndTraits {
+ fn as_ref(&self) -> &u8 {
+ b"hello"
+ }
+}
+
pub mod huge_amount_of_consts {
include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs"));
}
diff --git a/tests/rustdoc-gui/type-impls.goml b/tests/rustdoc-gui/type-impls.goml
index cc18b5de475..870a9cbe53f 100644
--- a/tests/rustdoc-gui/type-impls.goml
+++ b/tests/rustdoc-gui/type-impls.goml
@@ -24,11 +24,39 @@ assert-text: (".block.method li:nth-child(2)", 'some_other_method_directly')
assert-text: (".block.method li:nth-child(3)", 'warning1')
assert-text: (".block.method li:nth-child(4)", 'warning2')
+// Now try trait implementation merging and duplicate renumbering
+go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInliningAndTraits.html"
+
+// method directly on type alias
+assert: "//*[@id='method.as_ref']"
+assert-count: ("//*[@id='method.as_ref']", 1)
+// method on underlying type
+assert: "//*[@id='method.as_ref-1']"
+
+// sidebar items
+assert-count: (
+ "//*[@class='sidebar-elems']//h3/a[@href='#trait-implementations']",
+ 1
+)
+assert-text: ("//*[@class='sidebar-elems']//li/a[@href='#impl-AsRef%3Cstr%3E-for-UnderlyingFooBarBaz']", "AsRef")
+assert-text: (
+ "//*[@class='sidebar-elems']//li/a[@href='#impl-AsRef%3Cu8%3E-for-UnderlyingFooBarBaz']",
+ "AsRef"
+)
+assert-count: ("#trait-implementations-list", 1)
+assert-count: ("#trait-implementations-list > details", 2)
+// Both links point at the underlying trait
+store-property: ("//*[@id='method.as_ref']//a[@class='fn']", {"href": href})
+assert-property: ("//*[@id='method.as_ref-1']//a[@class='fn']", {"href": |href|})
+// Both links have a self-anchor
+assert: "//*[@id='method.as_ref']//a[@class='anchor'][@href='#method.as_ref']"
+assert: "//*[@id='method.as_ref-1']//a[@class='anchor'][@href='#method.as_ref-1']"
+
///////////////////////////////////////////////////////////////////////////
// Now, if JavaScript is disabled, only the first method will be present //
///////////////////////////////////////////////////////////////////////////
javascript: false
-reload:
+go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInlining.html"
// method directly on type alias
wait-for: "//*[@id='method.some_other_method_directly']"
@@ -37,3 +65,22 @@ wait-for: "//*[@id='method.some_other_method_directly']"
assert-false: "//*[@id='method.must_use']"
assert-false: "//*[@id='method.warning1']"
assert-false: "//*[@id='method.warning2']"
+
+// Now try trait implementation merging and duplicate renumbering
+go-to: "file://" + |DOC_PATH| + "/test_docs/type.SomeOtherTypeWithMethodsAndInliningAndTraits.html"
+
+// methods directly on type alias
+assert: "//*[@id='method.as_ref']"
+assert-count: ("//*[@id='method.as_ref']", 1)
+// method on target type
+assert-false: "//*[@id='method.as_ref-1']"
+
+// sidebar items
+assert-count: (
+ "//*[@class='sidebar-elems']//h3/a[@href='#trait-implementations']",
+ 1
+)
+assert-false: "//a[@href='#impl-AsRef%3Cstr%3E-for-UnderlyingFooBarBaz']"
+assert: "//a[@href='#impl-AsRef%3Cu8%3E-for-UnderlyingFooBarBaz']"
+assert-count: ("#trait-implementations-list", 1)
+assert-count: ("#trait-implementations-list > details", 1)
diff --git a/tests/rustdoc/type-alias/deref-32077.rs b/tests/rustdoc/type-alias/deref-32077.rs
index 740ed4cec70..186ebb1a632 100644
--- a/tests/rustdoc/type-alias/deref-32077.rs
+++ b/tests/rustdoc/type-alias/deref-32077.rs
@@ -22,7 +22,7 @@ impl Bar for GenericStruct {}
// We check that "Aliased type" is also present as a title in the sidebar.
// @has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased type'
// We check that we have the implementation of the type alias itself.
-// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct'
+// @has - '//*[@id="impl-GenericStruct%3Cu8%3E"]/h3' 'impl TypedefStruct'
// @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()'
// This trait implementation doesn't match the type alias parameters so shouldn't appear in docs.
// @!has - '//h3' 'impl Bar for GenericStruct {}'