Skip to content

Commit

Permalink
Auto merge of #84814 - Stupremee:properly-render-hrtbs, r=GuillaumeGomez
Browse files Browse the repository at this point in the history
Properly render HRTBs

```rust
pub fn test<T>()
where
    for<'a> &'a T: Iterator,
{}
```

This will now render properly including the `for<'a>`
![image](https://user-images.githubusercontent.com/39732259/116808426-fe6ce600-ab38-11eb-9452-f33f554fbb8e.png)

I do not know if this covers all cases, it only covers everything that I could think of that includes `for` and lifetimes in where bounds.
Also someone need to mentor me on how to add a proper rustdoc test for this.

Resolves #78482
  • Loading branch information
bors committed Jun 26, 2021
2 parents 4819719 + 4ea2748 commit 831ae3c
Show file tree
Hide file tree
Showing 12 changed files with 233 additions and 118 deletions.
18 changes: 7 additions & 11 deletions src/librustdoc/clean/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,12 +353,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
let (poly_trait, output) =
(data.0.as_ref().expect("as_ref failed").clone(), data.1.as_ref().cloned());
let new_ty = match poly_trait.trait_ {
Type::ResolvedPath {
ref path,
ref param_names,
ref did,
ref is_generic,
} => {
Type::ResolvedPath { ref path, ref did, ref is_generic } => {
let mut new_path = path.clone();
let last_segment =
new_path.segments.pop().expect("segments were empty");
Expand Down Expand Up @@ -395,7 +390,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {

Type::ResolvedPath {
path: new_path,
param_names: param_names.clone(),
did: *did,
is_generic: *is_generic,
}
Expand All @@ -414,7 +408,11 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
let mut bounds_vec = bounds.into_iter().collect();
self.sort_where_bounds(&mut bounds_vec);

Some(WherePredicate::BoundPredicate { ty, bounds: bounds_vec })
Some(WherePredicate::BoundPredicate {
ty,
bounds: bounds_vec,
bound_params: Vec::new(),
})
})
.chain(
lifetime_to_bounds.into_iter().filter(|&(_, ref bounds)| !bounds.is_empty()).map(
Expand Down Expand Up @@ -492,7 +490,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
}
let p = p.unwrap();
match p {
WherePredicate::BoundPredicate { ty, mut bounds } => {
WherePredicate::BoundPredicate { ty, mut bounds, .. } => {
// Writing a projection trait bound of the form
// <T as Trait>::Name : ?Sized
// is illegal, because ?Sized bounds can only
Expand Down Expand Up @@ -566,7 +564,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
match **trait_ {
Type::ResolvedPath {
path: ref trait_path,
ref param_names,
ref did,
ref is_generic,
} => {
Expand Down Expand Up @@ -613,7 +610,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
PolyTrait {
trait_: Type::ResolvedPath {
path: new_trait_path,
param_names: param_names.clone(),
did: *did,
is_generic: *is_generic,
},
Expand Down
11 changes: 7 additions & 4 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,9 +583,11 @@ fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::Item
fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
for pred in &mut g.where_predicates {
match *pred {
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref mut bounds }
if *s == kw::SelfUpper =>
{
clean::WherePredicate::BoundPredicate {
ty: clean::Generic(ref s),
ref mut bounds,
..
} if *s == kw::SelfUpper => {
bounds.retain(|bound| match *bound {
clean::GenericBound::TraitBound(
clean::PolyTrait { trait_: clean::ResolvedPath { did, .. }, .. },
Expand All @@ -608,6 +610,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
..
},
ref bounds,
..
} => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did),
_ => true,
});
Expand All @@ -622,7 +625,7 @@ fn separate_supertrait_bounds(
) -> (clean::Generics, Vec<clean::GenericBound>) {
let mut ty_bounds = Vec::new();
g.where_predicates.retain(|pred| match *pred {
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds }
clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. }
if *s == kw::SelfUpper =>
{
ty_bounds.extend(bounds.iter().cloned());
Expand Down
84 changes: 35 additions & 49 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {

debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);

ResolvedPath { path, param_names: None, did: trait_ref.def_id, is_generic: false }
ResolvedPath { path, did: trait_ref.def_id, is_generic: false }
}
}

Expand Down Expand Up @@ -330,6 +330,7 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
hir::WherePredicate::BoundPredicate(ref wbp) => WherePredicate::BoundPredicate {
ty: wbp.bounded_ty.clean(cx),
bounds: wbp.bounds.clean(cx),
bound_params: wbp.bound_generic_params.into_iter().map(|x| x.clean(cx)).collect(),
},

hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
Expand Down Expand Up @@ -370,6 +371,7 @@ impl<'a> Clean<WherePredicate> for ty::PolyTraitPredicate<'a> {
WherePredicate::BoundPredicate {
ty: poly_trait_ref.skip_binder().self_ty().clean(cx),
bounds: vec![poly_trait_ref.clean(cx)],
bound_params: Vec::new(),
}
}
}
Expand Down Expand Up @@ -402,6 +404,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
Some(WherePredicate::BoundPredicate {
ty: ty.clean(cx),
bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
bound_params: Vec::new(),
})
}
}
Expand Down Expand Up @@ -567,7 +570,9 @@ impl Clean<Generics> for hir::Generics<'_> {
// to where predicates when such cases occur.
for where_pred in &mut generics.where_predicates {
match *where_pred {
WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
WherePredicate::BoundPredicate {
ty: Generic(ref name), ref mut bounds, ..
} => {
if bounds.is_empty() {
for param in &mut generics.params {
match param.kind {
Expand Down Expand Up @@ -721,7 +726,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
// handled in cleaning associated types
let mut sized_params = FxHashSet::default();
where_predicates.retain(|pred| match *pred {
WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
WP::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
if bounds.iter().any(|b| b.is_sized_bound(cx)) {
sized_params.insert(*g);
false
Expand All @@ -741,6 +746,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
where_predicates.push(WP::BoundPredicate {
ty: Type::Generic(tp.name),
bounds: vec![GenericBound::maybe_sized(cx)],
bound_params: Vec::new(),
})
}
}
Expand Down Expand Up @@ -1117,6 +1123,7 @@ impl Clean<Item> for ty::AssocItem {
WherePredicate::BoundPredicate {
ty: QPath { ref name, ref self_type, ref trait_, .. },
ref bounds,
..
} => (name, self_type, trait_, bounds),
_ => return None,
};
Expand Down Expand Up @@ -1371,24 +1378,9 @@ impl Clean<Type> for hir::Ty<'_> {
}
TyKind::Path(_) => clean_qpath(&self, cx),
TyKind::TraitObject(ref bounds, ref lifetime, _) => {
match bounds[0].clean(cx).trait_ {
ResolvedPath { path, param_names: None, did, is_generic } => {
let mut bounds: Vec<self::GenericBound> = bounds[1..]
.iter()
.map(|bound| {
self::GenericBound::TraitBound(
bound.clean(cx),
hir::TraitBoundModifier::None,
)
})
.collect();
if !lifetime.is_elided() {
bounds.push(self::GenericBound::Outlives(lifetime.clean(cx)));
}
ResolvedPath { path, param_names: Some(bounds), did, is_generic }
}
_ => Infer, // shouldn't happen
}
let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
DynTrait(bounds, lifetime)
}
TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
TyKind::Infer | TyKind::Err => Infer,
Expand Down Expand Up @@ -1471,7 +1463,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
};
inline::record_extern_fqn(cx, did, kind);
let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs);
ResolvedPath { path, param_names: None, did, is_generic: false }
ResolvedPath { path, did, is_generic: false }
}
ty::Foreign(did) => {
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
Expand All @@ -1483,7 +1475,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
vec![],
InternalSubsts::empty(),
);
ResolvedPath { path, param_names: None, did, is_generic: false }
ResolvedPath { path, did, is_generic: false }
}
ty::Dynamic(ref obj, ref reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
Expand All @@ -1501,28 +1493,19 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {

inline::record_extern_fqn(cx, did, ItemType::Trait);

let mut param_names = vec![];
if let Some(b) = reg.clean(cx) {
param_names.push(GenericBound::Outlives(b));
}
let lifetime = reg.clean(cx);
let mut bounds = vec![];

for did in dids {
let empty = cx.tcx.intern_substs(&[]);
let path =
external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
let bound = GenericBound::TraitBound(
PolyTrait {
trait_: ResolvedPath {
path,
param_names: None,
did,
is_generic: false,
},
generic_params: Vec::new(),
},
hir::TraitBoundModifier::None,
);
param_names.push(bound);
let bound = PolyTrait {
trait_: ResolvedPath { path, did, is_generic: false },
generic_params: Vec::new(),
};
bounds.push(bound);
}

let mut bindings = vec![];
Expand All @@ -1535,7 +1518,15 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {

let path =
external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs);
ResolvedPath { path, param_names: Some(param_names), did, is_generic: false }
bounds.insert(
0,
PolyTrait {
trait_: ResolvedPath { path, did, is_generic: false },
generic_params: Vec::new(),
},
);

DynTrait(bounds, lifetime)
}
ty::Tuple(ref t) => {
Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
Expand Down Expand Up @@ -2239,14 +2230,9 @@ impl From<GenericBound> for SimpleBound {
match bound.clone() {
GenericBound::Outlives(l) => SimpleBound::Outlives(l),
GenericBound::TraitBound(t, mod_) => match t.trait_ {
Type::ResolvedPath { path, param_names, .. } => SimpleBound::TraitBound(
path.segments,
param_names.map_or_else(Vec::new, |v| {
v.iter().map(|p| SimpleBound::from(p.clone())).collect()
}),
t.generic_params,
mod_,
),
Type::ResolvedPath { path, .. } => {
SimpleBound::TraitBound(path.segments, Vec::new(), t.generic_params, mod_)
}
_ => panic!("Unexpected bound {:?}", bound),
},
}
Expand Down
28 changes: 19 additions & 9 deletions src/librustdoc/clean/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ use crate::core::DocContext;

crate fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
// First, partition the where clause into its separate components
let mut params: BTreeMap<_, Vec<_>> = BTreeMap::new();
let mut params: BTreeMap<_, (Vec<_>, Vec<_>)> = BTreeMap::new();
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 } => match ty {
clean::Generic(s) => params.entry(s).or_default().extend(bounds),
t => tybounds.push((t, bounds)),
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::RegionPredicate { lifetime, bounds } => {
lifetimes.push((lifetime, bounds));
Expand All @@ -54,7 +58,7 @@ crate fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
clean::Generic(s) => s,
_ => return true,
};
let bounds = match params.get_mut(generic) {
let (bounds, _) = match params.get_mut(generic) {
Some(bound) => bound,
None => return true,
};
Expand All @@ -67,10 +71,16 @@ 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, v)| WP::BoundPredicate { ty: clean::Generic(k), bounds: v }),
);
clauses.extend(tybounds.into_iter().map(|(ty, bounds)| WP::BoundPredicate { ty, 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,
bound_params,
}));
clauses.extend(equalities.into_iter().map(|(lhs, rhs)| WP::EqPredicate { lhs, rhs }));
clauses
}
Expand Down
8 changes: 5 additions & 3 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1168,7 +1168,7 @@ impl GenericBound {
inline::record_extern_fqn(cx, did, ItemType::Trait);
GenericBound::TraitBound(
PolyTrait {
trait_: ResolvedPath { path, param_names: None, did, is_generic: false },
trait_: ResolvedPath { path, did, is_generic: false },
generic_params: Vec::new(),
},
hir::TraitBoundModifier::Maybe,
Expand Down Expand Up @@ -1220,7 +1220,7 @@ impl Lifetime {

#[derive(Clone, Debug)]
crate enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
EqPredicate { lhs: Type, rhs: Type },
}
Expand Down Expand Up @@ -1434,11 +1434,12 @@ crate enum Type {
/// Structs/enums/traits (most that would be an `hir::TyKind::Path`).
ResolvedPath {
path: Path,
param_names: Option<Vec<GenericBound>>,
did: DefId,
/// `true` if is a `T::Name` path for associated types.
is_generic: bool,
},
/// `dyn for<'a> Trait<'a> + Send + 'static`
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
/// For parameterized types, so the consumer of the JSON don't go
/// looking for types which don't exist anywhere.
Generic(Symbol),
Expand Down Expand Up @@ -1625,6 +1626,7 @@ impl Type {
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self {
ResolvedPath { did, .. } => return Some(did.into()),
DynTrait(ref bounds, _) => return bounds[0].trait_.inner_def_id(cache),
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
Expand Down
Loading

0 comments on commit 831ae3c

Please sign in to comment.