Rollup merge of #121022 - fmease:rustdoc-x-crate-late-bound-lt-src-order, r=GuillaumeGomez
rustdoc: cross-crate re-exports: correctly render late-bound params in source order even if early-bound params are present r? ghost
This commit is contained in:
commit
f9a0675c3c
@ -334,7 +334,7 @@ fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet<GenericParam
|
|||||||
match br {
|
match br {
|
||||||
// We only care about named late bound regions, as we need to add them
|
// We only care about named late bound regions, as we need to add them
|
||||||
// to the 'for<>' section
|
// to the 'for<>' section
|
||||||
ty::BrNamed(_, name) => Some(GenericParamDef::lifetime(name)),
|
ty::BrNamed(def_id, name) => Some(GenericParamDef::lifetime(def_id, name)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
|
|
||||||
use crate::clean::{
|
use crate::clean::{
|
||||||
self, clean_bound_vars, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item,
|
self, clean_bound_vars, clean_generics, clean_impl_item, clean_middle_assoc_item,
|
||||||
clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings,
|
clean_middle_field, clean_middle_ty, clean_poly_fn_sig, clean_trait_ref_with_bindings,
|
||||||
clean_ty, clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes,
|
clean_ty, clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes,
|
||||||
AttributesExt, ImplKind, ItemId, Type,
|
AttributesExt, ImplKind, ItemId, Type,
|
||||||
};
|
};
|
||||||
@ -72,7 +72,9 @@ pub(crate) fn try_inline(
|
|||||||
}
|
}
|
||||||
Res::Def(DefKind::Fn, did) => {
|
Res::Def(DefKind::Fn, did) => {
|
||||||
record_extern_fqn(cx, did, ItemType::Function);
|
record_extern_fqn(cx, did, ItemType::Function);
|
||||||
cx.with_param_env(did, |cx| clean::FunctionItem(build_external_function(cx, did)))
|
cx.with_param_env(did, |cx| {
|
||||||
|
clean::enter_impl_trait(cx, |cx| clean::FunctionItem(build_function(cx, did)))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::Struct, did) => {
|
Res::Def(DefKind::Struct, did) => {
|
||||||
record_extern_fqn(cx, did, ItemType::Struct);
|
record_extern_fqn(cx, did, ItemType::Struct);
|
||||||
@ -274,18 +276,38 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
|
|||||||
clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
|
clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box<clean::Function> {
|
pub(crate) fn build_function<'tcx>(
|
||||||
let sig = cx.tcx.fn_sig(did).instantiate_identity();
|
cx: &mut DocContext<'tcx>,
|
||||||
let predicates = cx.tcx.explicit_predicates_of(did);
|
def_id: DefId,
|
||||||
|
) -> Box<clean::Function> {
|
||||||
|
let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
|
||||||
|
// The generics need to be cleaned before the signature.
|
||||||
|
let mut generics =
|
||||||
|
clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
|
||||||
|
let bound_vars = clean_bound_vars(sig.bound_vars());
|
||||||
|
|
||||||
|
// At the time of writing early & late-bound params are stored separately in rustc,
|
||||||
|
// namely in `generics.params` and `bound_vars` respectively.
|
||||||
|
//
|
||||||
|
// To reestablish the original source code order of the generic parameters, we
|
||||||
|
// need to manually sort them by their definition span after concatenation.
|
||||||
|
//
|
||||||
|
// See also:
|
||||||
|
// * https://rustc-dev-guide.rust-lang.org/bound-vars-and-params.html
|
||||||
|
// * https://rustc-dev-guide.rust-lang.org/what-does-early-late-bound-mean.html
|
||||||
|
let has_early_bound_params = !generics.params.is_empty();
|
||||||
|
let has_late_bound_params = !bound_vars.is_empty();
|
||||||
|
generics.params.extend(bound_vars);
|
||||||
|
if has_early_bound_params && has_late_bound_params {
|
||||||
|
// If this ever becomes a performances bottleneck either due to the sorting
|
||||||
|
// or due to the query calls, consider inserting the late-bound lifetime params
|
||||||
|
// right after the last early-bound lifetime param followed by only sorting
|
||||||
|
// the slice of lifetime params.
|
||||||
|
generics.params.sort_by_key(|param| cx.tcx.def_ident_span(param.def_id).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let decl = clean_poly_fn_sig(cx, Some(def_id), sig);
|
||||||
|
|
||||||
let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
|
|
||||||
// NOTE: generics need to be cleaned before the decl!
|
|
||||||
let mut generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
|
|
||||||
// FIXME: This does not place parameters in source order (late-bound ones come last)
|
|
||||||
generics.params.extend(clean_bound_vars(sig.bound_vars()));
|
|
||||||
let decl = clean_fn_decl_from_did_and_sig(cx, Some(did), sig);
|
|
||||||
(generics, decl)
|
|
||||||
});
|
|
||||||
Box::new(clean::Function { decl, generics })
|
Box::new(clean::Function { decl, generics })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,7 +523,6 @@ fn clean_generic_param_def<'tcx>(
|
|||||||
(
|
(
|
||||||
def.name,
|
def.name,
|
||||||
GenericParamDefKind::Type {
|
GenericParamDefKind::Type {
|
||||||
did: def.def_id,
|
|
||||||
bounds: ThinVec::new(), // These are filled in from the where-clauses.
|
bounds: ThinVec::new(), // These are filled in from the where-clauses.
|
||||||
default: default.map(Box::new),
|
default: default.map(Box::new),
|
||||||
synthetic,
|
synthetic,
|
||||||
@ -555,7 +554,7 @@ fn clean_generic_param_def<'tcx>(
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
GenericParamDef { name, kind }
|
GenericParamDef { name, def_id: def.def_id, kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_generic_param<'tcx>(
|
fn clean_generic_param<'tcx>(
|
||||||
@ -594,7 +593,6 @@ fn clean_generic_param<'tcx>(
|
|||||||
(
|
(
|
||||||
param.name.ident().name,
|
param.name.ident().name,
|
||||||
GenericParamDefKind::Type {
|
GenericParamDefKind::Type {
|
||||||
did: param.def_id.to_def_id(),
|
|
||||||
bounds,
|
bounds,
|
||||||
default: default.map(|t| clean_ty(t, cx)).map(Box::new),
|
default: default.map(|t| clean_ty(t, cx)).map(Box::new),
|
||||||
synthetic,
|
synthetic,
|
||||||
@ -612,7 +610,7 @@ fn clean_generic_param<'tcx>(
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
GenericParamDef { name, kind }
|
GenericParamDef { name, def_id: param.def_id.to_def_id(), kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synthetic type-parameters are inserted after normal ones.
|
/// Synthetic type-parameters are inserted after normal ones.
|
||||||
@ -644,8 +642,8 @@ pub(crate) fn clean_generics<'tcx>(
|
|||||||
let param = clean_generic_param(cx, Some(gens), param);
|
let param = clean_generic_param(cx, Some(gens), param);
|
||||||
match param.kind {
|
match param.kind {
|
||||||
GenericParamDefKind::Lifetime { .. } => unreachable!(),
|
GenericParamDefKind::Lifetime { .. } => unreachable!(),
|
||||||
GenericParamDefKind::Type { did, ref bounds, .. } => {
|
GenericParamDefKind::Type { ref bounds, .. } => {
|
||||||
cx.impl_trait_bounds.insert(did.into(), bounds.to_vec());
|
cx.impl_trait_bounds.insert(param.def_id.into(), bounds.to_vec());
|
||||||
}
|
}
|
||||||
GenericParamDefKind::Const { .. } => unreachable!(),
|
GenericParamDefKind::Const { .. } => unreachable!(),
|
||||||
}
|
}
|
||||||
@ -1062,8 +1060,11 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib
|
|||||||
match literal.kind {
|
match literal.kind {
|
||||||
ast::LitKind::Int(a, _) => {
|
ast::LitKind::Int(a, _) => {
|
||||||
let gen = func.generics.params.remove(0);
|
let gen = func.generics.params.remove(0);
|
||||||
if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } =
|
if let GenericParamDef {
|
||||||
gen
|
name,
|
||||||
|
kind: GenericParamDefKind::Const { ty, .. },
|
||||||
|
..
|
||||||
|
} = gen
|
||||||
{
|
{
|
||||||
func.decl
|
func.decl
|
||||||
.inputs
|
.inputs
|
||||||
@ -1167,7 +1168,7 @@ fn clean_fn_decl_with_args<'tcx>(
|
|||||||
FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
|
FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_fn_decl_from_did_and_sig<'tcx>(
|
fn clean_poly_fn_sig<'tcx>(
|
||||||
cx: &mut DocContext<'tcx>,
|
cx: &mut DocContext<'tcx>,
|
||||||
did: Option<DefId>,
|
did: Option<DefId>,
|
||||||
sig: ty::PolyFnSig<'tcx>,
|
sig: ty::PolyFnSig<'tcx>,
|
||||||
@ -1357,16 +1358,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AssocKind::Fn => {
|
ty::AssocKind::Fn => {
|
||||||
let sig = tcx.fn_sig(assoc_item.def_id).instantiate_identity();
|
let mut item = inline::build_function(cx, assoc_item.def_id);
|
||||||
let mut generics = clean_ty_generics(
|
|
||||||
cx,
|
|
||||||
tcx.generics_of(assoc_item.def_id),
|
|
||||||
tcx.explicit_predicates_of(assoc_item.def_id),
|
|
||||||
);
|
|
||||||
// FIXME: This does not place parameters in source order (late-bound ones come last)
|
|
||||||
generics.params.extend(clean_bound_vars(sig.bound_vars()));
|
|
||||||
|
|
||||||
let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
|
|
||||||
|
|
||||||
if assoc_item.fn_has_self_parameter {
|
if assoc_item.fn_has_self_parameter {
|
||||||
let self_ty = match assoc_item.container {
|
let self_ty = match assoc_item.container {
|
||||||
@ -1375,12 +1367,13 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
|||||||
}
|
}
|
||||||
ty::TraitContainer => tcx.types.self_param,
|
ty::TraitContainer => tcx.types.self_param,
|
||||||
};
|
};
|
||||||
let self_arg_ty = sig.input(0).skip_binder();
|
let self_arg_ty =
|
||||||
|
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
|
||||||
if self_arg_ty == self_ty {
|
if self_arg_ty == self_ty {
|
||||||
decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
|
item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
|
||||||
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
|
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
|
||||||
if ty == self_ty {
|
if ty == self_ty {
|
||||||
match decl.inputs.values[0].type_ {
|
match item.decl.inputs.values[0].type_ {
|
||||||
BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
|
BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@ -1397,9 +1390,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
|||||||
ty::ImplContainer => Some(assoc_item.defaultness(tcx)),
|
ty::ImplContainer => Some(assoc_item.defaultness(tcx)),
|
||||||
ty::TraitContainer => None,
|
ty::TraitContainer => None,
|
||||||
};
|
};
|
||||||
MethodItem(Box::new(Function { generics, decl }), defaultness)
|
MethodItem(item, defaultness)
|
||||||
} else {
|
} else {
|
||||||
TyMethodItem(Box::new(Function { generics, decl }))
|
TyMethodItem(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AssocKind::Type => {
|
ty::AssocKind::Type => {
|
||||||
@ -2083,7 +2076,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||||||
ty::FnDef(..) | ty::FnPtr(_) => {
|
ty::FnDef(..) | ty::FnPtr(_) => {
|
||||||
// FIXME: should we merge the outer and inner binders somehow?
|
// FIXME: should we merge the outer and inner binders somehow?
|
||||||
let sig = bound_ty.skip_binder().fn_sig(cx.tcx);
|
let sig = bound_ty.skip_binder().fn_sig(cx.tcx);
|
||||||
let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
|
let decl = clean_poly_fn_sig(cx, None, sig);
|
||||||
let generic_params = clean_bound_vars(sig.bound_vars());
|
let generic_params = clean_bound_vars(sig.bound_vars());
|
||||||
|
|
||||||
BareFunction(Box::new(BareFunctionDecl {
|
BareFunction(Box::new(BareFunctionDecl {
|
||||||
@ -2166,10 +2159,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||||||
.iter()
|
.iter()
|
||||||
.flat_map(|pred| pred.bound_vars())
|
.flat_map(|pred| pred.bound_vars())
|
||||||
.filter_map(|var| match var {
|
.filter_map(|var| match var {
|
||||||
ty::BoundVariableKind::Region(ty::BrNamed(_, name))
|
ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
|
||||||
if name != kw::UnderscoreLifetime =>
|
if name != kw::UnderscoreLifetime =>
|
||||||
{
|
{
|
||||||
Some(GenericParamDef::lifetime(name))
|
Some(GenericParamDef::lifetime(def_id, name))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
@ -3141,20 +3134,22 @@ fn clean_bound_vars<'tcx>(
|
|||||||
bound_vars
|
bound_vars
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|var| match var {
|
.filter_map(|var| match var {
|
||||||
ty::BoundVariableKind::Region(ty::BrNamed(_, name))
|
ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
|
||||||
if name != kw::UnderscoreLifetime =>
|
if name != kw::UnderscoreLifetime =>
|
||||||
{
|
{
|
||||||
Some(GenericParamDef::lifetime(name))
|
Some(GenericParamDef::lifetime(def_id, name))
|
||||||
|
}
|
||||||
|
ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) => {
|
||||||
|
Some(GenericParamDef {
|
||||||
|
name,
|
||||||
|
def_id,
|
||||||
|
kind: GenericParamDefKind::Type {
|
||||||
|
bounds: ThinVec::new(),
|
||||||
|
default: None,
|
||||||
|
synthetic: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(did, name)) => Some(GenericParamDef {
|
|
||||||
name,
|
|
||||||
kind: GenericParamDefKind::Type {
|
|
||||||
did,
|
|
||||||
bounds: ThinVec::new(),
|
|
||||||
default: None,
|
|
||||||
synthetic: false,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
// FIXME(non_lifetime_binders): Support higher-ranked const parameters.
|
// FIXME(non_lifetime_binders): Support higher-ranked const parameters.
|
||||||
ty::BoundVariableKind::Const => None,
|
ty::BoundVariableKind::Const => None,
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -1326,7 +1326,7 @@ pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
|
|||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub(crate) enum GenericParamDefKind {
|
pub(crate) enum GenericParamDefKind {
|
||||||
Lifetime { outlives: ThinVec<Lifetime> },
|
Lifetime { outlives: ThinVec<Lifetime> },
|
||||||
Type { did: DefId, bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
|
Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
|
||||||
// Option<Box<String>> makes this type smaller than `Option<String>` would.
|
// Option<Box<String>> makes this type smaller than `Option<String>` would.
|
||||||
Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool },
|
Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool },
|
||||||
}
|
}
|
||||||
@ -1340,12 +1340,13 @@ pub(crate) fn is_type(&self) -> bool {
|
|||||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||||
pub(crate) struct GenericParamDef {
|
pub(crate) struct GenericParamDef {
|
||||||
pub(crate) name: Symbol,
|
pub(crate) name: Symbol,
|
||||||
|
pub(crate) def_id: DefId,
|
||||||
pub(crate) kind: GenericParamDefKind,
|
pub(crate) kind: GenericParamDefKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenericParamDef {
|
impl GenericParamDef {
|
||||||
pub(crate) fn lifetime(name: Symbol) -> Self {
|
pub(crate) fn lifetime(def_id: DefId, name: Symbol) -> Self {
|
||||||
Self { name, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
|
Self { name, def_id, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_synthetic_param(&self) -> bool {
|
pub(crate) fn is_synthetic_param(&self) -> bool {
|
||||||
|
@ -456,7 +456,7 @@ fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self {
|
|||||||
Lifetime { outlives } => GenericParamDefKind::Lifetime {
|
Lifetime { outlives } => GenericParamDefKind::Lifetime {
|
||||||
outlives: outlives.into_iter().map(convert_lifetime).collect(),
|
outlives: outlives.into_iter().map(convert_lifetime).collect(),
|
||||||
},
|
},
|
||||||
Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
|
Type { bounds, default, synthetic } => GenericParamDefKind::Type {
|
||||||
bounds: bounds.into_tcx(tcx),
|
bounds: bounds.into_tcx(tcx),
|
||||||
default: default.map(|x| (*x).into_tcx(tcx)),
|
default: default.map(|x| (*x).into_tcx(tcx)),
|
||||||
synthetic,
|
synthetic,
|
||||||
@ -486,19 +486,16 @@ fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self {
|
|||||||
outlives: outlives.iter().map(|lt| lt.0.to_string()).collect(),
|
outlives: outlives.iter().map(|lt| lt.0.to_string()).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clean::GenericParamDefKind::Type {
|
clean::GenericParamDefKind::Type { bounds, default, synthetic } => {
|
||||||
did: _,
|
GenericParamDefKind::Type {
|
||||||
bounds,
|
bounds: bounds
|
||||||
default,
|
.into_iter()
|
||||||
synthetic,
|
.map(|bound| bound.into_tcx(tcx))
|
||||||
} => GenericParamDefKind::Type {
|
.collect(),
|
||||||
bounds: bounds
|
default: default.map(|ty| (*ty).into_tcx(tcx)),
|
||||||
.into_iter()
|
synthetic,
|
||||||
.map(|bound| bound.into_tcx(tcx))
|
}
|
||||||
.collect(),
|
}
|
||||||
default: default.map(|ty| (*ty).into_tcx(tcx)),
|
|
||||||
synthetic,
|
|
||||||
},
|
|
||||||
clean::GenericParamDefKind::Const {
|
clean::GenericParamDefKind::Const {
|
||||||
ty,
|
ty,
|
||||||
default,
|
default,
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
// Here, `'a` and `'c` are late-bound and `'b`, `'d`, `T` and `N` are early-bound.
|
||||||
|
|
||||||
|
pub fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)
|
||||||
|
where
|
||||||
|
'b:,
|
||||||
|
'd:,
|
||||||
|
{}
|
||||||
|
|
||||||
|
pub struct Ty;
|
||||||
|
|
||||||
|
impl Ty {
|
||||||
|
pub fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)
|
||||||
|
where
|
||||||
|
'b:,
|
||||||
|
'd:,
|
||||||
|
{}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// Check that we correctly render late-bound lifetime params in source order
|
||||||
|
// even if early-bound generic params are present.
|
||||||
|
//
|
||||||
|
// For context, at the time of writing early- and late-bound params are stored
|
||||||
|
// separately in rustc and therefore rustdoc needs to manually merge them.
|
||||||
|
|
||||||
|
#![crate_name = "usr"]
|
||||||
|
// aux-crate:dep=early-late-bound-lifetime-params.rs
|
||||||
|
// edition:2021
|
||||||
|
|
||||||
|
// @has usr/fn.f.html
|
||||||
|
// @has - '//pre[@class="rust item-decl"]' "fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)"
|
||||||
|
pub use dep::f;
|
||||||
|
|
||||||
|
// @has usr/struct.Ty.html
|
||||||
|
// @has - '//*[@id="method.f"]' "fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)"
|
||||||
|
pub use dep::Ty;
|
Loading…
Reference in New Issue
Block a user