Rollup merge of #149274 - GuillaumeGomez:tyalias-method-link, r=lolbinarycat

Fix invalid link generation for type alias methods

Fixes https://github.com/rust-lang/rust/issues/149205.

That one was quite the wild ride. First commit is the actual fix, the second commit is just a small name variable improvement while I was going through the code. Anyway, let's go through it:

 * We don't generate directly implementations in the HTML files for local impls (which I think is a mistake and should be changed, gonna do that as a follow-up) but instead generate a JS file for each type alias containing the HTML for these impls.
 * So in `write_shared.rs::TypeAliasPart::get`, when generating the JS file, we generate the impl into a `String` by calling `render_impl`. This method expects an `AssocItemLink` to help it generate the correct link to the item (I'm planning to also remove this enum because it's yet another way to generate anchors/hrefs).
 * Problem was: we call the `provided_trait_methods` method on the impl item... which is empty if not a trait impl. This becomes an issue when we arrive in `render::assoc_href_attr` because of this code:
     ```rust
            AssocItemLink::GotoSource(did, provided_methods) => {
                let item_type = match item_type {
                    ItemType::Method | ItemType::TyMethod => {
                        if provided_methods.contains(&name) {
                            ItemType::Method
                        } else {
                            ItemType::TyMethod
                        }
                    }
                    item_type => item_type,
                };
                // ...
            }
    ```

     Since `provided_methods` is always empty, it means all methods on type aliases will be `TyMethod`, generating `#tymethod.` URLs instead of `#method.`.
 * So generating `AssocItemLink::GoToSource` only on traits (when `provided_trait_methods` is supposed to return something) was the fix.
 * And finally, because it's (currently) generating implementations only through JS, it means we cannot test it in `tests/rustdoc` so I had to write the test in `tests/rustdoc-gui`. Once I change how we generate local implementations for type aliases, I'll move it to `tests/rustdoc`.

r? ```@lolbinarycat```
This commit is contained in:
Matthias Krüger 2025-11-25 17:51:17 +01:00 committed by GitHub
commit d6966fa15a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 26 additions and 15 deletions

View file

@ -2020,13 +2020,11 @@ fn render_impl(
let mut methods = Vec::new();
if !impl_.is_negative_trait_impl() {
for trait_item in &impl_.items {
match trait_item.kind {
clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
methods.push(trait_item)
}
for impl_item in &impl_.items {
match impl_item.kind {
clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(impl_item),
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
assoc_types.push(trait_item)
assoc_types.push(impl_item)
}
clean::RequiredAssocConstItem(..)
| clean::ProvidedAssocConstItem(_)
@ -2036,7 +2034,7 @@ fn render_impl(
&mut default_impl_items,
&mut impl_items,
cx,
trait_item,
impl_item,
if trait_.is_some() { &i.impl_item } else { parent },
link,
render_mode,

View file

@ -582,18 +582,14 @@ impl TypeAliasPart {
if let Some(ret) = &mut ret {
ret.aliases.push(type_alias_fqp);
} else {
let target_did = impl_
.inner_impl()
.trait_
.as_ref()
.map(|trait_| trait_.def_id())
.or_else(|| impl_.inner_impl().for_.def_id(&cx.shared.cache));
let target_trait_did =
impl_.inner_impl().trait_.as_ref().map(|trait_| trait_.def_id());
let provided_methods;
let assoc_link = if let Some(target_did) = target_did {
let assoc_link = if let Some(target_trait_did) = target_trait_did {
provided_methods =
impl_.inner_impl().provided_trait_methods(cx.tcx());
AssocItemLink::GotoSource(
ItemId::DefId(target_did),
ItemId::DefId(target_trait_did),
&provided_methods,
)
} else {

View file

@ -786,3 +786,13 @@ pub mod tooltips {
Vec::new()
}
}
pub mod tyalias {
pub struct X<T>(pub T);
impl<T: std::fmt::Debug> X<T> {
pub fn blob(&self) {}
}
pub type Y = X<u8>;
}

View file

@ -0,0 +1,7 @@
// This test ensures that we correctly generate links to methods on type aliases.
go-to: "file://" + |DOC_PATH| + "/test_docs/tyalias/type.Y.html"
// It's generated with JS so we need to wait for it to be done generating.
wait-for: "#implementations"
// We check that it's "#method." and not "#tymethod.".
assert-text: ('#method\.blob a.fn[href="#method.blob"]', "blob")