Skip to content

Commit 13dfdc4

Browse files
committed
Auto merge of #121022 - fmease:rustdoc-x-crate-late-bound-lt-src-order, r=<try>
rustdoc: cross-crate re-exports: correctly render late-bound params in source order even if early-bound params are present r? ghost
2 parents 502ce82 + d4a5de3 commit 13dfdc4

File tree

8 files changed

+106
-62
lines changed

8 files changed

+106
-62
lines changed

src/librustdoc/clean/auto_trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ where
334334
match br {
335335
// We only care about named late bound regions, as we need to add them
336336
// to the 'for<>' section
337-
ty::BrNamed(_, name) => Some(GenericParamDef::lifetime(name)),
337+
ty::BrNamed(did, name) => Some(GenericParamDef::lifetime(did, name)),
338338
_ => None,
339339
}
340340
})

src/librustdoc/clean/inline.rs

+32-13
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ use rustc_span::hygiene::MacroKind;
1818
use rustc_span::symbol::{kw, sym, Symbol};
1919

2020
use crate::clean::{
21-
self, clean_bound_vars, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item,
22-
clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings,
21+
self, clean_bound_vars, clean_generics, clean_impl_item, clean_middle_assoc_item,
22+
clean_middle_field, clean_middle_ty, clean_poly_fn_sig, clean_trait_ref_with_bindings,
2323
clean_ty, clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes,
2424
AttributesExt, ImplKind, ItemId, Type,
2525
};
@@ -72,7 +72,9 @@ pub(crate) fn try_inline(
7272
}
7373
Res::Def(DefKind::Fn, did) => {
7474
record_extern_fqn(cx, did, ItemType::Function);
75-
cx.with_param_env(did, |cx| clean::FunctionItem(build_external_function(cx, did)))
75+
cx.with_param_env(did, |cx| {
76+
clean::enter_impl_trait(cx, |cx| clean::FunctionItem(build_function(cx, did)))
77+
})
7678
}
7779
Res::Def(DefKind::Struct, did) => {
7880
record_extern_fqn(cx, did, ItemType::Struct);
@@ -274,18 +276,35 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
274276
clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
275277
}
276278

277-
fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box<clean::Function> {
279+
pub(crate) fn build_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box<clean::Function> {
278280
let sig = cx.tcx.fn_sig(did).instantiate_identity();
279-
let predicates = cx.tcx.explicit_predicates_of(did);
281+
// The generics need to be cleaned before the signature.
282+
let mut generics =
283+
clean_ty_generics(cx, cx.tcx.generics_of(did), cx.tcx.explicit_predicates_of(did));
284+
let bound_vars = clean_bound_vars(sig.bound_vars());
285+
286+
// At the time of writing early & late-bound params are stored separately in rustc,
287+
// namely in `generics.params` and `bound_vars` respectively.
288+
//
289+
// To reestablish the original source code order of the generic parameters, we
290+
// need to manually sort them by their definition span after concatenation.
291+
//
292+
// See also:
293+
// * https://rustc-dev-guide.rust-lang.org/bound-vars-and-params.html
294+
// * https://rustc-dev-guide.rust-lang.org/what-does-early-late-bound-mean.html
295+
let has_early_bound_params = !generics.params.is_empty();
296+
let has_late_bound_params = !bound_vars.is_empty();
297+
generics.params.extend(bound_vars);
298+
if has_early_bound_params && has_late_bound_params {
299+
// If this ever becomes a performances bottleneck either due to the sorting
300+
// or due to the query calls, consider inserting the late-bound lifetime params
301+
// right after the last early-bound lifetime param followed by only sorting
302+
// the slice of lifetime params.
303+
generics.params.sort_by_key(|param| cx.tcx.def_ident_span(param.did).unwrap());
304+
}
305+
306+
let decl = clean_poly_fn_sig(cx, Some(did), sig);
280307

281-
let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
282-
// NOTE: generics need to be cleaned before the decl!
283-
let mut generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
284-
// FIXME: This does not place parameters in source order (late-bound ones come last)
285-
generics.params.extend(clean_bound_vars(sig.bound_vars()));
286-
let decl = clean_fn_decl_from_did_and_sig(cx, Some(did), sig);
287-
(generics, decl)
288-
});
289308
Box::new(clean::Function { decl, generics })
290309
}
291310

src/librustdoc/clean/mod.rs

+23-30
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,6 @@ fn clean_generic_param_def<'tcx>(
523523
(
524524
def.name,
525525
GenericParamDefKind::Type {
526-
did: def.def_id,
527526
bounds: ThinVec::new(), // These are filled in from the where-clauses.
528527
default: default.map(Box::new),
529528
synthetic,
@@ -555,7 +554,7 @@ fn clean_generic_param_def<'tcx>(
555554
),
556555
};
557556

558-
GenericParamDef { name, kind }
557+
GenericParamDef { name, did: def.def_id, kind }
559558
}
560559

561560
fn clean_generic_param<'tcx>(
@@ -594,7 +593,6 @@ fn clean_generic_param<'tcx>(
594593
(
595594
param.name.ident().name,
596595
GenericParamDefKind::Type {
597-
did: param.def_id.to_def_id(),
598596
bounds,
599597
default: default.map(|t| clean_ty(t, cx)).map(Box::new),
600598
synthetic,
@@ -612,7 +610,7 @@ fn clean_generic_param<'tcx>(
612610
),
613611
};
614612

615-
GenericParamDef { name, kind }
613+
GenericParamDef { name, did: param.def_id.to_def_id(), kind }
616614
}
617615

618616
/// Synthetic type-parameters are inserted after normal ones.
@@ -644,8 +642,8 @@ pub(crate) fn clean_generics<'tcx>(
644642
let param = clean_generic_param(cx, Some(gens), param);
645643
match param.kind {
646644
GenericParamDefKind::Lifetime { .. } => unreachable!(),
647-
GenericParamDefKind::Type { did, ref bounds, .. } => {
648-
cx.impl_trait_bounds.insert(did.into(), bounds.to_vec());
645+
GenericParamDefKind::Type { ref bounds, .. } => {
646+
cx.impl_trait_bounds.insert(param.did.into(), bounds.to_vec());
649647
}
650648
GenericParamDefKind::Const { .. } => unreachable!(),
651649
}
@@ -1062,8 +1060,11 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib
10621060
match literal.kind {
10631061
ast::LitKind::Int(a, _) => {
10641062
let gen = func.generics.params.remove(0);
1065-
if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } =
1066-
gen
1063+
if let GenericParamDef {
1064+
name,
1065+
kind: GenericParamDefKind::Const { ty, .. },
1066+
..
1067+
} = gen
10671068
{
10681069
func.decl
10691070
.inputs
@@ -1167,7 +1168,7 @@ fn clean_fn_decl_with_args<'tcx>(
11671168
FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
11681169
}
11691170

1170-
fn clean_fn_decl_from_did_and_sig<'tcx>(
1171+
fn clean_poly_fn_sig<'tcx>(
11711172
cx: &mut DocContext<'tcx>,
11721173
did: Option<DefId>,
11731174
sig: ty::PolyFnSig<'tcx>,
@@ -1357,16 +1358,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
13571358
}
13581359
}
13591360
ty::AssocKind::Fn => {
1360-
let sig = tcx.fn_sig(assoc_item.def_id).instantiate_identity();
1361-
let mut generics = clean_ty_generics(
1362-
cx,
1363-
tcx.generics_of(assoc_item.def_id),
1364-
tcx.explicit_predicates_of(assoc_item.def_id),
1365-
);
1366-
// FIXME: This does not place parameters in source order (late-bound ones come last)
1367-
generics.params.extend(clean_bound_vars(sig.bound_vars()));
1368-
1369-
let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
1361+
let mut item = inline::build_function(cx, assoc_item.def_id);
13701362

13711363
if assoc_item.fn_has_self_parameter {
13721364
let self_ty = match assoc_item.container {
@@ -1375,12 +1367,13 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
13751367
}
13761368
ty::TraitContainer => tcx.types.self_param,
13771369
};
1378-
let self_arg_ty = sig.input(0).skip_binder();
1370+
let self_arg_ty =
1371+
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
13791372
if self_arg_ty == self_ty {
1380-
decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
1373+
item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
13811374
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
13821375
if ty == self_ty {
1383-
match decl.inputs.values[0].type_ {
1376+
match item.decl.inputs.values[0].type_ {
13841377
BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
13851378
_ => unreachable!(),
13861379
}
@@ -1397,9 +1390,9 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
13971390
ty::ImplContainer => Some(assoc_item.defaultness(tcx)),
13981391
ty::TraitContainer => None,
13991392
};
1400-
MethodItem(Box::new(Function { generics, decl }), defaultness)
1393+
MethodItem(item, defaultness)
14011394
} else {
1402-
TyMethodItem(Box::new(Function { generics, decl }))
1395+
TyMethodItem(item)
14031396
}
14041397
}
14051398
ty::AssocKind::Type => {
@@ -2083,7 +2076,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
20832076
ty::FnDef(..) | ty::FnPtr(_) => {
20842077
// FIXME: should we merge the outer and inner binders somehow?
20852078
let sig = bound_ty.skip_binder().fn_sig(cx.tcx);
2086-
let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
2079+
let decl = clean_poly_fn_sig(cx, None, sig);
20872080
let generic_params = clean_bound_vars(sig.bound_vars());
20882081

20892082
BareFunction(Box::new(BareFunctionDecl {
@@ -2166,10 +2159,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
21662159
.iter()
21672160
.flat_map(|pred| pred.bound_vars())
21682161
.filter_map(|var| match var {
2169-
ty::BoundVariableKind::Region(ty::BrNamed(_, name))
2162+
ty::BoundVariableKind::Region(ty::BrNamed(did, name))
21702163
if name != kw::UnderscoreLifetime =>
21712164
{
2172-
Some(GenericParamDef::lifetime(name))
2165+
Some(GenericParamDef::lifetime(did, name))
21732166
}
21742167
_ => None,
21752168
})
@@ -3141,15 +3134,15 @@ fn clean_bound_vars<'tcx>(
31413134
bound_vars
31423135
.into_iter()
31433136
.filter_map(|var| match var {
3144-
ty::BoundVariableKind::Region(ty::BrNamed(_, name))
3137+
ty::BoundVariableKind::Region(ty::BrNamed(did, name))
31453138
if name != kw::UnderscoreLifetime =>
31463139
{
3147-
Some(GenericParamDef::lifetime(name))
3140+
Some(GenericParamDef::lifetime(did, name))
31483141
}
31493142
ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(did, name)) => Some(GenericParamDef {
31503143
name,
3144+
did,
31513145
kind: GenericParamDefKind::Type {
3152-
did,
31533146
bounds: ThinVec::new(),
31543147
default: None,
31553148
synthetic: false,

src/librustdoc/clean/types.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,7 @@ impl WherePredicate {
13261326
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
13271327
pub(crate) enum GenericParamDefKind {
13281328
Lifetime { outlives: ThinVec<Lifetime> },
1329-
Type { did: DefId, bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
1329+
Type { bounds: ThinVec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
13301330
// Option<Box<String>> makes this type smaller than `Option<String>` would.
13311331
Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool },
13321332
}
@@ -1339,13 +1339,14 @@ impl GenericParamDefKind {
13391339

13401340
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
13411341
pub(crate) struct GenericParamDef {
1342+
pub(crate) did: DefId,
13421343
pub(crate) name: Symbol,
13431344
pub(crate) kind: GenericParamDefKind,
13441345
}
13451346

13461347
impl GenericParamDef {
1347-
pub(crate) fn lifetime(name: Symbol) -> Self {
1348-
Self { name, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
1348+
pub(crate) fn lifetime(did: DefId, name: Symbol) -> Self {
1349+
Self { name, did, kind: GenericParamDefKind::Lifetime { outlives: ThinVec::new() } }
13491350
}
13501351

13511352
pub(crate) fn is_synthetic_param(&self) -> bool {

src/librustdoc/html/format.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ impl clean::GenericParamDef {
188188
cx: &'a Context<'tcx>,
189189
) -> impl fmt::Display + 'a + Captures<'tcx> {
190190
display_fn(move |f| match &self.kind {
191-
clean::GenericParamDefKind::Lifetime { outlives } => {
191+
clean::GenericParamDefKind::Lifetime { outlives, .. } => {
192192
write!(f, "{}", self.name)?;
193193

194194
if !outlives.is_empty() {

src/librustdoc/json/conversions.rs

+11-14
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
456456
Lifetime { outlives } => GenericParamDefKind::Lifetime {
457457
outlives: outlives.into_iter().map(convert_lifetime).collect(),
458458
},
459-
Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
459+
Type { bounds, default, synthetic } => GenericParamDefKind::Type {
460460
bounds: bounds.into_tcx(tcx),
461461
default: default.map(|x| (*x).into_tcx(tcx)),
462462
synthetic,
@@ -486,19 +486,16 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
486486
outlives: outlives.iter().map(|lt| lt.0.to_string()).collect(),
487487
}
488488
}
489-
clean::GenericParamDefKind::Type {
490-
did: _,
491-
bounds,
492-
default,
493-
synthetic,
494-
} => GenericParamDefKind::Type {
495-
bounds: bounds
496-
.into_iter()
497-
.map(|bound| bound.into_tcx(tcx))
498-
.collect(),
499-
default: default.map(|ty| (*ty).into_tcx(tcx)),
500-
synthetic,
501-
},
489+
clean::GenericParamDefKind::Type { bounds, default, synthetic } => {
490+
GenericParamDefKind::Type {
491+
bounds: bounds
492+
.into_iter()
493+
.map(|bound| bound.into_tcx(tcx))
494+
.collect(),
495+
default: default.map(|ty| (*ty).into_tcx(tcx)),
496+
synthetic,
497+
}
498+
}
502499
clean::GenericParamDefKind::Const {
503500
ty,
504501
default,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Here, `'a` and `'c` are late-bound and `'b`, `'d`, `T` and `N` are early-bound.
2+
3+
pub fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)
4+
where
5+
'b:,
6+
'd:,
7+
{}
8+
9+
pub struct Ty;
10+
11+
impl Ty {
12+
pub fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)
13+
where
14+
'b:,
15+
'd:,
16+
{}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Check that we correctly render late-bound lifetime params in source order
2+
// even if early-bound generic params are present.
3+
//
4+
// For context, at the time of writing early- and late-bound params are stored
5+
// separately in rustc and therefore rustdoc needs to manually merge them.
6+
7+
#![crate_name = "usr"]
8+
// aux-crate:dep=early-late-bound-lifetime-params.rs
9+
// edition:2021
10+
11+
// @has usr/fn.f.html
12+
// @has - '//pre[@class="rust item-decl"]' "fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)"
13+
pub use dep::f;
14+
15+
// @has usr/struct.Ty.html
16+
// @has - '//*[@id="method.f"]' "fn f<'a, 'b, 'c, 'd, T, const N: usize>(_: impl Copy)"
17+
pub use dep::Ty;

0 commit comments

Comments
 (0)