// 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
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
- }
- } 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
+ 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 {
+
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 {
_ => 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 {
// 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 generic = match **self_ {
- clean::Generic(ref s) => s,
- _ => return true,
+ let (self_, trait_did, name) = if let Some(p) = lhs.projection() {
+ p
+ } else {
+ 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
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 {