rustdoc: render more cross-crate hrtbs properly
This commit is contained in:
parent
f1112099eb
commit
73c239e5eb
10 changed files with 124 additions and 41 deletions
|
@ -475,6 +475,12 @@ where
|
||||||
|
|
||||||
let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
|
let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
|
||||||
|
|
||||||
|
// FIXME: This code shares much of the logic found in `clean_ty_generics` and
|
||||||
|
// `simplify::where_clause`. Consider deduplicating it to avoid diverging
|
||||||
|
// implementations.
|
||||||
|
// Further, the code below does not merge (partially re-sugared) bounds like
|
||||||
|
// `Tr<A = T>` & `Tr<B = U>` and it does not render higher-ranked parameters
|
||||||
|
// originating from equality predicates.
|
||||||
for p in clean_where_predicates {
|
for p in clean_where_predicates {
|
||||||
let (orig_p, p) = (p, clean_predicate(p, self.cx));
|
let (orig_p, p) = (p, clean_predicate(p, self.cx));
|
||||||
if p.is_none() {
|
if p.is_none() {
|
||||||
|
@ -549,8 +555,8 @@ where
|
||||||
WherePredicate::RegionPredicate { lifetime, bounds } => {
|
WherePredicate::RegionPredicate { lifetime, bounds } => {
|
||||||
lifetime_to_bounds.entry(lifetime).or_default().extend(bounds);
|
lifetime_to_bounds.entry(lifetime).or_default().extend(bounds);
|
||||||
}
|
}
|
||||||
WherePredicate::EqPredicate { lhs, rhs } => {
|
WherePredicate::EqPredicate { lhs, rhs, bound_params } => {
|
||||||
match lhs {
|
match *lhs {
|
||||||
Type::QPath(box QPathData {
|
Type::QPath(box QPathData {
|
||||||
ref assoc, ref self_type, ref trait_, ..
|
ref assoc, ref self_type, ref trait_, ..
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -585,13 +591,14 @@ where
|
||||||
GenericArgs::AngleBracketed { ref mut bindings, .. } => {
|
GenericArgs::AngleBracketed { ref mut bindings, .. } => {
|
||||||
bindings.push(TypeBinding {
|
bindings.push(TypeBinding {
|
||||||
assoc: assoc.clone(),
|
assoc: assoc.clone(),
|
||||||
kind: TypeBindingKind::Equality { term: rhs },
|
kind: TypeBindingKind::Equality { term: *rhs },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
GenericArgs::Parenthesized { .. } => {
|
GenericArgs::Parenthesized { .. } => {
|
||||||
existing_predicates.push(WherePredicate::EqPredicate {
|
existing_predicates.push(WherePredicate::EqPredicate {
|
||||||
lhs: lhs.clone(),
|
lhs: lhs.clone(),
|
||||||
rhs,
|
rhs,
|
||||||
|
bound_params,
|
||||||
});
|
});
|
||||||
continue; // If something other than a Fn ends up
|
continue; // If something other than a Fn ends up
|
||||||
// with parentheses, leave it alone
|
// with parentheses, leave it alone
|
||||||
|
|
|
@ -292,8 +292,9 @@ fn clean_where_predicate<'tcx>(
|
||||||
},
|
},
|
||||||
|
|
||||||
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
|
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
|
||||||
lhs: clean_ty(wrp.lhs_ty, cx),
|
lhs: Box::new(clean_ty(wrp.lhs_ty, cx)),
|
||||||
rhs: clean_ty(wrp.rhs_ty, cx).into(),
|
rhs: Box::new(clean_ty(wrp.rhs_ty, cx).into()),
|
||||||
|
bound_params: Vec::new(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -309,7 +310,9 @@ pub(crate) fn clean_predicate<'tcx>(
|
||||||
}
|
}
|
||||||
ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
|
ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
|
||||||
ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
|
ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
|
||||||
ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
|
ty::PredicateKind::Projection(pred) => {
|
||||||
|
Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
|
||||||
|
}
|
||||||
ty::PredicateKind::ConstEvaluatable(..) => None,
|
ty::PredicateKind::ConstEvaluatable(..) => None,
|
||||||
ty::PredicateKind::WellFormed(..) => None,
|
ty::PredicateKind::WellFormed(..) => None,
|
||||||
|
|
||||||
|
@ -387,13 +390,25 @@ fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Te
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_projection_predicate<'tcx>(
|
fn clean_projection_predicate<'tcx>(
|
||||||
pred: ty::ProjectionPredicate<'tcx>,
|
pred: ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
|
||||||
cx: &mut DocContext<'tcx>,
|
cx: &mut DocContext<'tcx>,
|
||||||
) -> WherePredicate {
|
) -> WherePredicate {
|
||||||
let ty::ProjectionPredicate { projection_ty, term } = pred;
|
let late_bound_regions = cx
|
||||||
|
.tcx
|
||||||
|
.collect_referenced_late_bound_regions(&pred)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|br| match br {
|
||||||
|
ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(Lifetime(name)),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let ty::ProjectionPredicate { projection_ty, term } = pred.skip_binder();
|
||||||
|
|
||||||
WherePredicate::EqPredicate {
|
WherePredicate::EqPredicate {
|
||||||
lhs: clean_projection(projection_ty, cx, None),
|
lhs: Box::new(clean_projection(projection_ty, cx, None)),
|
||||||
rhs: clean_middle_term(term, cx),
|
rhs: Box::new(clean_middle_term(term, cx)),
|
||||||
|
bound_params: late_bound_regions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,8 +670,9 @@ fn clean_ty_generics<'tcx>(
|
||||||
})
|
})
|
||||||
.collect::<Vec<GenericParamDef>>();
|
.collect::<Vec<GenericParamDef>>();
|
||||||
|
|
||||||
// param index -> [(DefId of trait, associated type name and generics, type)]
|
// param index -> [(trait DefId, associated type name & generics, type, higher-ranked params)]
|
||||||
let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, PathSegment, Ty<'_>)>>::default();
|
let mut impl_trait_proj =
|
||||||
|
FxHashMap::<u32, Vec<(DefId, PathSegment, Ty<'_>, Vec<GenericParamDef>)>>::default();
|
||||||
|
|
||||||
let where_predicates = preds
|
let where_predicates = preds
|
||||||
.predicates
|
.predicates
|
||||||
|
@ -715,6 +731,14 @@ fn clean_ty_generics<'tcx>(
|
||||||
trait_did,
|
trait_did,
|
||||||
name,
|
name,
|
||||||
rhs.ty().unwrap(),
|
rhs.ty().unwrap(),
|
||||||
|
p.get_bound_params()
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.map(|param| GenericParamDef {
|
||||||
|
name: param.0,
|
||||||
|
kind: GenericParamDefKind::Lifetime { outlives: Vec::new() },
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -730,16 +754,20 @@ fn clean_ty_generics<'tcx>(
|
||||||
// Move trait bounds to the front.
|
// Move trait bounds to the front.
|
||||||
bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
|
bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
|
||||||
|
|
||||||
if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
|
let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() };
|
||||||
if let Some(proj) = impl_trait_proj.remove(&idx) {
|
if let Some(proj) = impl_trait_proj.remove(&idx) {
|
||||||
for (trait_did, name, rhs) in proj {
|
for (trait_did, name, rhs, bound_params) in proj {
|
||||||
let rhs = clean_middle_ty(rhs, cx, None);
|
let rhs = clean_middle_ty(rhs, cx, None);
|
||||||
simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
|
simplify::merge_bounds(
|
||||||
|
cx,
|
||||||
|
&mut bounds,
|
||||||
|
bound_params,
|
||||||
|
trait_did,
|
||||||
|
name,
|
||||||
|
&Term::Type(rhs),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.impl_trait_bounds.insert(param, bounds);
|
cx.impl_trait_bounds.insert(param, bounds);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,23 +39,23 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
|
||||||
WP::RegionPredicate { lifetime, bounds } => {
|
WP::RegionPredicate { lifetime, bounds } => {
|
||||||
lifetimes.push((lifetime, bounds));
|
lifetimes.push((lifetime, bounds));
|
||||||
}
|
}
|
||||||
WP::EqPredicate { lhs, rhs } => equalities.push((lhs, rhs)),
|
WP::EqPredicate { lhs, rhs, bound_params } => equalities.push((lhs, rhs, bound_params)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for equality predicates on associated types that can be merged into
|
// Look for equality predicates on associated types that can be merged into
|
||||||
// general bound predicates.
|
// general bound predicates.
|
||||||
equalities.retain(|&(ref lhs, ref rhs)| {
|
equalities.retain(|&(ref lhs, ref rhs, ref bound_params)| {
|
||||||
let Some((ty, trait_did, name)) = lhs.projection() else { return true; };
|
let Some((ty, trait_did, name)) = lhs.projection() else { return true; };
|
||||||
// FIXME(fmease): We don't handle HRTBs correctly here.
|
let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
|
||||||
// Pass `_bound_params` (higher-rank lifetimes) to a modified version of
|
let bound_params = bound_params
|
||||||
// `merge_bounds`. That vector is currently always empty though since we
|
.into_iter()
|
||||||
// don't keep track of late-bound lifetimes when cleaning projection
|
.map(|param| clean::GenericParamDef {
|
||||||
// predicates to cleaned equality predicates while we should first query
|
name: param.0,
|
||||||
// them with `collect_referenced_late_bound_regions` and then store them
|
kind: clean::GenericParamDefKind::Lifetime { outlives: Vec::new() },
|
||||||
// (or something similar). For prior art, see `clean::auto_trait`.
|
})
|
||||||
let Some((bounds, _bound_params)) = tybounds.get_mut(ty) else { return true };
|
.collect();
|
||||||
merge_bounds(cx, bounds, trait_did, name, rhs)
|
merge_bounds(cx, bounds, bound_params, trait_did, name, rhs)
|
||||||
});
|
});
|
||||||
|
|
||||||
// And finally, let's reassemble everything
|
// And finally, let's reassemble everything
|
||||||
|
@ -68,13 +68,18 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
|
||||||
bounds,
|
bounds,
|
||||||
bound_params,
|
bound_params,
|
||||||
}));
|
}));
|
||||||
clauses.extend(equalities.into_iter().map(|(lhs, rhs)| WP::EqPredicate { lhs, rhs }));
|
clauses.extend(equalities.into_iter().map(|(lhs, rhs, bound_params)| WP::EqPredicate {
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
bound_params,
|
||||||
|
}));
|
||||||
clauses
|
clauses
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn merge_bounds(
|
pub(crate) fn merge_bounds(
|
||||||
cx: &clean::DocContext<'_>,
|
cx: &clean::DocContext<'_>,
|
||||||
bounds: &mut Vec<clean::GenericBound>,
|
bounds: &mut Vec<clean::GenericBound>,
|
||||||
|
mut bound_params: Vec<clean::GenericParamDef>,
|
||||||
trait_did: DefId,
|
trait_did: DefId,
|
||||||
assoc: clean::PathSegment,
|
assoc: clean::PathSegment,
|
||||||
rhs: &clean::Term,
|
rhs: &clean::Term,
|
||||||
|
@ -91,6 +96,14 @@ pub(crate) fn merge_bounds(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let last = trait_ref.trait_.segments.last_mut().expect("segments were empty");
|
let last = trait_ref.trait_.segments.last_mut().expect("segments were empty");
|
||||||
|
|
||||||
|
trait_ref.generic_params.append(&mut bound_params);
|
||||||
|
// Since the parameters (probably) originate from `tcx.collect_*_late_bound_regions` which
|
||||||
|
// returns a hash set, sort them alphabetically to guarantee a stable and deterministic
|
||||||
|
// output (and to fully deduplicate them).
|
||||||
|
trait_ref.generic_params.sort_unstable_by(|p, q| p.name.as_str().cmp(q.name.as_str()));
|
||||||
|
trait_ref.generic_params.dedup_by_key(|p| p.name);
|
||||||
|
|
||||||
match last.args {
|
match last.args {
|
||||||
PP::AngleBracketed { ref mut bindings, .. } => {
|
PP::AngleBracketed { ref mut bindings, .. } => {
|
||||||
bindings.push(clean::TypeBinding {
|
bindings.push(clean::TypeBinding {
|
||||||
|
|
|
@ -1350,7 +1350,7 @@ impl Lifetime {
|
||||||
pub(crate) enum WherePredicate {
|
pub(crate) enum WherePredicate {
|
||||||
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
|
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
|
||||||
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
|
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
|
||||||
EqPredicate { lhs: Type, rhs: Term },
|
EqPredicate { lhs: Box<Type>, rhs: Box<Term>, bound_params: Vec<Lifetime> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WherePredicate {
|
impl WherePredicate {
|
||||||
|
@ -1361,6 +1361,15 @@ impl WherePredicate {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_bound_params(&self) -> Option<&[Lifetime]> {
|
||||||
|
match self {
|
||||||
|
Self::BoundPredicate { bound_params, .. } | Self::EqPredicate { bound_params, .. } => {
|
||||||
|
Some(bound_params)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
|
|
|
@ -331,7 +331,8 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
|
||||||
bounds_display.truncate(bounds_display.len() - " + ".len());
|
bounds_display.truncate(bounds_display.len() - " + ".len());
|
||||||
write!(f, "{}: {bounds_display}", lifetime.print())
|
write!(f, "{}: {bounds_display}", lifetime.print())
|
||||||
}
|
}
|
||||||
clean::WherePredicate::EqPredicate { lhs, rhs } => {
|
// FIXME(fmease): Render bound params.
|
||||||
|
clean::WherePredicate::EqPredicate { lhs, rhs, bound_params: _ } => {
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
|
write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -432,8 +432,9 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
|
||||||
lifetime: convert_lifetime(lifetime),
|
lifetime: convert_lifetime(lifetime),
|
||||||
bounds: bounds.into_tcx(tcx),
|
bounds: bounds.into_tcx(tcx),
|
||||||
},
|
},
|
||||||
EqPredicate { lhs, rhs } => {
|
// FIXME(fmease): Convert bound parameters as well.
|
||||||
WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
|
EqPredicate { lhs, rhs, bound_params: _ } => {
|
||||||
|
WherePredicate::EqPredicate { lhs: (*lhs).into_tcx(tcx), rhs: (*rhs).into_tcx(tcx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ extern crate assoc_item_trait_bounds_with_bindings as aux;
|
||||||
|
|
||||||
// FIXME(fmease): Don't render an incorrect `T: ?Sized` where-clause for parameters
|
// FIXME(fmease): Don't render an incorrect `T: ?Sized` where-clause for parameters
|
||||||
// of GATs like `Main::Out{2,4}`. Add a snapshot test once it's fixed.
|
// of GATs like `Main::Out{2,4}`. Add a snapshot test once it's fixed.
|
||||||
// FIXME(fmease): Print the `for<>` parameter list in the bounds of
|
|
||||||
// `Main::Out{6,11,12}`.
|
|
||||||
|
|
||||||
// @has main/trait.Main.html
|
// @has main/trait.Main.html
|
||||||
// @has - '//*[@id="associatedtype.Out0"]' 'type Out0: Support<Item = ()>'
|
// @has - '//*[@id="associatedtype.Out0"]' 'type Out0: Support<Item = ()>'
|
||||||
|
@ -18,13 +16,14 @@ extern crate assoc_item_trait_bounds_with_bindings as aux;
|
||||||
// @has - '//*[@id="associatedtype.Out3"]' 'type Out3: Support<Produce<()> = bool>'
|
// @has - '//*[@id="associatedtype.Out3"]' 'type Out3: Support<Produce<()> = bool>'
|
||||||
// @has - '//*[@id="associatedtype.Out4"]' 'type Out4<T>: Support<Produce<T> = T>'
|
// @has - '//*[@id="associatedtype.Out4"]' 'type Out4<T>: Support<Produce<T> = T>'
|
||||||
// @has - '//*[@id="associatedtype.Out5"]' "type Out5: Support<Output<'static> = &'static ()>"
|
// @has - '//*[@id="associatedtype.Out5"]' "type Out5: Support<Output<'static> = &'static ()>"
|
||||||
// @has - '//*[@id="associatedtype.Out6"]' "type Out6: Support<Output<'a> = &'a ()>"
|
// @has - '//*[@id="associatedtype.Out6"]' "type Out6: for<'a> Support<Output<'a> = &'a ()>"
|
||||||
// @has - '//*[@id="associatedtype.Out7"]' "type Out7: Support<Item = String, Produce<i32> = u32> + Unrelated"
|
// @has - '//*[@id="associatedtype.Out7"]' "type Out7: Support<Item = String, Produce<i32> = u32> + Unrelated"
|
||||||
// @has - '//*[@id="associatedtype.Out8"]' "type Out8: Unrelated + Protocol<i16, Q1 = u128, Q0 = ()>"
|
// @has - '//*[@id="associatedtype.Out8"]' "type Out8: Unrelated + Protocol<i16, Q1 = u128, Q0 = ()>"
|
||||||
// @has - '//*[@id="associatedtype.Out9"]' "type Out9: FnMut(i32) -> bool + Clone"
|
// @has - '//*[@id="associatedtype.Out9"]' "type Out9: FnMut(i32) -> bool + Clone"
|
||||||
// @has - '//*[@id="associatedtype.Out10"]' "type Out10<'q>: Support<Output<'q> = ()>"
|
// @has - '//*[@id="associatedtype.Out10"]' "type Out10<'q>: Support<Output<'q> = ()>"
|
||||||
// @has - '//*[@id="associatedtype.Out11"]' "type Out11: Helper<A<'s> = &'s (), B<'r> = ()>"
|
// @has - '//*[@id="associatedtype.Out11"]' "type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>"
|
||||||
// @has - '//*[@id="associatedtype.Out12"]' "type Out12: Helper<B<'w> = Cow<'w, str>, A<'w> = bool>"
|
// @has - '//*[@id="associatedtype.Out12"]' "type Out12: for<'w> Helper<B<'w> = Cow<'w, str>, A<'w> = bool>"
|
||||||
|
// @has - '//*[@id="associatedtype.Out13"]' "type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>"
|
||||||
//
|
//
|
||||||
// Snapshots: Check that we do not render any where-clauses for those associated types since all of
|
// Snapshots: Check that we do not render any where-clauses for those associated types since all of
|
||||||
// the trait bounds contained within were moved to the bounds of the respective item.
|
// the trait bounds contained within were moved to the bounds of the respective item.
|
||||||
|
|
|
@ -14,6 +14,7 @@ pub trait Main {
|
||||||
type Out10<'q>: Support<Output<'q> = ()>;
|
type Out10<'q>: Support<Output<'q> = ()>;
|
||||||
type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>;
|
type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>;
|
||||||
type Out12: for<'w> Helper<B<'w> = std::borrow::Cow<'w, str>, A<'w> = bool>;
|
type Out12: for<'w> Helper<B<'w> = std::borrow::Cow<'w, str>, A<'w> = bool>;
|
||||||
|
type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>;
|
||||||
|
|
||||||
fn make<F>(_: F, _: impl FnMut(&str) -> bool)
|
fn make<F>(_: F, _: impl FnMut(&str) -> bool)
|
||||||
where
|
where
|
||||||
|
@ -38,3 +39,7 @@ pub trait Helper {
|
||||||
type A<'q>;
|
type A<'q>;
|
||||||
type B<'q>;
|
type B<'q>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Aid<'src> {
|
||||||
|
type Result<'inter>;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,19 @@ pub fn func3(_x: impl Iterator<Item = impl Iterator<Item = u8>> + Clone) {}
|
||||||
|
|
||||||
pub fn func4<T: Iterator<Item = impl Clone>>(_x: T) {}
|
pub fn func4<T: Iterator<Item = impl Clone>>(_x: T) {}
|
||||||
|
|
||||||
|
pub fn func5(
|
||||||
|
_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,
|
||||||
|
_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(&'beta ())>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
pub trait Other {
|
||||||
|
type T<'dependency>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Auxiliary<'arena> {
|
||||||
|
type Item<'input>;
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn async_fn() {}
|
pub async fn async_fn() {}
|
||||||
|
|
||||||
pub struct Foo;
|
pub struct Foo;
|
||||||
|
|
|
@ -26,6 +26,13 @@ pub use impl_trait_aux::func3;
|
||||||
// @has - '//pre[@class="rust fn"]' "T: Iterator<Item = impl Clone>,"
|
// @has - '//pre[@class="rust fn"]' "T: Iterator<Item = impl Clone>,"
|
||||||
pub use impl_trait_aux::func4;
|
pub use impl_trait_aux::func4;
|
||||||
|
|
||||||
|
// @has impl_trait/fn.func5.html
|
||||||
|
// @has - '//pre[@class="rust fn"]' "func5("
|
||||||
|
// @has - '//pre[@class="rust fn"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,"
|
||||||
|
// @has - '//pre[@class="rust fn"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(&'beta ())>"
|
||||||
|
// @!has - '//pre[@class="rust fn"]' 'where'
|
||||||
|
pub use impl_trait_aux::func5;
|
||||||
|
|
||||||
// @has impl_trait/fn.async_fn.html
|
// @has impl_trait/fn.async_fn.html
|
||||||
// @has - '//pre[@class="rust fn"]' "pub async fn async_fn()"
|
// @has - '//pre[@class="rust fn"]' "pub async fn async_fn()"
|
||||||
pub use impl_trait_aux::async_fn;
|
pub use impl_trait_aux::async_fn;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue