Skip to content

Commit

Permalink
Rollup merge of rust-lang#98053 - GuillaumeGomez:fix-generic-impl-jso…
Browse files Browse the repository at this point in the history
…n-ice, r=notriddle

Fix generic impl rustdoc json output

Fixes rust-lang#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``
  • Loading branch information
GuillaumeGomez authored Jun 15, 2022
2 parents 2a8abe6 + 99cd9ca commit 046ff35
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 10 deletions.
53 changes: 43 additions & 10 deletions src/librustdoc/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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);
}
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/test/rustdoc-json/generic_impl.rs
Original file line number Diff line number Diff line change
@@ -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
}
}

0 comments on commit 046ff35

Please sign in to comment.