Skip to content

rustdoc: Clean up handling of lifetime bounds #88604

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/librustdoc/clean/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,9 +331,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
match br {
// We only care about named late bound regions, as we need to add them
// to the 'for<>' section
ty::BrNamed(_, name) => {
Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime })
}
ty::BrNamed(_, name) => Some(GenericParamDef {
name,
kind: GenericParamDefKind::Lifetime { outlives: vec![] },
}),
_ => None,
}
})
Expand Down Expand Up @@ -659,7 +660,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
bounds.insert(0, GenericBound::maybe_sized(self.cx));
}
}
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Lifetime { .. } => {}
GenericParamDefKind::Const { ref mut default, .. } => {
// We never want something like `impl<const N: usize = 10>`
default.take();
Expand Down
91 changes: 42 additions & 49 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use rustc_target::spec::abi::Abi;
use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
use rustc_typeck::hir_ty_to_ty;

use std::assert_matches::assert_matches;
use std::collections::hash_map::Entry;
use std::default::Default;
use std::hash::Hash;
Expand Down Expand Up @@ -199,9 +200,10 @@ impl Clean<GenericBound> for (ty::PolyTraitRef<'_>, &[TypeBinding]) {
.collect_referenced_late_bound_regions(&poly_trait_ref)
.into_iter()
.filter_map(|br| match br {
ty::BrNamed(_, name) => {
Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime })
}
ty::BrNamed(_, name) => Some(GenericParamDef {
name,
kind: GenericParamDefKind::Lifetime { outlives: vec![] },
}),
_ => None,
})
.collect();
Expand Down Expand Up @@ -241,30 +243,6 @@ impl Clean<Lifetime> for hir::Lifetime {
}
}

impl Clean<Lifetime> for hir::GenericParam<'_> {
fn clean(&self, _: &mut DocContext<'_>) -> Lifetime {
match self.kind {
hir::GenericParamKind::Lifetime { .. } => {
if !self.bounds.is_empty() {
let mut bounds = self.bounds.iter().map(|bound| match bound {
hir::GenericBound::Outlives(lt) => lt,
_ => panic!(),
});
let name = bounds.next().expect("no more bounds").name.ident();
let mut s = format!("{}: {}", self.name.ident(), name);
for bound in bounds {
s.push_str(&format!(" + {}", bound.name.ident()));
}
Lifetime(Symbol::intern(&s))
} else {
Lifetime(self.name.ident().name)
}
}
_ => panic!(),
}
}
}

