about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2023-06-22 10:42:02 +0200
committerLeón Orell Valerian Liehr <me@fmease.dev>2023-06-24 12:20:26 +0200
commitc643bedf7c90940005da021ba80b6c4e6dcbdaa5 (patch)
treee3df03f501327263456f21edd625e35588f2d699
parente0ba2d038db3afa968e13075b1d6eabd24339708 (diff)
downloadrust-c643bedf7c90940005da021ba80b6c4e6dcbdaa5.tar.gz
rust-c643bedf7c90940005da021ba80b6c4e6dcbdaa5.zip
rustdoc: render gen params & where-clauses of cross-crate assoc tys in impl blocks
-rw-r--r--src/librustdoc/clean/mod.rs88
-rw-r--r--tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs12
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs17
3 files changed, 74 insertions, 43 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f86c32158e0..3dd3a6a8394 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1360,21 +1360,53 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                 }
             }
 
+            let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
             if let ty::TraitContainer = assoc_item.container {
                 let bounds = tcx
                     .explicit_item_bounds(assoc_item.def_id)
                     .subst_identity_iter_copied()
                     .map(|(c, s)| (c.as_predicate(), s));
-                let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
-                let predicates =
-                    tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
-                let mut generics = clean_ty_generics(
-                    cx,
-                    tcx.generics_of(assoc_item.def_id),
-                    ty::GenericPredicates { parent: None, predicates },
-                );
-                // Filter out the bounds that are (likely?) directly attached to the associated type,
-                // as opposed to being located in the where clause.
+                predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
+            }
+            let mut generics = clean_ty_generics(
+                cx,
+                tcx.generics_of(assoc_item.def_id),
+                ty::GenericPredicates { parent: None, predicates },
+            );
+            // Move bounds that are (likely) directly attached to the parameters of the
+            // (generic) associated type from the where clause to the respective parameter.
+            // There is no guarantee that this is what the user actually wrote but we have
+            // no way of knowing.
+            let mut where_predicates = ThinVec::new();
+            for mut pred in generics.where_predicates {
+                if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
+                    && let Some(GenericParamDef {
+                        kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
+                        ..
+                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
+                {
+                    param_bounds.append(bounds);
+                } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
+                    && let Some(GenericParamDef {
+                        kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
+                        ..
+                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
+                {
+                    param_bounds.extend(bounds.drain(..).map(|bound| match bound {
+                        GenericBound::Outlives(lifetime) => lifetime,
+                        _ => unreachable!(),
+                    }));
+                } else {
+                    where_predicates.push(pred);
+                }
+            }
+            generics.where_predicates = where_predicates;
+
+            if let ty::TraitContainer = assoc_item.container {
+                // Move bounds that are (likely) directly attached to the associated type
+                // from the where-clause to the associated type.
+                // There is no guarantee that this is what the user actually wrote but we have
+                // no way of knowing.
                 let mut bounds: Vec<GenericBound> = Vec::new();
                 generics.where_predicates.retain_mut(|pred| match *pred {
                     WherePredicate::BoundPredicate {
@@ -1431,33 +1463,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                     }
                     None => bounds.push(GenericBound::maybe_sized(cx)),
                 }
-                // Move bounds that are (likely) directly attached to the parameters of the
-                // (generic) associated type from the where clause to the respective parameter.
-                // There is no guarantee that this is what the user actually wrote but we have
-                // no way of knowing.
-                let mut where_predicates = ThinVec::new();
-                for mut pred in generics.where_predicates {
-                    if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
-                    && let Some(GenericParamDef {
-                        kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
-                        ..
-                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
-                    {
-                        param_bounds.append(bounds);
-                    } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
-                    && let Some(GenericParamDef {
-                        kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
-                        ..
-                    }) = generics.params.iter_mut().find(|param| &param.name == arg) {
-                        param_bounds.extend(bounds.drain(..).map(|bound| match bound {
-                            GenericBound::Outlives(lifetime) => lifetime,
-                            _ => unreachable!(),
-                        }));
-                    } else {
-                        where_predicates.push(pred);
-                    }
-                }
-                generics.where_predicates = where_predicates;
 
                 if tcx.defaultness(assoc_item.def_id).has_value() {
                     AssocTypeItem(
@@ -1469,7 +1474,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                                 None,
                             ),
                             generics,
-                            // FIXME: should we obtain the Type from HIR and pass it on here?
                             item_type: None,
                         }),
                         bounds,
@@ -1478,7 +1482,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                     TyAssocTypeItem(generics, bounds)
                 }
             } else {
-                // FIXME: when could this happen? Associated items in inherent impls?
                 AssocTypeItem(
                     Box::new(Typedef {
                         type_: clean_middle_ty(
@@ -1487,12 +1490,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                             Some(assoc_item.def_id),
                             None,
                         ),
-                        generics: Generics {
-                            params: ThinVec::new(),
-                            where_predicates: ThinVec::new(),
-                        },
+                        generics,
                         item_type: None,
                     }),
+                    // Associated types inside trait or inherent impls are not allowed to have
+                    // item bounds. Thus we don't attempt to move any bounds there.
                     Vec::new(),
                 )
             }
diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs b/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs
index db2491b87b4..74ceb697af6 100644
--- a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs
+++ b/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs
@@ -42,3 +42,15 @@ pub use aux::Main;
 // @has main/trait.Aid.html
 // @has - '//*[@id="associatedtype.Result"]' "type Result<'inter: 'src>"
 pub use aux::Aid;
+
+// Below, ensure that we correctly display generic parameters and where-clauses on
+// associated types inside trait *impls*. More particularly, check that we don't render
+// any bounds (here `Self::Alias<T>: ...`) as item bounds unlike all the trait test cases above.
+
+// @has main/struct.Implementor.html
+// @has - '//*[@id="associatedtype.Alias"]' \
+// "type Alias<T: Eq> = T \
+// where \
+//     String: From<T>, \
+//     <Implementor as Implementee>::Alias<T>: From<<Implementor as Implementee>::Alias<T>>"
+pub use aux::Implementor;
diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs b/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs
index 6644c8e4147..551e97a2fa9 100644
--- a/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs
@@ -44,3 +44,20 @@ pub trait Helper {
 pub trait Aid<'src> {
     type Result<'inter: 'src>;
 }
+
+pub trait Implementee {
+    type Alias<T: Eq>
+    where
+        String: From<T>;
+}
+
+pub struct Implementor;
+
+impl Implementee for Implementor {
+    type Alias<T: Eq> = T
+    where
+        String: From<T>,
+        // We will check that this bound doesn't get turned into an item bound since
+        // associated types in impls are not allowed to have any.
+        Self::Alias<T>: From<Self::Alias<T>>;
+}