Skip to content

[rustdoc] Unify type aliases rendering with other ADT #140863

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 8 commits into
base: master
Choose a base branch
from

Conversation

GuillaumeGomez
Copy link
Member

@GuillaumeGomez GuillaumeGomez commented May 9, 2025

Fixes #140739.

Better reviewed one commit at a time.

Just one thing I'm wondering: should we also render non-repr attributes? If so, I wonder if we shouldn't simply change clean::TypeAlias to contain the other ADT directly (Struct, Enum and Union) and remove the TypeAlias::generics field.

Can be done in a follow-up too.

cc @camelid
r? @notriddle

@rustbot rustbot added A-rustdoc-json Area: Rustdoc JSON backend 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 May 9, 2025
Copy link
Contributor

@lolbinarycat lolbinarycat left a comment

Choose a reason for hiding this comment

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

I hope this is helpful, it's mostly a bunch of nitpicks, I didn't find any major issues (besides the witout typo), feel free to disregard things if you believe you have a good reason to do things your way, though I would appreciate a brief explanation so I can try to provide better feedback in the future.

@@ -759,22 +762,19 @@ impl Item {
Some(tcx.visibility(def_id))
}

pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
pub(crate) fn attributes_witout_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<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
pub(crate) fn attributes_witout_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
/// get a list of every attribute except `#[repr(...)]`.
pub(crate) fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {

Typo, also add a small doc comment to make things more immediately obvious.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the typo! In this case, the doc comment doesn't provide extra information in addition to the function name, so not sure it's worth adding.

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 niche clarification, making it clear that it excludes attributes that are repr, not that have repr, but there's no currently extant attribute forms i can think of where the latter interpretation would make sense, so it should be fine either way.

@@ -2351,6 +2371,16 @@ pub(crate) enum TypeAliasInnerType {
Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
}

impl TypeAliasInnerType {
fn has_stripped_entries(&self) -> Option<bool> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't this make more sense as has_stripped_variants? Am I missing something?

Ofc if we're doing that we should rename the other has_stripped_entries for consistency, I think that seems pretty in line with all the other refactoring going on here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe I'm the one who missed something. 😆

A type alias can be an alias of an enum, a union or a struct. Of these three, 2 have fields and one has variants. So in this case, neither "fields" nor "variants" can be used.

Copy link
Contributor

Choose a reason for hiding this comment

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

ah, you're right. really it's the other has_stripped_entries that look odd, since in those cases we do actually know if its a field or variant. i guess it makes sense to keep the names the same, and i suppose the function body is simple enough it doesn't need a doc comment.

Comment on lines 2378 to 2379
Self::Union { fields } => fields.iter().any(|f| f.is_stripped()),
Self::Struct { fields, .. } => fields.iter().any(|f| f.is_stripped()),
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
Self::Union { fields } => fields.iter().any(|f| f.is_stripped()),
Self::Struct { fields, .. } => fields.iter().any(|f| f.is_stripped()),
Self::Union { fields } |
Self::Struct { fields, .. } => fields.iter().any(|f| f.is_stripped()),

unfortunately variants is a different type, but we can at least unify these two branches.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch!

Comment on lines 1576 to 1584
let def_id = it.item_id.expect_def_id();
let layout_def_id = if !is_type_alias {
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?;
def_id
} else {
self.def_id
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: def_id could be raised into the scope of the if or inlined entirely, which would save a few branches and maybe be easier to read.

the ternary with side effect pattern is a bit difficult to read, especially with the negated condition, perhaps a brief comment explaining things would help (in particular, why are we using a different DefId in the type alias case).

Copy link
Member Author

Choose a reason for hiding this comment

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

Gonna add a comment but for posterity: since we have extra generics information, the size of the type layout might change.

Comment on lines 1532 to 1539
struct DisplayEnum<'a> {
variants: &'a IndexVec<VariantIdx, clean::Item>,
generics: &'a clean::Generics,
is_non_exhaustive: bool,
def_id: DefId,
}

impl<'a> DisplayEnum<'a> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: could we use a more descriptive lifetime name, such as 'clean, since this lifetime seems to be bound to that of the cleaned ast ?

variants: &e.variants,
generics: &e.generics,
is_non_exhaustive: it.is_non_exhaustive(),
def_id: it.def_id().unwrap(),
Copy link
Contributor

Choose a reason for hiding this comment

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

earlier you replaced it.def_id().unwrap() with e.def_id (or self.def_id), is there a reason you're not doing that again here?

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's the original code behaviour. Keeping it as is, although it's curious indeed.

}
fn render_attributes_in_pre(&self) -> impl fmt::Display {
fmt::from_fn(move |f| {
if !self.is_type_alias {
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 a reason for all the inverted if conditions? if you're trying to do branch predictor hints based on what the "primary" branch is, I don't believe that's a thing in rust, and indeed with opt-level=3 I got identical asm no matter which way it was written.

https://rust.godbolt.org/z/Y99Kb15sb

Copy link
Member Author

Choose a reason for hiding this comment

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

No, it's often because of how I originally wrote the code (ie no else yet) and I didn't update afterward. Gonna switch both branches.

if !is_type_alias {
render_attributes_in_code(w, it, cx);
} else {
// For now we only render `repr` attributes for type aliases.
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
// For now we only render `repr` attributes for type aliases.
// For now the only attributes we render for type aliases are `repr` attributes.

same nit again

@GuillaumeGomez GuillaumeGomez force-pushed the cleanup-tyalias-render branch from cb63d99 to 509bff1 Compare May 21, 2025 20:59
@GuillaumeGomez
Copy link
Member Author

Applied suggestions!

@bors
Copy link
Collaborator

bors commented May 23, 2025

☔ The latest upstream changes (presumably #141437) 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
A-rustdoc-json Area: Rustdoc JSON backend 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: type alias does not show the repr of the aliased type
5 participants