rustdoc: render gen params & where-clauses of cross-crate assoc tys in impl blocks
This commit is contained in:
parent
e0ba2d038d
commit
c643bedf7c
@ -1360,21 +1360,53 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
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.
|
||||
// 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| ¶m.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| ¶m.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 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
|
||||
}
|
||||
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| ¶m.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| ¶m.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 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
|
||||
None,
|
||||
),
|
||||
generics,
|
||||
// FIXME: should we obtain the Type from HIR and pass it on here?
|
||||
item_type: None,
|
||||
}),
|
||||
bounds,
|
||||
@ -1478,7 +1482,6 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
|
||||
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 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
|
||||
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(),
|
||||
)
|
||||
}
|
||||
|
@ -42,3 +42,15 @@
|
||||
// @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;
|
||||
|
@ -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>>;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user