Change:
The documentation for is inconsistent in how it shows the constraints. The actual trait declaration looks like this: The matches this declaration as of 1.49.0-nightly ( 2020-10-08). This is good. However, the shows no constraints at all: The is even weirder, using an equality constraint that's not supported (), and this goes all the way back to . <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
This is the relevant code for traits: This is the relevant code for trait bounds: After that it goes into and I'm not sure where it goes.
Well. I think I found the issue.
Hmm, changing that didn't help - it's always , at least when documenting .
The bounds passed to  are incorrect across crates. Here they are for the original crate: and for the re-export: In particular note that is completely empty.
This looks like the culprit: is the bindings.
This needs larger refactors to rustdoc than I'm comfortable making. is , but the only way to construct those is through which works on the hir, not s, and the HIR is not preserved across crates. Maybe is interested in refactoring this? ;)
Update: The current nightly output is still incorrect: I am already working on a fix and I have already assigned myself to the duplicates of this issue ( and ). claim
Awesome, thanks!

Discussion:
} if let ty::TraitContainer = assoc_item.container { <ins> // FIXME(fmease): `tcx.explicit_item_bounds` does not contain the bounds of GATs, //                e.g. the bounds `Copy`, `Display` & (implicitly) `Sized` in //                `type Assoc<T: Copy> where T: Display`. This also means that we //                later incorrectly render `where T: ?Sized`. // //                The result of `tcx.explicit_predicates_of` *does* contain them but //                it does not contain the other bounds / predicates we need. //                Either merge those two interned lists somehow or refactor //                `clean_ty_generics` to call `explicit_item_bounds` by itself. </ins> let bounds = tcx.explicit_item_bounds(assoc_item.def_id); let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; let mut generics =

use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_middle::ty; <del> use rustc_span::Symbol; </del> use crate::clean; use crate::clean::GenericArgs as PP;

// // We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to // the order of the generated bounds. <del> let mut params: FxIndexMap<Symbol, (Vec<_>, Vec<_>)> = FxIndexMap::default(); </del> <ins> let mut tybounds = FxIndexMap::default(); </ins> let mut lifetimes = Vec::new(); let mut equalities = Vec::new(); <del> let mut tybounds = Vec::new(); </del> for clause in clauses { match clause { <del> WP::BoundPredicate { ty, bounds, bound_params } => match ty { clean::Generic(s) => { let (b, p) = params.entry(s).or_default(); b.extend(bounds); p.extend(bound_params); } t => tybounds.push((t, (bounds, bound_params))), }, </del> <ins> WP::BoundPredicate { ty, bounds, bound_params } => { let (b, p): &mut (Vec<_>, Vec<_>) = tybounds.entry(ty).or_default(); b.extend(bounds); p.extend(bound_params); } </ins> WP::RegionPredicate { lifetime, bounds } => { lifetimes.push((lifetime, bounds)); }

} // Look for equality predicates on associated types that can be merged into <del> // general bound predicates </del> <ins> // general bound predicates. </ins> equalities.retain(|&(ref lhs, ref rhs)| { <del> let Some((self_, trait_did, name)) = lhs.projection() else { return true; }; let clean::Generic(generic) = self_ else { return true }; let Some((bounds, _)) = params.get_mut(generic) else { return true }; </del> <ins> let Some((ty, trait_did, name)) = lhs.projection() else { return true; }; // FIXME(fmease): We don't handle HRTBs correctly here. //                Pass `_bound_params` (higher-rank lifetimes) to a modified version of //                `merge_bounds`. That vector is currently always empty though since we //                don't keep track of late-bound lifetimes when cleaning projection //                predicates to cleaned equality predicates while we should first query //                them with `collect_referenced_late_bound_regions` and then store them //                (or something similar). For prior art, see `clean::auto_trait`. let Some((bounds, _bound_params)) = tybounds.get_mut(ty) else { return true }; </ins> merge_bounds(cx, bounds, trait_did, name, rhs) });

