Associated type bound for inlined impl Trait doc
This commit is contained in:
parent
b78367d8e8
commit
9beff38382
4 changed files with 131 additions and 68 deletions
|
|
@ -1698,7 +1698,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
|
|||
|
||||
// Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
|
||||
// since `Clean for ty::Predicate` would consume them.
|
||||
let mut impl_trait = FxHashMap::<ImplTraitParam, Vec<_>>::default();
|
||||
let mut impl_trait = FxHashMap::<ImplTraitParam, Vec<GenericBound>>::default();
|
||||
|
||||
// Bounds in the type_params and lifetimes fields are repeated in the
|
||||
// predicates field (see rustc_typeck::collect::ty_generics), so remove
|
||||
|
|
@ -1720,41 +1720,73 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
|
|||
ty::GenericParamDefKind::Const { .. } => None,
|
||||
}).collect::<Vec<GenericParamDef>>();
|
||||
|
||||
// (param index, def id of trait) -> (name, type)
|
||||
let mut impl_trait_proj = FxHashMap::<(u32, DefId), Vec<(String, Type)>>::default();
|
||||
|
||||
let mut where_predicates = preds.predicates.iter()
|
||||
.flat_map(|(p, _)| {
|
||||
let param_idx = if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
|
||||
if let ty::Param(param) = trait_ref.self_ty().sty {
|
||||
Some(param.index)
|
||||
} else {
|
||||
None
|
||||
let param_idx = (|| {
|
||||
if let Some(trait_ref) = p.to_opt_poly_trait_ref() {
|
||||
if let ty::Param(param) = trait_ref.self_ty().sty {
|
||||
return Some(param.index);
|
||||
}
|
||||
} else if let Some(outlives) = p.to_opt_type_outlives() {
|
||||
if let ty::Param(param) = outlives.skip_binder().0.sty {
|
||||
return Some(param.index);
|
||||
}
|
||||
} else if let ty::Predicate::Projection(proj) = p {
|
||||
if let ty::Param(param) = proj.skip_binder().projection_ty.self_ty().sty {
|
||||
return Some(param.index);
|
||||
}
|
||||
}
|
||||
} else if let Some(outlives) = p.to_opt_type_outlives() {
|
||||
if let ty::Param(param) = outlives.skip_binder().0.sty {
|
||||
Some(param.index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
|
||||
None
|
||||
};
|
||||
})();
|
||||
|
||||
let p = p.clean(cx)?;
|
||||
|
||||
if let Some(b) = param_idx.and_then(|i| impl_trait.get_mut(&i.into())) {
|
||||
b.extend(
|
||||
p.get_bounds()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.cloned()
|
||||
.filter(|b| !b.is_sized_bound(cx))
|
||||
);
|
||||
return None;
|
||||
if let Some(param_idx) = param_idx {
|
||||
if let Some(b) = impl_trait.get_mut(¶m_idx.into()) {
|
||||
b.extend(
|
||||
p.get_bounds()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.cloned()
|
||||
.filter(|b| !b.is_sized_bound(cx))
|
||||
);
|
||||
|
||||
let proj = match &p {
|
||||
WherePredicate::EqPredicate { lhs, rhs } => Some((lhs, rhs))
|
||||
.and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(((_, trait_did, name), rhs)) = proj {
|
||||
impl_trait_proj
|
||||
.entry((param_idx, trait_did))
|
||||
.or_default()
|
||||
.push((name.to_string(), rhs.clone()));
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Some(p)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for ((param_idx, trait_did), bounds) in impl_trait_proj {
|
||||
for (name, rhs) in bounds {
|
||||
simplify::merge_bounds(
|
||||
cx,
|
||||
impl_trait.get_mut(¶m_idx.into()).unwrap(),
|
||||
trait_did,
|
||||
&name,
|
||||
&rhs,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Move `TraitPredicate`s to the front.
|
||||
for (_, bounds) in impl_trait.iter_mut() {
|
||||
bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b {
|
||||
|
|
@ -2664,6 +2696,21 @@ impl Type {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn projection(&self) -> Option<(&Type, DefId, &str)> {
|
||||
let (self_, trait_, name) = match self {
|
||||
QPath { ref self_type, ref trait_, ref name } => {
|
||||
(self_type, trait_, name)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let trait_did = match **trait_ {
|
||||
ResolvedPath { did, .. } => did,
|
||||
_ => return None,
|
||||
};
|
||||
Some((&self_, trait_did, name))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl GetDefId for Type {
|
||||
|
|
|
|||
|
|
@ -53,58 +53,21 @@ pub 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
|
||||
equalities.retain(|&(ref lhs, ref rhs)| {
|
||||
let (self_, trait_, name) = match *lhs {
|
||||
clean::QPath { ref self_type, ref trait_, ref name } => {
|
||||
(self_type, trait_, name)
|
||||
}
|
||||
_ => return true,
|
||||
let (self_, trait_did, name) = if let Some(p) = lhs.projection() {
|
||||
p
|
||||
} else {
|
||||
return true;
|
||||
};
|
||||
let generic = match **self_ {
|
||||
clean::Generic(ref s) => s,
|
||||
_ => return true,
|
||||
};
|
||||
let trait_did = match **trait_ {
|
||||
clean::ResolvedPath { did, .. } => did,
|
||||
let generic = match self_ {
|
||||
clean::Generic(s) => s,
|
||||
_ => return true,
|
||||
};
|
||||
let bounds = match params.get_mut(generic) {
|
||||
Some(bound) => bound,
|
||||
None => return true,
|
||||
};
|
||||
!bounds.iter_mut().any(|b| {
|
||||
let trait_ref = match *b {
|
||||
clean::GenericBound::TraitBound(ref mut tr, _) => tr,
|
||||
clean::GenericBound::Outlives(..) => return false,
|
||||
};
|
||||
let (did, path) = match trait_ref.trait_ {
|
||||
clean::ResolvedPath { did, ref mut path, ..} => (did, path),
|
||||
_ => return false,
|
||||
};
|
||||
// If this QPath's trait `trait_did` is the same as, or a supertrait
|
||||
// of, the bound's trait `did` then we can keep going, otherwise
|
||||
// this is just a plain old equality bound.
|
||||
if !trait_is_same_or_supertrait(cx, did, trait_did) {
|
||||
return false
|
||||
}
|
||||
let last = path.segments.last_mut().expect("segments were empty");
|
||||
match last.args {
|
||||
PP::AngleBracketed { ref mut bindings, .. } => {
|
||||
bindings.push(clean::TypeBinding {
|
||||
name: name.clone(),
|
||||
kind: clean::TypeBindingKind::Equality {
|
||||
ty: rhs.clone(),
|
||||
},
|
||||
});
|
||||
}
|
||||
PP::Parenthesized { ref mut output, .. } => {
|
||||
assert!(output.is_none());
|
||||
if *rhs != clean::Type::Tuple(Vec::new()) {
|
||||
*output = Some(rhs.clone());
|
||||
}
|
||||
}
|
||||
};
|
||||
true
|
||||
})
|
||||
|
||||
merge_bounds(cx, bounds, trait_did, name, rhs)
|
||||
});
|
||||
|
||||
// And finally, let's reassemble everything
|
||||
|
|
@ -127,6 +90,49 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
|
|||
clauses
|
||||
}
|
||||
|
||||
pub fn merge_bounds(
|
||||
cx: &clean::DocContext<'_>,
|
||||
bounds: &mut Vec<clean::GenericBound>,
|
||||
trait_did: DefId,
|
||||
name: &str,
|
||||
rhs: &clean::Type,
|
||||
) -> bool {
|
||||
!bounds.iter_mut().any(|b| {
|
||||
let trait_ref = match *b {
|
||||
clean::GenericBound::TraitBound(ref mut tr, _) => tr,
|
||||
clean::GenericBound::Outlives(..) => return false,
|
||||
};
|
||||
let (did, path) = match trait_ref.trait_ {
|
||||
clean::ResolvedPath { did, ref mut path, ..} => (did, path),
|
||||
_ => return false,
|
||||
};
|
||||
// If this QPath's trait `trait_did` is the same as, or a supertrait
|
||||
// of, the bound's trait `did` then we can keep going, otherwise
|
||||
// this is just a plain old equality bound.
|
||||
if !trait_is_same_or_supertrait(cx, did, trait_did) {
|
||||
return false
|
||||
}
|
||||
let last = path.segments.last_mut().expect("segments were empty");
|
||||
match last.args {
|
||||
PP::AngleBracketed { ref mut bindings, .. } => {
|
||||
bindings.push(clean::TypeBinding {
|
||||
name: name.to_string(),
|
||||
kind: clean::TypeBindingKind::Equality {
|
||||
ty: rhs.clone(),
|
||||
},
|
||||
});
|
||||
}
|
||||
PP::Parenthesized { ref mut output, .. } => {
|
||||
assert!(output.is_none());
|
||||
if *rhs != clean::Type::Tuple(Vec::new()) {
|
||||
*output = Some(rhs.clone());
|
||||
}
|
||||
}
|
||||
};
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
pub fn ty_params(mut params: Vec<clean::GenericParamDef>) -> Vec<clean::GenericParamDef> {
|
||||
for param in &mut params {
|
||||
match param.kind {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
pub fn func<'a>(_x: impl Clone + Into<Vec<u8>> + 'a) {}
|
||||
|
||||
pub fn func2<T>(_x: impl Deref<Target = Option<T>> + Iterator<Item = T>, _y: impl Iterator<Item = u8>) {}
|
||||
|
||||
pub struct Foo;
|
||||
|
||||
impl Foo {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@ extern crate impl_trait_aux;
|
|||
// @!has - '//pre[@class="rust fn"]' 'where'
|
||||
pub use impl_trait_aux::func;
|
||||
|
||||
// @has impl_trait/fn.func2.html
|
||||
// @has - '//pre[@class="rust fn"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
|
||||
// @has - '//pre[@class="rust fn"]' "_y: impl Iterator<Item = u8>)"
|
||||
// @!has - '//pre[@class="rust fn"]' 'where'
|
||||
pub use impl_trait_aux::func2;
|
||||
|
||||
// @has impl_trait/struct.Foo.html
|
||||
// @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8>> + 'a)"
|
||||
// @!has - '//code[@id="method.v"]' 'where'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue