Skip to content

Commit f7c00dc

Browse files
committed
Auto merge of #88604 - camelid:rustdoc-lifetime-bounds, r=GuillaumeGomez
rustdoc: Clean up handling of lifetime bounds Previously, rustdoc recorded lifetime bounds by rendering them into the name of the lifetime parameter. Now, it leaves the name as the actual name and instead records lifetime bounds in an `outlives` list, similar to how type parameter bounds are recorded. Also, higher-ranked lifetimes cannot currently have bounds, so I simplified the code to reflect that. r? `@GuillaumeGomez`
2 parents 7e1e3eb + 3a3f99a commit f7c00dc

File tree

11 files changed

+96
-64
lines changed

11 files changed

+96
-64
lines changed

src/librustdoc/clean/auto_trait.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
331331
match br {
332332
// We only care about named late bound regions, as we need to add them
333333
// to the 'for<>' section
334-
ty::BrNamed(_, name) => {
335-
Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime })
336-
}
334+
ty::BrNamed(_, name) => Some(GenericParamDef {
335+
name,
336+
kind: GenericParamDefKind::Lifetime { outlives: vec![] },
337+
}),
337338
_ => None,
338339
}
339340
})
@@ -659,7 +660,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
659660
bounds.insert(0, GenericBound::maybe_sized(self.cx));
660661
}
661662
}
662-
GenericParamDefKind::Lifetime => {}
663+
GenericParamDefKind::Lifetime { .. } => {}
663664
GenericParamDefKind::Const { ref mut default, .. } => {
664665
// We never want something like `impl<const N: usize = 10>`
665666
default.take();

src/librustdoc/clean/mod.rs

+42-49
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use rustc_target::spec::abi::Abi;
3030
use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
3131
use rustc_typeck::hir_ty_to_ty;
3232

33+
use std::assert_matches::assert_matches;
3334
use std::collections::hash_map::Entry;
3435
use std::default::Default;
3536
use std::hash::Hash;
@@ -199,9 +200,10 @@ impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
199200
.collect_referenced_late_bound_regions(&poly_trait_ref)
200201
.into_iter()
201202
.filter_map(|br| match br {
202-
ty::BrNamed(_, name) => {
203-
Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime })
204-
}
203+
ty::BrNamed(_, name) => Some(GenericParamDef {
204+
name,
205+
kind: GenericParamDefKind::Lifetime { outlives: vec![] },
206+
}),
205207
_ => None,
206208
})
207209
.collect();
@@ -241,30 +243,6 @@ impl Clean<Lifetime> for hir::Lifetime {
241243
}
242244
}
243245

244-
impl Clean<Lifetime> for hir::GenericParam<'_> {
245-
fn clean(&self, _: &mut DocContext<'_>) -> Lifetime {
246-
match self.kind {
247-
hir::GenericParamKind::Lifetime { .. } => {
248-
if !self.bounds.is_empty() {
249-
let mut bounds = self.bounds.iter().map(|bound| match bound {
250-
hir::GenericBound::Outlives(lt) => lt,
251-
_ => panic!(),
252-
});
253-
let name = bounds.next().expect("no more bounds").name.ident();
254-
let mut s = format!("{}: {}", self.name.ident(), name);
255-
for bound in bounds {
256-
s.push_str(&format!(" + {}", bound.name.ident()));
257-
}
258-
Lifetime(Symbol::intern(&s))
259-
} else {
260-
Lifetime(self.name.ident().name)
261-
}
262-
}
263-
_ => panic!(),
264-
}
265-
}
266-
}
267-
268246
impl Clean<Constant> for hir::ConstArg {
269247
fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
270248
Constant {
@@ -302,11 +280,30 @@ impl Clean<Option<Lifetime>> for ty::RegionKind {
302280
impl Clean<WherePredicate> for hir::WherePredicate<'_> {
303281
fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
304282
match *self {
305-
hir::WherePredicate::BoundPredicate(ref wbp) => WherePredicate::BoundPredicate {
306-
ty: wbp.bounded_ty.clean(cx),
307-
bounds: wbp.bounds.clean(cx),
308-
bound_params: wbp.bound_generic_params.into_iter().map(|x| x.clean(cx)).collect(),
309-
},
283+
hir::WherePredicate::BoundPredicate(ref wbp) => {
284+
let bound_params = wbp
285+
.bound_generic_params
286+
.into_iter()
287+
.map(|param| {
288+
// Higher-ranked params must be lifetimes.
289+
// Higher-ranked lifetimes can't have bounds.
290+
assert_matches!(
291+
param,
292+
hir::GenericParam {
293+
kind: hir::GenericParamKind::Lifetime { .. },
294+
bounds: [],
295+
..
296+
}
297+
);
298+
Lifetime(param.name.ident().name)
299+
})
300+
.collect();
301+
WherePredicate::BoundPredicate {
302+
ty: wbp.bounded_ty.clean(cx),
303+
bounds: wbp.bounds.clean(cx),
304+
bound_params,
305+
}
306+
}
310307

311308
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
312309
lifetime: wrp.lifetime.clean(cx),
@@ -412,7 +409,9 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
412409
impl Clean<GenericParamDef> for ty::GenericParamDef {
413410
fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
414411
let (name, kind) = match self.kind {
415-
ty::GenericParamDefKind::Lifetime => (self.name, GenericParamDefKind::Lifetime),
412+
ty::GenericParamDefKind::Lifetime => {
413+
(self.name, GenericParamDefKind::Lifetime { outlives: vec![] })
414+
}
416415
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
417416
let default = if has_default {
418417
let mut default = cx.tcx.type_of(self.def_id).clean(cx);
@@ -462,21 +461,15 @@ impl Clean<GenericParamDef> for hir::GenericParam<'_> {
462461
fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
463462
let (name, kind) = match self.kind {
464463
hir::GenericParamKind::Lifetime { .. } => {
465-
let name = if !self.bounds.is_empty() {
466-
let mut bounds = self.bounds.iter().map(|bound| match bound {
467-
hir::GenericBound::Outlives(lt) => lt,
464+
let outlives = self
465+
.bounds
466+
.iter()
467+
.map(|bound| match bound {
468+
hir::GenericBound::Outlives(lt) => lt.clean(cx),
468469
_ => panic!(),
469-
});
470-
let name = bounds.next().expect("no more bounds").name.ident();
471-
let mut s = format!("{}: {}", self.name.ident(), name);
472-
for bound in bounds {
473-
s.push_str(&format!(" + {}", bound.name.ident()));
474-
}
475-
Symbol::intern(&s)
476-
} else {
477-
self.name.ident().name
478-
};
479-
(name, GenericParamDefKind::Lifetime)
470+
})
471+
.collect();
472+
(self.name.ident().name, GenericParamDefKind::Lifetime { outlives })
480473
}
481474
hir::GenericParamKind::Type { ref default, synthetic } => (
482475
self.name.ident().name,
@@ -536,7 +529,7 @@ impl Clean<Generics> for hir::Generics<'_> {
536529
.map(|param| {
537530
let param: GenericParamDef = param.clean(cx);
538531
match param.kind {
539-
GenericParamDefKind::Lifetime => unreachable!(),
532+
GenericParamDefKind::Lifetime { .. } => unreachable!(),
540533
GenericParamDefKind::Type { did, ref bounds, .. } => {
541534
cx.impl_trait_bounds.insert(did.into(), bounds.clone());
542535
}
@@ -569,7 +562,7 @@ impl Clean<Generics> for hir::Generics<'_> {
569562
{
570563
for param in &mut generics.params {
571564
match param.kind {
572-
GenericParamDefKind::Lifetime => {}
565+
GenericParamDefKind::Lifetime { .. } => {}
573566
GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
574567
if &param.name == name {
575568
mem::swap(bounds, ty_bounds);

src/librustdoc/clean/types.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,9 @@ impl WherePredicate {
12311231

12321232
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
12331233
crate enum GenericParamDefKind {
1234-
Lifetime,
1234+
Lifetime {
1235+
outlives: Vec<Lifetime>,
1236+
},
12351237
Type {
12361238
did: DefId,
12371239
bounds: Vec<GenericBound>,
@@ -1257,7 +1259,7 @@ impl GenericParamDefKind {
12571259
match self {
12581260
GenericParamDefKind::Type { default, .. } => default.clone(),
12591261
GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
1260-
GenericParamDefKind::Lifetime => None,
1262+
GenericParamDefKind::Lifetime { .. } => None,
12611263
}
12621264
}
12631265
}
@@ -1271,7 +1273,7 @@ crate struct GenericParamDef {
12711273
impl GenericParamDef {
12721274
crate fn is_synthetic_type_param(&self) -> bool {
12731275
match self.kind {
1274-
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => false,
1276+
GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
12751277
GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
12761278
}
12771279
}

src/librustdoc/html/format.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,23 @@ impl clean::GenericParamDef {
155155
&'a self,
156156
cx: &'a Context<'tcx>,
157157
) -> impl fmt::Display + 'a + Captures<'tcx> {
158-
display_fn(move |f| match self.kind {
159-
clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
160-
clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
158+
display_fn(move |f| match &self.kind {
159+
clean::GenericParamDefKind::Lifetime { outlives } => {
160+
write!(f, "{}", self.name)?;
161+
162+
if !outlives.is_empty() {
163+
f.write_str(": ")?;
164+
for (i, lt) in outlives.iter().enumerate() {
165+
if i != 0 {
166+
f.write_str(" + ")?;
167+
}
168+
write!(f, "{}", lt.print())?;
169+
}
170+
}
171+
172+
Ok(())
173+
}
174+
clean::GenericParamDefKind::Type { bounds, default, .. } => {
161175
f.write_str(&*self.name.as_str())?;
162176

163177
if !bounds.is_empty() {
@@ -178,7 +192,7 @@ impl clean::GenericParamDef {
178192

179193
Ok(())
180194
}
181-
clean::GenericParamDefKind::Const { ref ty, ref default, .. } => {
195+
clean::GenericParamDefKind::Const { ty, default, .. } => {
182196
if f.alternate() {
183197
write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
184198
} else {

src/librustdoc/json/conversions.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,9 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
326326
fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self {
327327
use clean::GenericParamDefKind::*;
328328
match kind {
329-
Lifetime => GenericParamDefKind::Lifetime,
329+
Lifetime { outlives } => GenericParamDefKind::Lifetime {
330+
outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(),
331+
},
330332
Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type {
331333
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
332334
default: default.map(|x| x.into_tcx(tcx)),

src/librustdoc/json/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
234234
)
235235
})
236236
.collect(),
237-
format_version: 6,
237+
format_version: 7,
238238
};
239239
let mut p = self.out_path.clone();
240240
p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
)]
55
#![feature(rustc_private)]
66
#![feature(array_methods)]
7+
#![feature(assert_matches)]
78
#![feature(box_patterns)]
89
#![feature(control_flow_enum)]
910
#![feature(in_band_lifetimes)]

src/rustdoc-json-types/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ pub struct GenericParamDef {
323323
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
324324
#[serde(rename_all = "snake_case")]
325325
pub enum GenericParamDefKind {
326-
Lifetime,
326+
Lifetime { outlives: Vec<String> },
327327
Type { bounds: Vec<GenericBound>, default: Option<Type> },
328328
Const { ty: Type, default: Option<String> },
329329
}

src/test/rustdoc-json/structs/with_primitives.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @has with_primitives.json "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
22
// @has - "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
33
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
4-
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind" \"lifetime\"
4+
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
55
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\"
66
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true
77
pub struct WithPrimitives<'a> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// This test ensures that rustdoc doesn't panic on higher-ranked lifetimes
2+
// with bounds, because an error should have already been emitted by rustc.
3+
4+
pub fn hrlt<'b, 'c>()
5+
where
6+
for<'a: 'b + 'c> &'a (): std::fmt::Debug,
7+
//~^ ERROR lifetime bounds cannot be used in this context
8+
{
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: lifetime bounds cannot be used in this context
2+
--> $DIR/bounded-hr-lifetime.rs:6:13
3+
|
4+
LL | for<'a: 'b + 'c> &'a (): std::fmt::Debug,
5+
| ^^ ^^
6+
7+
error: Compilation failed, aborting rustdoc
8+
9+
error: aborting due to 2 previous errors
10+

0 commit comments

Comments
 (0)