about summary refs log tree commit diff
path: root/src/librustdoc
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-10-03 19:12:17 +0200
committerGitHub <noreply@github.com>2022-10-03 19:12:17 +0200
commit2e7e17a84abea8f4c3e2d95ce432ef784af06bef (patch)
tree6ed48fc9816df9eee3bde078a2526d6100bb9365 /src/librustdoc
parent33d351972ad9c43bc30e87edd2765de9a4898629 (diff)
parenta5402343f60271c7e428bb6e6aac704bd88bb2bf (diff)
Rollup merge of #102439 - fmease:rustdoc-simplify-cross-crate-trait-bounds, r=GuillaumeGomez
rustdoc: re-sugar more cross-crate trait bounds

Previously, we would only ever re-sugar cross-crate predicates like `Type: Trait, <Type as Trait>::Name == Rhs` to `Type: Trait<Name = Rhs>` if the `Type` was a generic parameter like `Self` or `T`. With this PR, `Type` can be any type.

Most notably, this means that we now re-sugar predicates involving associated types (where `Type` is of the form `Self::Name`) which are then picked up by the pre-existing logic that re-sugars them into bounds. As a result of that, the associated type `IntoIter` of `std`'s `IntoIterator` trait (re-exported from `core`) is no longer rendered as:

```rust
type IntoIter: Iterator
where
    <Self::IntoIter as Iterator>::Item == Self::Item;
```

but as one would expect: `type IntoIter: Iterator<Item = Self::Item>;`.

Cross-crate closure bounds like `F: Fn(i32) -> bool` are now also rendered properly (previously, the return type (`Self::Output`) would not be rendered and we would show the underlying equality predicate).

Fixes #77763.
Fixes #84579.
Fixes #102142.

`@rustbot` label T-rustdoc A-cross-crate-reexports
r? rustdoc
Diffstat (limited to 'src/librustdoc')
-rw-r--r--src/librustdoc/clean/mod.rs9
-rw-r--r--src/librustdoc/clean/simplify.rs39
2 files changed, 25 insertions, 23 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 704292c1048..c61175ecebf 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1176,6 +1176,15 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
             }
 
             if let ty::TraitContainer = assoc_item.container {
+                // 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.
                 let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
                 let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
                 let mut generics =
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index af7813a7740..f82ea8969ab 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -14,7 +14,6 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty;
-use rustc_span::Symbol;
 
 use crate::clean;
 use crate::clean::GenericArgs as PP;
@@ -26,21 +25,17 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
     //
     // We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to
     // the order of the generated bounds.
-    let mut params: FxIndexMap<Symbol, (Vec<_>, Vec<_>)> = FxIndexMap::default();
+    let mut tybounds = FxIndexMap::default();
     let mut lifetimes = Vec::new();
     let mut equalities = Vec::new();
-    let mut tybounds = Vec::new();
 
     for clause in clauses {
         match clause {
-            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))),
-            },
+            WP::BoundPredicate { ty, bounds, bound_params } => {
+                let (b, p): &mut (Vec<_>, Vec<_>) = tybounds.entry(ty).or_default();
+                b.extend(bounds);
+                p.extend(bound_params);
+            }
             WP::RegionPredicate { lifetime, bounds } => {
                 lifetimes.push((lifetime, bounds));
             }
@@ -49,14 +44,17 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
     }
 
     // Look for equality predicates on associated types that can be merged into
-    // general bound predicates
+    // general bound predicates.
     equalities.retain(|&(ref lhs, ref rhs)| {
-        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 };
-
+        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 };
         merge_bounds(cx, bounds, trait_did, name, rhs)
     });
 
@@ -65,11 +63,6 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
     clauses.extend(
         lifetimes.into_iter().map(|(lt, bounds)| WP::RegionPredicate { lifetime: lt, bounds }),
     );
-    clauses.extend(params.into_iter().map(|(k, (bounds, params))| WP::BoundPredicate {
-        ty: clean::Generic(k),
-        bounds,
-        bound_params: params,
-    }));
     clauses.extend(tybounds.into_iter().map(|(ty, (bounds, bound_params))| WP::BoundPredicate {
         ty,
         bounds,