Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rustdoc does not show bounds on associated items in the declaration of re-exported traits #84579

Closed
Nemo157 opened this issue Apr 26, 2021 · 4 comments · Fixed by #102439
Closed
Assignees
Labels
A-associated-items Area: Associated items (types, constants & functions) A-cross-crate-reexports Area: Documentation that has been re-exported from a different crate A-rustdoc-ui Area: Rustdoc UI (generated HTML) C-bug Category: This is a bug. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.

Comments

@Nemo157
Copy link
Member

Nemo157 commented Apr 26, 2021

Currently on nightly the declaration for IntoIterator looks like:

image

While the actual declaration with attributes stripped is:

pub trait IntoIterator {
    type Item;
    type IntoIter: Iterator<Item = Self::Item>;
    fn into_iter(self) -> Self::IntoIter;
}

Previously up till 1.48.0 this rendered as:

image

Which is not great, but at least it has the information there. I tried to identify the PR which changed this in 1.49.0, but skimming the list from a few search queries none of them stood out to me.

@Nemo157 Nemo157 added T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. C-bug Category: This is a bug. A-rustdoc-ui Area: Rustdoc UI (generated HTML) labels Apr 26, 2021
@cynecx
Copy link
Contributor

cynecx commented May 2, 2021

Rendering the IntoIterator declaration without the attributes and outside core/std works just fine:

image

@Nemo157
Copy link
Member Author

Nemo157 commented May 2, 2021

Ooooh, it works on core::iter::IntoIterator, it's only on the re-exported std::iter::IntoIterator that it has this issue. Similarly on 1.48.0 core showed the associated type bound nicely, only std showed it as a where clause.

@Nemo157 Nemo157 changed the title Rustdoc does not show bounds on associated items in the declaration Rustdoc does not show bounds on associated items in the declaration of re-exported traits May 2, 2021
@cynecx
Copy link
Contributor

cynecx commented May 25, 2021

I may have found the reason why we are skipping the associated type binding.

So when an external item (in our case an associated type) gets documented it goes through clean::inline::build_external_trait which then goes through this clean visitor:

