about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Howell <michael@notriddle.com>2021-11-29 12:18:57 -0700
committerMichael Howell <michael@notriddle.com>2021-11-29 12:23:07 -0700
commit85ba6c7b3489f5b23ca146d6ebde657bf8b52c36 (patch)
treeb1d337e852eb729d6cd8f3c8f14afd2113f51477
parent6db0a0e9a4a2f55b1a85954e114ada0b45c32e45 (diff)
downloadrust-85ba6c7b3489f5b23ca146d6ebde657bf8b52c36.tar.gz
rust-85ba6c7b3489f5b23ca146d6ebde657bf8b52c36.zip
Only show notable traits if both types are the same
Checking only their DefId doesn't work because all slices have the same
fake DefId.

Fixes #91347
-rw-r--r--src/librustdoc/clean/types.rs39
-rw-r--r--src/librustdoc/html/render/mod.rs9
-rw-r--r--src/test/rustdoc/doc-notable_trait-slice.rs20
3 files changed, 67 insertions, 1 deletions
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 37acf68defd..f7762fd2521 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1468,6 +1468,45 @@ crate enum Type {
 rustc_data_structures::static_assert_size!(Type, 72);
 
 impl Type {
+    /// When comparing types for equality, it can help to ignore `&` wrapping.
+    crate fn without_borrowed_ref(&self) -> &Type {
+        let mut result = self;
+        while let Type::BorrowedRef { type_, .. } = result {
+            result = &*type_;
+        }
+        result
+    }
+
+    /// Check if two types are "potentially the same."
+    /// This is different from Eq, because it knows that things like
+    /// `Placeholder` are possible matches for everything.
+    crate fn is_same(&self, other: &Self, cache: &Cache) -> bool {
+        match (self, other) {
+            // Recursive cases.
+            (Type::Tuple(a), Type::Tuple(b)) => {
+                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(&b, cache))
+            }
+            (Type::Slice(a), Type::Slice(b)) => a.is_same(&b, cache),
+            (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(&b, cache),
+            (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
+                mutability == b_mutability && type_.is_same(&b_type_, cache)
+            }
+            (
+                Type::BorrowedRef { mutability, type_, .. },
+                Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
+            ) => mutability == b_mutability && type_.is_same(&b_type_, cache),
+            // Placeholders and generics are equal to all other types.
+            (Type::Infer, _) | (_, Type::Infer) => true,
+            (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
+            // Other cases, such as primitives, just use recursion.
+            (a, b) => a
+                .def_id(cache)
+                .and_then(|a| Some((a, b.def_id(cache)?)))
+                .map(|(a, b)| a == b)
+                .unwrap_or(false),
+        }
+    }
+
     crate fn primitive_type(&self) -> Option<PrimitiveType> {
         match *self {
             Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 08022d526fe..8bf7d0416dd 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1235,10 +1235,17 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
 fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
     let mut out = Buffer::html();
 
-    if let Some(did) = decl.output.as_return().and_then(|t| t.def_id(cx.cache())) {
+    if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t)))
+    {
         if let Some(impls) = cx.cache().impls.get(&did) {
             for i in impls {
                 let impl_ = i.inner_impl();
+                if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache())
+                {
+                    // Two different types might have the same did,
+                    // without actually being the same.
+                    continue;
+                }
                 if let Some(trait_) = &impl_.trait_ {
                     let trait_did = trait_.def_id();
 
diff --git a/src/test/rustdoc/doc-notable_trait-slice.rs b/src/test/rustdoc/doc-notable_trait-slice.rs
new file mode 100644
index 00000000000..b0d41402721
--- /dev/null
+++ b/src/test/rustdoc/doc-notable_trait-slice.rs
@@ -0,0 +1,20 @@
+#![feature(doc_notable_trait)]
+
+#[doc(notable_trait)]
+pub trait SomeTrait {}
+
+pub struct SomeStruct;
+pub struct OtherStruct;
+impl SomeTrait for &[SomeStruct] {}
+
+// @has doc_notable_trait_slice/fn.bare_fn_matches.html
+// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_matches() -> &'static [SomeStruct] {
+    &[]
+}
+
+// @has doc_notable_trait_slice/fn.bare_fn_no_matches.html
+// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
+    &[]
+}