impl Clean<Constant> for hir::ConstArg {
fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
Constant {
Expand Down Expand Up @@ -302,11 +280,30 @@ impl Clean<Option<Lifetime>> for ty::RegionKind {
impl Clean<WherePredicate> for hir::WherePredicate<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
match *self {
hir::WherePredicate::BoundPredicate(ref wbp) => WherePredicate::BoundPredicate {
ty: wbp.bounded_ty.clean(cx),
bounds: wbp.bounds.clean(cx),
bound_params: wbp.bound_generic_params.into_iter().map(|x| x.clean(cx)).collect(),
},
hir::WherePredicate::BoundPredicate(ref wbp) => {
let bound_params = wbp
.bound_generic_params
.into_iter()
.map(|param| {
// Higher-ranked params must be lifetimes.
// Higher-ranked lifetimes can't have bounds.
assert_matches!(
param,
hir::GenericParam {
kind: hir::GenericParamKind::Lifetime { .. },
bounds: [],
..
}
);
Lifetime(param.name.ident().name)
})
.collect();
WherePredicate::BoundPredicate {
ty: wbp.bounded_ty.clean(cx),
bounds: wbp.bounds.clean(cx),
bound_params,
}
}

hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
lifetime: wrp.lifetime.clean(cx),
Expand Down Expand Up @@ -412,7 +409,9 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
impl Clean<GenericParamDef> for ty::GenericParamDef {
fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
let (name, kind) = match self.kind {
ty::GenericParamDefKind::Lifetime => (self.name, GenericParamDefKind::Lifetime),
ty::GenericParamDefKind::Lifetime => {
(self.name, GenericParamDefKind::Lifetime { outlives: vec![] })
}
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
let default = if has_default {
let mut default = cx.tcx.type_of(self.def_id).clean(cx);
Expand Down Expand Up @@ -462,21 +461,15 @@ impl Clean<GenericParamDef> for hir::GenericParam<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
let (name, kind) = match self.kind {
hir::GenericParamKind::Lifetime { .. } => {
let name = if !self.bounds.is_empty() {
let mut bounds = self.bounds.iter().map(|bound| match bound {
hir::GenericBound::Outlives(lt) => lt,
let outlives = self
.bounds
.iter()
.map(|bound| match bound {
hir::GenericBound::Outlives(lt) => lt.clean(cx),
_ => panic!(),
});
let name = bounds.next().expect("no more bounds").name.ident();
let mut s = format!("{}: {}", self.name.ident(), name);
for bound in bounds {
s.push_str(&format!(" + {}", bound.name.ident()));
}
Symbol::intern(&s)
} else {
self.name.ident().name
};
(name, GenericParamDefKind::Lifetime)
})
.collect();
(self.name.ident().name, GenericParamDefKind::Lifetime { outlives })
}
hir::GenericParamKind::Type { ref default, synthetic } => (
self.name.ident().name,
Expand Down Expand Up @@ -536,7 +529,7 @@ impl Clean<Generics> for hir::Generics<'_> {
.map(|param| {
let param: GenericParamDef = param.clean(cx);
match param.kind {
GenericParamDefKind::Lifetime => unreachable!(),
GenericParamDefKind::Lifetime { .. } => unreachable!(),
GenericParamDefKind::Type { did, ref bounds, .. } => {
cx.impl_trait_bounds.insert(did.into(), bounds.clone());
}
Expand Down Expand Up @@ -569,7 +562,7 @@ impl Clean<Generics> for hir::Generics<'_> {
{
for param in &mut generics.params {
match param.kind {
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Lifetime { .. } => {}
GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
if &param.name == name {
mem::swap(bounds, ty_bounds);
Expand Down
8 changes: 5 additions & 3 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1231,7 +1231,9 @@ impl WherePredicate {

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
crate enum GenericParamDefKind {
Lifetime,
Lifetime {
outlives: Vec<Lifetime>,
},
Type {
did: DefId,
bounds: Vec<GenericBound>,
Expand All @@ -1257,7 +1259,7 @@ impl GenericParamDefKind {
match self {
GenericParamDefKind::Type { default, .. } => default.clone(),
GenericParamDefKind::Const { ty, .. } => Some(ty.clone()),
GenericParamDefKind::Lifetime => None,
GenericParamDefKind::Lifetime { .. } => None,
}
}
}
Expand All @@ -1271,7 +1273,7 @@ crate struct GenericParamDef {
impl GenericParamDef {
crate fn is_synthetic_type_param(&self) -> bool {
match self.kind {
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => false,
GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
}
}
Expand Down
22 changes: 18 additions & 4 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,23 @@ impl clean::GenericParamDef {
&'a self,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
display_fn(move |f| match self.kind {
clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
display_fn(move |f| match &self.kind {
clean::GenericParamDefKind::Lifetime { outlives } => {
write!(f, "{}", self.name)?;

if !outlives.is_empty() {
f.write_str(": ")?;
for (i, lt) in outlives.iter().enumerate() {
if i != 0 {
f.write_str(" + ")?;
}
write!(f, "{}", lt.print())?;
}
}

Ok(())
}
clean::GenericParamDefKind::Type { bounds, default, .. } => {
f.write_str(&*self.name.as_str())?;

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

Ok(())
}
clean::GenericParamDefKind::Const { ref ty, ref default, .. } => {
clean::GenericParamDefKind::Const { ty, default, .. } => {
if f.alternate() {
write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
} else {
Expand Down
4 changes: 3 additions & 1 deletion src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,9 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self {
use clean::GenericParamDefKind::*;
match kind {
Lifetime => GenericParamDefKind::Lifetime,
Lifetime { outlives } => GenericParamDefKind::Lifetime {
outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(),
},
Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type {
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
default: default.map(|x| x.into_tcx(tcx)),
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
)
})
.collect(),
format_version: 6,
format_version: 7,
};
let mut p = self.out_path.clone();
p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
)]
#![feature(rustc_private)]
#![feature(array_methods)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(in_band_lifetimes)]
Expand Down
2 changes: 1 addition & 1 deletion src/rustdoc-json-types/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ pub struct GenericParamDef {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum GenericParamDefKind {
Lifetime,
Lifetime { outlives: Vec<String> },
Type { bounds: Vec<GenericBound>, default: Option<Type> },
Const { ty: Type, default: Option<String> },
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/rustdoc-json/structs/with_primitives.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @has with_primitives.json "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
// @has - "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind" \"lifetime\"
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\"
// @has - "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true
pub struct WithPrimitives<'a> {
Expand Down
9 changes: 9 additions & 0 deletions src/test/rustdoc-ui/bounded-hr-lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This test ensures that rustdoc doesn't panic on higher-ranked lifetimes
// with bounds, because an error should have already been emitted by rustc.

pub fn hrlt<'b, 'c>()
where
for<'a: 'b + 'c> &'a (): std::fmt::Debug,
//~^ ERROR lifetime bounds cannot be used in this context
{
}
10 changes: 10 additions & 0 deletions src/test/rustdoc-ui/bounded-hr-lifetime.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: lifetime bounds cannot be used in this context
--> $DIR/bounded-hr-lifetime.rs:6:13
|
LL | for<'a: 'b + 'c> &'a (): std::fmt::Debug,
| ^^ ^^

error: Compilation failed, aborting rustdoc

error: aborting due to 2 previous errors