about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorYuki Okushi <jtitor@2k36.org>2022-06-16 07:24:40 +0900
committerGitHub <noreply@github.com>2022-06-16 07:24:40 +0900
commit4ee78a686facf95eb640fc00d5b92d4e9281e81c (patch)
treeba451d17fb0ed0b8beba3ff15aee2fc49b4de334 /src
parent52afa3a70c2f5fad0c61f06497b13b66490b97a8 (diff)
parent99cd9cae10fd7c9db35f3047a7f376bdb2d13f66 (diff)
downloadrust-4ee78a686facf95eb640fc00d5b92d4e9281e81c.tar.gz
rust-4ee78a686facf95eb640fc00d5b92d4e9281e81c.zip
Rollup merge of #98053 - GuillaumeGomez:fix-generic-impl-json-ice, r=notriddle
Fix generic impl rustdoc json output

Fixes #97986.

The problem in case of generic trait impl is that the trait's items are the same for all the types afterward. But since they're the same, it's safe for rustdoc-json to just ignore them.

A little representation of what's going on:

```rust
trait T {
    fn f(); // <- defid 0
}

impl<Y> T for Y {
    fn f() {} // <- defid 1
}

struct S; // <- defid 1 (since it matches `impl<Y> T for Y`
```

cc ```@Urgau```

r? ```@CraftSpider```
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/json/mod.rs53
-rw-r--r--src/test/rustdoc-json/generic_impl.rs24
2 files changed, 67 insertions, 10 deletions
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index f338050bee0..0964b757e74 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -181,15 +181,44 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         let name = item.name;
         let item_id = item.item_id;
         if let Some(mut new_item) = self.convert_item(item) {
-            if let types::ItemEnum::Trait(ref mut t) = new_item.inner {
-                t.implementations = self.get_trait_implementors(item_id.expect_def_id())
-            } else if let types::ItemEnum::Struct(ref mut s) = new_item.inner {
-                s.impls = self.get_impls(item_id.expect_def_id())
-            } else if let types::ItemEnum::Enum(ref mut e) = new_item.inner {
-                e.impls = self.get_impls(item_id.expect_def_id())
-            } else if let types::ItemEnum::Union(ref mut u) = new_item.inner {
-                u.impls = self.get_impls(item_id.expect_def_id())
-            }
+            let can_be_ignored = match new_item.inner {
+                types::ItemEnum::Trait(ref mut t) => {
+                    t.implementations = self.get_trait_implementors(item_id.expect_def_id());
+                    false
+                }
+                types::ItemEnum::Struct(ref mut s) => {
+                    s.impls = self.get_impls(item_id.expect_def_id());
+                    false
+                }
+                types::ItemEnum::Enum(ref mut e) => {
+                    e.impls = self.get_impls(item_id.expect_def_id());
+                    false
+                }
+                types::ItemEnum::Union(ref mut u) => {
+                    u.impls = self.get_impls(item_id.expect_def_id());
+                    false
+                }
+
+                types::ItemEnum::Method(_)
+                | types::ItemEnum::AssocConst { .. }
+                | types::ItemEnum::AssocType { .. } => true,
+                types::ItemEnum::Module(_)
+                | types::ItemEnum::ExternCrate { .. }
+                | types::ItemEnum::Import(_)
+                | types::ItemEnum::StructField(_)
+                | types::ItemEnum::Variant(_)
+                | types::ItemEnum::Function(_)
+                | types::ItemEnum::TraitAlias(_)
+                | types::ItemEnum::Impl(_)
+                | types::ItemEnum::Typedef(_)
+                | types::ItemEnum::OpaqueTy(_)
+                | types::ItemEnum::Constant(_)
+                | types::ItemEnum::Static(_)
+                | types::ItemEnum::ForeignType
+                | types::ItemEnum::Macro(_)
+                | types::ItemEnum::ProcMacro(_)
+                | types::ItemEnum::PrimitiveType(_) => false,
+            };
             let removed = self
                 .index
                 .borrow_mut()
@@ -199,7 +228,11 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
             // to make sure the items are unique. The main place this happens is when an item, is
             // reexported in more than one place. See `rustdoc-json/reexport/in_root_and_mod`
             if let Some(old_item) = removed {
-                assert_eq!(old_item, new_item);
+                // In case of generic implementations (like `impl<T> Trait for T {}`), all the
+                // inner items will be duplicated so we can ignore if they are slightly different.
+                if !can_be_ignored {
+                    assert_eq!(old_item, new_item);
+                }
             }
         }
 
diff --git a/src/test/rustdoc-json/generic_impl.rs b/src/test/rustdoc-json/generic_impl.rs
new file mode 100644
index 00000000000..ac68ba578b6
--- /dev/null
+++ b/src/test/rustdoc-json/generic_impl.rs
@@ -0,0 +1,24 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/97986>.
+
+// @has generic_impl.json
+// @has - "$.index[*][?(@.name=='f')]"
+// @has - "$.index[*][?(@.name=='AssocTy')]"
+// @has - "$.index[*][?(@.name=='AssocConst')]"
+
+pub mod m {
+    pub struct S;
+}
+
+pub trait F {
+    type AssocTy;
+    const AssocConst: usize;
+    fn f() -> m::S;
+}
+
+impl<T> F for T {
+    type AssocTy = u32;
+    const AssocConst: usize = 0;
+    fn f() -> m::S {
+        m::S
+    }
+}