Skip to content

Put negative implementors first and apply same ordering logic to foreign implementors #142380

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

GuillaumeGomez
Copy link
Member

@GuillaumeGomez GuillaumeGomez commented Jun 11, 2025

Fixes #51129.

This PR changeda surprisingly small amount of things to put negative trait impls before the others: basically just adding a new information in the generated JS file for foreign implementors and a "negative marker" DOM element to know where to insert negative impls.

I also used this occasion to make the foreign implementors sort the same as the local ones by using compare_names.

You can test it here.

r? @notriddle

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output. labels Jun 11, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jun 11, 2025

Some changes occurred in HTML/CSS/JS.

cc @GuillaumeGomez, @jsha, @lolbinarycat

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez
Copy link
Member Author

Took me a while to figure out where the typescript definition was stored to fix the error. ^^'


fn insert_if_needed(&mut self, w: &mut fmt::Formatter<'_>, implementor: &Impl) -> fmt::Result {
if !self.inserted_negative_marker && !implementor.is_negative_trait_impl() {
write!(w, "<div class=\"negative-marker\"></div>")?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
write!(w, "<div class=\"negative-marker\"></div>")?;
write!(w, "<span class=\"negative-marker\"></span>")?;

Using a span feels more idiomatic, as it's less likely to cause weird extra linebreaks in unstyled environments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the docs/spec I read, it's exactly what div is for. From MDN:

The <div> HTML element is the generic container for flow content. It has no effect on the content or layout until styled in some way using CSS (e.g., styling is directly applied to it, or some kind of layout model like Flexbox is applied to its parent element).

As for linebreaks, I couldn't find information about how div is supposed to handle them by default.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

div has a default style of display: block; so its presence can in fact change layout quite easily, as it will cause line/paragraph breaks the same way any other block element will. I'm not sure why MDN says it can't impact layout.

span is essentially the equivalent of div except it is used for inline content, which I believe a zero size marker with no impact on layout technically is?

let part = OrderedJson::array_sorted(
implementors.sort_unstable();

let part = OrderedJson::array_unsorted(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely an improvement, as it eliminates an allocation, but we're still allocating an intermediate string for each element.

OrderedJson could be much more efficient if it had a method that appended using serde_json::to_writer.

I can open an issue for improving the OrderedJson interface, if you want.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An issue would be welcome indeed.

@@ -791,10 +797,12 @@ impl TraitAliasPart {
}
}

#[derive(PartialEq, Eq)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic error: Eq and Ord impls disagree on the definition of equality, as Ord only checks the name.

this can easily be fixed by writing a PartialEq impl that defers to Ord:

impl PartialEq for Implementor {
    fn eq(&self, other: &Self) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting approach, I like it. Adding it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, in which would it be an issue to have this difference? Ordering and equality don't have to be equivalent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a correctness requirement on PartialEq.

it doesn't cause any issue with the current code, bur it could cause issues with generic datastructures like BTreeMap, so I think it would be best to try to avoid something that can cause this type of sneaky logic error.

I think this is technically the same class of error as if you had Copy and Clone diverge, not unsound, just incorrect.

Comment on lines +2779 to +2781
.negative-marker {
display: none;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any meaningful difference between an inline span with no content and the same span but hidden? if not, then I don't think this is needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes the rendering engine completely discard the element. So close to no difference. But still better to have.

@@ -467,7 +467,7 @@ declare namespace rustdoc {
* Provied by generated `trait.impl` files.
*/
type Implementors = {
[key: string]: Array<[string, number, Array<string>]>
[key: string]: Array<[string, number, number, Array<string>]>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[key: string]: Array<[string, number, number, Array<string>]>
[key: string]: Array<[string, number, 0|1, Array<string>]>

we can be a bit more specific here.

also, it would be nice to expand the comment to mention what the meaning of each field is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL.

@rust-log-analyzer

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Jun 17, 2025
alternate interface for OrderedJson to reduce allocations

inspired by #142380 (comment)

r? `@GuillaumeGomez`
<!-- homu-ignore:start -->
<!--
If this PR is related to an unstable feature or an otherwise tracked effort,
please link to the relevant tracking issue here. If you don't know of a related
tracking issue or there are none, feel free to ignore this.

This PR will get automatically assigned to a reviewer. In case you would like
a specific user to review your work, you can assign it to them by using

    r? <reviewer name>
-->
<!-- homu-ignore:end -->
@bors
Copy link
Collaborator

bors commented Jun 22, 2025

☔ The latest upstream changes (presumably #142667) made this pull request unmergeable. Please resolve the merge conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[rustdoc] Implementors section of Sync (and other similar traits) should separate implementors and !implementors
6 participants