clauses.extend( lifetimes.into_iter().map(|(lt, bounds)| WP::RegionPredicate { lifetime: lt, bounds }), ); <del> clauses.extend(params.into_iter().map(|(k, (bounds, params))| WP::BoundPredicate { ty: clean::Generic(k), bounds, bound_params: params, })); </del> clauses.extend(tybounds.into_iter().map(|(ty, (bounds, bound_params))| WP::BoundPredicate { ty, bounds,

<ins> <h4 class="code-header">type <a href="#associatedtype.Out0" class="associatedtype">Out0</a>: <a class="trait" href="../assoc_item_trait_bounds_with_bindings/trait.Support.html" title="trait assoc_item_trait_bounds_with_bindings::Support">Support</a>&lt;Item = <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>&gt;</h4> </ins>  No newline at end of file

<ins> <h4 class="code-header">type <a href="#associatedtype.Out9" class="associatedtype">Out9</a>: <a class="trait" href="{{channel}}/core/ops/function/trait.FnMut.html" title="trait core::ops::function::FnMut">FnMut</a>(<a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a>) -&gt; <a class="primitive" href="{{channel}}/std/primitive.bool.html">bool</a> + <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a></h4> </ins>  No newline at end of file

<ins> // Regression test for issues #77763, #84579 and #102142. #![crate_name = "main"] // aux-build:assoc_item_trait_bounds_with_bindings.rs // build-aux-docs // ignore-cross-compile extern crate assoc_item_trait_bounds_with_bindings as aux; // FIXME(fmease): Don't render an incorrect `T: ?Sized` where-clause for parameters //                of GATs like `Main::Out{2,4}`. Add a snapshot test once it's fixed. // FIXME(fmease): Print the `for<>` parameter list in the bounds of //                `Main::Out{6,11,12}`. // @has main/trait.Main.html // @has - '//*[@id="associatedtype.Out0"]' 'type Out0: Support<Item = ()>' // @has - '//*[@id="associatedtype.Out1"]' 'type Out1: Support<Item = Self::Item>' // @has - '//*[@id="associatedtype.Out2"]' 'type Out2<T>: Support<Item = T>' // @has - '//*[@id="associatedtype.Out3"]' 'type Out3: Support<Produce<()> = bool>' // @has - '//*[@id="associatedtype.Out4"]' 'type Out4<T>: Support<Produce<T> = T>' // @has - '//*[@id="associatedtype.Out5"]' "type Out5: Support<Output<'static> = &'static ()>" // @has - '//*[@id="associatedtype.Out6"]' "type Out6: Support<Output<'a> = &'a ()>" // @has - '//*[@id="associatedtype.Out7"]' "type Out7: Support<Item = String, Produce<i32> = u32> + Unrelated" // @has - '//*[@id="associatedtype.Out8"]' "type Out8: Unrelated + Protocol<i16, Q1 = u128, Q0 = ()>" // @has - '//*[@id="associatedtype.Out9"]' "type Out9: FnMut(i32) -> bool + Clone" // @has - '//*[@id="associatedtype.Out10"]' "type Out10<'q>: Support<Output<'q> = ()>" // @has - '//*[@id="associatedtype.Out11"]' "type Out11: Helper<A<'s> = &'s (), B<'r> = ()>" // @has - '//*[@id="associatedtype.Out12"]' "type Out12: Helper<B<'w> = Cow<'w, str>, A<'w> = bool>" // // Snapshots: Check that we do not render any where-clauses for those associated types since all of // the trait bounds contained within were moved to the bounds of the respective item. // // @snapshot out0 - '//*[@id="associatedtype.Out0"]/*[@class="code-header"]' // @snapshot out9 - '//*[@id="associatedtype.Out9"]/*[@class="code-header"]' // // @has - '//*[@id="tymethod.make"]'  // "fn make<F>(F, impl FnMut(&str) -> bool) // where  //     F: FnOnce(u32) -> String,  //     Self::Out2<()>: Protocol<u8, Q0 = Self::Item, Q1 = ()>" pub use aux::Main; </ins>

<ins> pub trait Main { type Item; type Out0: Support<Item = ()>; type Out1: Support<Item = Self::Item>; type Out2<T>: Support<Item = T>; type Out3: Support<Produce<()> = bool>; type Out4<T>: Support<Produce<T> = T>; type Out5: Support<Output<'static> = &'static ()>; type Out6: for<'a> Support<Output<'a> = &'a ()>; type Out7: Support<Item = String, Produce<i32> = u32> + Unrelated; type Out8: Unrelated + Protocol<i16, Q1 = u128, Q0 = ()>; type Out9: FnMut(i32) -> bool + Clone; type Out10<'q>: Support<Output<'q> = ()>; type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>; type Out12: for<'w> Helper<B<'w> = std::borrow::Cow<'w, str>, A<'w> = bool>; fn make<F>(_: F, _: impl FnMut(&str) -> bool) where F: FnOnce(u32) -> String, Self::Out2<()>: Protocol<u8, Q0 = Self::Item, Q1 = ()>; } pub trait Support { type Item; type Output<'a>; type Produce<T>; } pub trait Protocol<K> { type Q0; type Q1; } pub trait Unrelated {} pub trait Helper { type A<'q>; type B<'q>; } </ins>