rustdoc: Render for<'_> lifetimes in front of where bound

This commit is contained in:
Justus K 2021-05-02 14:48:28 +02:00
parent 312b894cc1
commit e0162a8a56
No known key found for this signature in database
GPG Key ID: 8C62FE98A62FC462
8 changed files with 104 additions and 22 deletions

View File

@ -414,7 +414,11 @@ fn make_final_bounds(
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(
@ -492,7 +496,7 @@ fn param_env_to_generics(
}
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

View File

@ -566,9 +566,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, .. }, .. },
@ -591,6 +593,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,
});
@ -605,7 +608,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());

View File

@ -330,6 +330,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> 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 {
@ -370,6 +371,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
WherePredicate::BoundPredicate {
ty: poly_trait_ref.skip_binder().self_ty().clean(cx),
bounds: vec![poly_trait_ref.clean(cx)],
bound_params: Vec::new(),
}
}
}
@ -402,6 +404,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
Some(WherePredicate::BoundPredicate {
ty: ty.clean(cx),
bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
bound_params: Vec::new(),
})
}
}
@ -567,7 +570,9 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
// 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 {
@ -721,7 +726,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
// 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
@ -741,6 +746,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
where_predicates.push(WP::BoundPredicate {
ty: Type::Generic(tp.name),
bounds: vec![GenericBound::maybe_sized(cx)],
bound_params: Vec::new(),
})
}
}
@ -1117,6 +1123,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
WherePredicate::BoundPredicate {
ty: QPath { ref name, ref self_type, ref trait_, .. },
ref bounds,
..
} => (name, self_type, trait_, bounds),
_ => return None,
};

View File

@ -24,16 +24,20 @@
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));
@ -54,7 +58,7 @@
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,
};
@ -67,10 +71,16 @@
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
}

View File

@ -1193,7 +1193,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 },
}

View File

@ -249,17 +249,33 @@ impl clean::Generics {
}
match pred {
clean::WherePredicate::BoundPredicate { ty, bounds } => {
clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
let bounds = bounds;
let for_prefix = match bound_params.len() {
0 => String::new(),
_ if f.alternate() => {
format!(
"for<{:#}> ",
comma_sep(bound_params.iter().map(|lt| lt.print()))
)
}
_ => format!(
"for&lt;{}&gt; ",
comma_sep(bound_params.iter().map(|lt| lt.print()))
),
};
if f.alternate() {
clause.push_str(&format!(
"{:#}: {:#}",
"{}{:#}: {:#}",
for_prefix,
ty.print(cx),
print_generic_bounds(bounds, cx)
));
} else {
clause.push_str(&format!(
"{}: {}",
"{}{}: {}",
for_prefix,
ty.print(cx),
print_generic_bounds(bounds, cx)
));

View File

@ -328,9 +328,10 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self {
use clean::WherePredicate::*;
match predicate {
BoundPredicate { ty, bounds } => WherePredicate::BoundPredicate {
BoundPredicate { ty, bounds, .. } => WherePredicate::BoundPredicate {
ty: ty.into_tcx(tcx),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
// FIXME: add `bound_params` to rustdoc-json-params?
},
RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
lifetime: lifetime.0.to_string(),

View File

@ -0,0 +1,41 @@
#![crate_name = "foo"]
trait A<'x> {}
// @has foo/fn.test1.html
// @has - '//pre' "pub fn test1<T>() where for<'a> &'a T: Iterator,"
pub fn test1<T>()
where
for<'a> &'a T: Iterator,
{
}
// @has foo/fn.test2.html
// @has - '//pre' "pub fn test2<T>() where for<'a, 'b> &'a T: A<'b>,"
pub fn test2<T>()
where
for<'a, 'b> &'a T: A<'b>,
{
}
// @has foo/fn.test3.html
// @has - '//pre' "pub fn test3<F>() where F: for<'a, 'b> Fn(&'a u8, &'b u8),"
pub fn test3<F>()
where
F: for<'a, 'b> Fn(&'a u8, &'b u8),
{
}
// @has foo/struct.Foo.html
pub struct Foo<'a> {
_x: &'a u8,
}
impl<'a> Foo<'a> {
// @has - '//code' "pub fn bar<T>() where T: A<'a>,"
pub fn bar<T>()
where
T: A<'a>,
{
}
}