impl Clean<Item> for ty::AssocItem {
fn clean(&self, cx: &mut DocContext<'_>) -> Item {

Further down we get to:

let generics = (tcx.generics_of(self.def_id), predicates).clean(cx);

which produces (for the IntoIter associated item):

[src/librustdoc/clean/mod.rs:1101] tcx.explicit_item_bounds(self.def_id) = [
    (
        Binder(TraitPredicate(<<Self as b::IntoIterator>::IntoIter as std::marker::Sized>), []),
        /home/cynecx/dev/test-rustdoc/b/src/lib.rs:3:5: 3:48 (#0),
    ),
    (
        Binder(TraitPredicate(<<Self as b::IntoIterator>::IntoIter as std::iter::Iterator>), []),
        /home/cynecx/dev/test-rustdoc/b/src/lib.rs:3:20: 3:47 (#0),
    ),
    (
        Binder(ProjectionPredicate(ProjectionTy { substs: [<Self as b::IntoIterator>::IntoIter], item_def_id: DefId(2:7247 ~ core[51e2]::iter::traits::iterator::Iterator::Item) }, <Self as b::IntoIterator>::Item), []),
        /home/cynecx/dev/test-rustdoc/b/src/lib.rs:3:29: 3:46 (#0),
    ),
]

Then

let generics = (tcx.generics_of(self.def_id), predicates).clean(cx);
produces:

Output
[src/librustdoc/clean/mod.rs:1105] &generics = Generics {
    params: [],
    where_predicates: [
        BoundPredicate {
            ty: QPath {
                name: "IntoIter",
                self_type: Generic(
                    "Self",
                ),
                self_def_id: None,
                trait_: ResolvedPath {
                    path: Path {
                        global: false,
                        res: Err,
                        segments: [
                            PathSegment {
                                name: "IntoIterator",
                                args: AngleBracketed {
                                    args: [],
                                    bindings: [],
                                },
                            },
                        ],
                    },
                    param_names: None,
                    did: DefId(19:3 ~ b[78df]::IntoIterator),
                    is_generic: false,
                },
            },
            bounds: [
                TraitBound(
                    PolyTrait {
                        trait_: ResolvedPath {
                            path: Path {
                                global: false,
                                res: Err,
                                segments: [
                                    PathSegment {
                                        name: "Sized",
                                        args: AngleBracketed {
                                            args: [],
                                            bindings: [],
                                        },
                                    },
                                ],
                            },
                            param_names: None,
                            did: DefId(2:2839 ~ core[51e2]::marker::Sized),
                            is_generic: false,
                        },
                        generic_params: [],
                    },
                    None,
                ),
            ],
        },
        BoundPredicate {
            ty: QPath {
                name: "IntoIter",
                self_type: Generic(
                    "Self",
                ),
                self_def_id: None,
                trait_: ResolvedPath {
                    path: Path {
                        global: false,
                        res: Err,
                        segments: [
                            PathSegment {
                                name: "IntoIterator",
                                args: AngleBracketed {
                                    args: [],
                                    bindings: [],
                                },
                            },
                        ],
                    },
                    param_names: None,
                    did: DefId(19:3 ~ b[78df]::IntoIterator),
                    is_generic: false,
                },
            },
            bounds: [
                TraitBound(
                    PolyTrait {
                        trait_: ResolvedPath {
                            path: Path {
                                global: false,
                                res: Err,
                                segments: [
                                    PathSegment {
                                        name: "Iterator",
                                        args: AngleBracketed {
                                            args: [],
                                            bindings: [],
                                        },
                                    },
                                ],
                            },
                            param_names: None,
                            did: DefId(2:7246 ~ core[51e2]::iter::traits::iterator::Iterator),
                            is_generic: false,
                        },
                        generic_params: [],
                    },
                    None,
                ),
            ],
        },
        EqPredicate {
            lhs: QPath {
                name: "Item",
                self_type: QPath {
                    name: "IntoIter",
                    self_type: Generic(
                        "Self",
                    ),
                    self_def_id: None,
                    trait_: ResolvedPath {
                        path: Path {
                            global: false,
                            res: Err,
                            segments: [
                                PathSegment {
                                    name: "IntoIterator",
                                    args: AngleBracketed {
                                        args: [],
                                        bindings: [],
                                    },
                                },
                            ],
                        },
                        param_names: None,
                        did: DefId(19:3 ~ b[78df]::IntoIterator),
                        is_generic: false,
                    },
                },
                self_def_id: None,
                trait_: ResolvedPath {
                    path: Path {
                        global: false,
                        res: Err,
                        segments: [
                            PathSegment {
                                name: "Iterator",
                                args: AngleBracketed {
                                    args: [],
                                    bindings: [],
                                },
                            },
                        ],
                    },
                    param_names: None,
                    did: DefId(2:7246 ~ core[51e2]::iter::traits::iterator::Iterator),
                    is_generic: false,
                },
            },
            rhs: QPath {
                name: "Item",
                self_type: Generic(
                    "Self",
                ),
                self_def_id: None,
                trait_: ResolvedPath {
                    path: Path {
                        global: false,
                        res: Err,
                        segments: [
                            PathSegment {
                                name: "IntoIterator",
                                args: AngleBracketed {
                                    args: [],
                                    bindings: [],
                                },
                            },
                        ],
                    },
                    param_names: None,
                    did: DefId(19:3 ~ b[78df]::IntoIterator),
                    is_generic: false,
                },
            },
        },
    ],
}

The last WherePredicate::EqPredicate boils down to <Self::IntoIter as Iterator>::Item == Self::Item which gets discarded further down here (in a filter_map operation):

.filter_map(|pred| {
let (name, self_type, trait_, bounds) = match *pred {
WherePredicate::BoundPredicate {
ty: QPath { ref name, ref self_type, ref trait_, .. },
ref bounds,
} => (name, self_type, trait_, bounds),
_ => return None,

Afaics, the reason the unexported trait gets properly "documented" is because a different code path is run which doesn't involve clean on a ty::AssocItem.

@fmease
Copy link
Member

fmease commented Sep 22, 2022

@rustbot label A-cross-crate-reexports A-associated-items

Update: The output is still incorrect but it now looks like this:

pub trait IntoIterator {
    type Item;
    type IntoIter: Iterator
    where
        <Self::IntoIter as Iterator>::Item == Self::Item;

    fn into_iter(self) -> Self::IntoIter;
}

@rustbot claim

@rustbot rustbot added A-cross-crate-reexports Area: Documentation that has been re-exported from a different crate A-associated-items Area: Associated items (types, constants & functions) labels Sep 22, 2022
@bors bors closed this as completed in 2e7e17a Oct 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-associated-items Area: Associated items (types, constants & functions) A-cross-crate-reexports Area: Documentation that has been re-exported from a different crate A-rustdoc-ui Area: Rustdoc UI (generated HTML) C-bug Category: This is a bug. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants