Skip to content

Commit a011dd9

Browse files
committed
Render generic const items in rustdoc
1 parent 59bb77c commit a011dd9

File tree

8 files changed

+116
-69
lines changed

8 files changed

+116
-69
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,13 +644,18 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
644644
}
645645

646646
fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
647+
let mut generics =
648+
clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
649+
clean::simplify::move_bounds_to_generic_parameters(&mut generics);
650+
647651
clean::Constant {
648652
type_: clean_middle_ty(
649653
ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()),
650654
cx,
651655
Some(def_id),
652656
None,
653657
),
658+
generics: Box::new(generics),
654659
kind: clean::ConstantKind::Extern { def_id },
655660
}
656661
}

src/librustdoc/clean/mod.rs

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'t
273273
Some(def_id),
274274
None,
275275
),
276+
generics: Box::new(Generics::default()),
276277
kind: ConstantKind::Anonymous { body: constant.value.body },
277278
}
278279
}
@@ -284,6 +285,7 @@ pub(crate) fn clean_middle_const<'tcx>(
284285
// FIXME: instead of storing the stringified expression, store `self` directly instead.
285286
Constant {
286287
type_: clean_middle_ty(constant.map_bound(|c| c.ty()), cx, None, None),
288+
generics: Box::new(Generics::default()),
287289
kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() },
288290
}
289291
}
@@ -1188,11 +1190,18 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
11881190
let local_did = trait_item.owner_id.to_def_id();
11891191
cx.with_param_env(local_did, |cx| {
11901192
let inner = match trait_item.kind {
1191-
hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
1192-
clean_ty(ty, cx),
1193-
ConstantKind::Local { def_id: local_did, body: default },
1194-
),
1195-
hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
1193+
hir::TraitItemKind::Const(ty, Some(default)) => {
1194+
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
1195+
AssocConstItem(
1196+
Box::new(generics),
1197+
clean_ty(ty, cx),
1198+
ConstantKind::Local { def_id: local_did, body: default },
1199+
)
1200+
}
1201+
hir::TraitItemKind::Const(ty, None) => {
1202+
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
1203+
TyAssocConstItem(Box::new(generics), clean_ty(ty, cx))
1204+
}
11961205
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
11971206
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
11981207
MethodItem(m, None)
@@ -1237,8 +1246,9 @@ pub(crate) fn clean_impl_item<'tcx>(
12371246
cx.with_param_env(local_did, |cx| {
12381247
let inner = match impl_.kind {
12391248
hir::ImplItemKind::Const(ty, expr) => {
1249+
let generics = clean_generics(impl_.generics, cx);
12401250
let default = ConstantKind::Local { def_id: local_did, body: expr };
1241-
AssocConstItem(clean_ty(ty, cx), default)
1251+
AssocConstItem(Box::new(generics), clean_ty(ty, cx), default)
12421252
}
12431253
hir::ImplItemKind::Fn(ref sig, body) => {
12441254
let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body));
@@ -1279,14 +1289,21 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
12791289
None,
12801290
);
12811291

1292+
let mut generics = Box::new(clean_ty_generics(
1293+
cx,
1294+
tcx.generics_of(assoc_item.def_id),
1295+
tcx.explicit_predicates_of(assoc_item.def_id),
1296+
));
1297+
simplify::move_bounds_to_generic_parameters(&mut generics);
1298+
12821299
let provided = match assoc_item.container {
12831300
ty::ImplContainer => true,
12841301
ty::TraitContainer => tcx.defaultness(assoc_item.def_id).has_value(),
12851302
};
12861303
if provided {
1287-
AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id })
1304+
AssocConstItem(generics, ty, ConstantKind::Extern { def_id: assoc_item.def_id })
12881305
} else {
1289-
TyAssocConstItem(ty)
1306+
TyAssocConstItem(generics, ty)
12901307
}
12911308
}
12921309
ty::AssocKind::Fn => {
@@ -1379,34 +1396,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
13791396
tcx.generics_of(assoc_item.def_id),
13801397
ty::GenericPredicates { parent: None, predicates },
13811398
);
1382-
// Move bounds that are (likely) directly attached to the parameters of the
1383-
// (generic) associated type from the where clause to the respective parameter.
1384-
// There is no guarantee that this is what the user actually wrote but we have
1385-
// no way of knowing.
1386-
let mut where_predicates = ThinVec::new();
1387-
for mut pred in generics.where_predicates {
1388-
if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
1389-
&& let Some(GenericParamDef {
1390-
kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
1391-
..
1392-
}) = generics.params.iter_mut().find(|param| &param.name == arg)
1393-
{
1394-
param_bounds.append(bounds);
1395-
} else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
1396-
&& let Some(GenericParamDef {
1397-
kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
1398-
..
1399-
}) = generics.params.iter_mut().find(|param| &param.name == arg)
1400-
{
1401-
param_bounds.extend(bounds.drain(..).map(|bound| match bound {
1402-
GenericBound::Outlives(lifetime) => lifetime,
1403-
_ => unreachable!(),
1404-
}));
1405-
} else {
1406-
where_predicates.push(pred);
1407-
}
1408-
}
1409-
generics.where_predicates = where_predicates;
1399+
simplify::move_bounds_to_generic_parameters(&mut generics);
14101400

14111401
if let ty::TraitContainer = assoc_item.container {
14121402
// Move bounds that are (likely) directly attached to the associated type
@@ -2603,9 +2593,9 @@ fn clean_maybe_renamed_item<'tcx>(
26032593
ItemKind::Static(ty, mutability, body_id) => {
26042594
StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) })
26052595
}
2606-
// FIXME(fmease): rustdoc integration
2607-
ItemKind::Const(ty, _generics, body_id) => ConstantItem(Constant {
2596+
ItemKind::Const(ty, generics, body_id) => ConstantItem(Constant {
26082597
type_: clean_ty(ty, cx),
2598+
generics: Box::new(clean_generics(generics, cx)),
26092599
kind: ConstantKind::Local { body: body_id, def_id },
26102600
}),
26112601
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {

src/librustdoc/clean/simplify.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,38 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
138138
})
139139
.any(|did| trait_is_same_or_supertrait(cx, did, trait_))
140140
}
141+
142+
/// Move bounds that are (likely) directly attached to generic parameters from the where-clause to
143+
/// the respective parameter.
144+
///
145+
/// There is no guarantee that this is what the user actually wrote but we have no way of knowing.
146+
// FIXME(fmease): It'd make a lot of sense to just incorporate this logic into `clean_ty_generics`
147+
// making every of its users benefit from it.
148+
pub(crate) fn move_bounds_to_generic_parameters(generics: &mut clean::Generics) {
149+
use clean::types::*;
150+
151+
let mut where_predicates = ThinVec::new();
152+
for mut pred in generics.where_predicates.drain(..) {
153+
if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
154+
&& let Some(GenericParamDef {
155+
kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
156+
..
157+
}) = generics.params.iter_mut().find(|param| &param.name == arg)
158+
{
159+
param_bounds.append(bounds);
160+
} else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
161+
&& let Some(GenericParamDef {
162+
kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
163+
..
164+
}) = generics.params.iter_mut().find(|param| &param.name == arg)
165+
{
166+
param_bounds.extend(bounds.drain(..).map(|bound| match bound {
167+
GenericBound::Outlives(lifetime) => lifetime,
168+
_ => unreachable!(),
169+
}));
170+
} else {
171+
where_predicates.push(pred);
172+
}
173+
}
174+
generics.where_predicates = where_predicates;
175+
}

src/librustdoc/clean/types.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -824,9 +824,9 @@ pub(crate) enum ItemKind {
824824
ProcMacroItem(ProcMacro),
825825
PrimitiveItem(PrimitiveType),
826826
/// A required associated constant in a trait declaration.
827-
TyAssocConstItem(Type),
827+
TyAssocConstItem(Box<Generics>, Type),
828828
/// An associated constant in a trait impl or a provided one in a trait declaration.
829-
AssocConstItem(Type, ConstantKind),
829+
AssocConstItem(Box<Generics>, Type, ConstantKind),
830830
/// A required associated type in a trait declaration.
831831
///
832832
/// The bounds may be non-empty if there is a `where` clause.
@@ -871,8 +871,8 @@ impl ItemKind {
871871
| MacroItem(_)
872872
| ProcMacroItem(_)
873873
| PrimitiveItem(_)
874-
| TyAssocConstItem(_)
875-
| AssocConstItem(_, _)
874+
| TyAssocConstItem(..)
875+
| AssocConstItem(..)
876876
| TyAssocTypeItem(..)
877877
| AssocTypeItem(..)
878878
| StrippedItem(_)
@@ -1278,7 +1278,7 @@ impl Lifetime {
12781278
}
12791279
}
12801280

1281-
#[derive(Clone, Debug)]
1281+
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
12821282
pub(crate) enum WherePredicate {
12831283
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
12841284
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
@@ -1348,7 +1348,7 @@ impl GenericParamDef {
13481348
}
13491349

13501350
// maybe use a Generic enum and use Vec<Generic>?
1351-
#[derive(Clone, Debug, Default)]
1351+
#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
13521352
pub(crate) struct Generics {
13531353
pub(crate) params: ThinVec<GenericParamDef>,
13541354
pub(crate) where_predicates: ThinVec<WherePredicate>,
@@ -2266,6 +2266,7 @@ pub(crate) struct Static {
22662266
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
22672267
pub(crate) struct Constant {
22682268
pub(crate) type_: Type,
2269+
pub(crate) generics: Box<Generics>,
22692270
pub(crate) kind: ConstantKind,
22702271
}
22712272

@@ -2515,7 +2516,8 @@ mod size_asserts {
25152516
static_assert_size!(GenericParamDef, 56);
25162517
static_assert_size!(Generics, 16);
25172518
static_assert_size!(Item, 56);
2518-
static_assert_size!(ItemKind, 64);
2519+
// FIXME(generic_const_items): Further reduce the size.
2520+
static_assert_size!(ItemKind, 72);
25192521
static_assert_size!(PathSegment, 40);
25202522
static_assert_size!(Type, 32);
25212523
// tidy-alphabetical-end

src/librustdoc/html/render/mod.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -748,20 +748,22 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
748748
fn assoc_const(
749749
w: &mut Buffer,
750750
it: &clean::Item,
751+
generics: &clean::Generics,
751752
ty: &clean::Type,
752753
default: Option<&clean::ConstantKind>,
753754
link: AssocItemLink<'_>,
754-
extra: &str,
755+
indent: usize,
755756
cx: &Context<'_>,
756757
) {
757758
let tcx = cx.tcx();
758759
write!(
759760
w,
760-
"{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
761-
extra = extra,
761+
"{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
762+
indent = " ".repeat(indent),
762763
vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
763764
href = assoc_href_attr(it, link, cx),
764765
name = it.name.as_ref().unwrap(),
766+
generics = generics.print(cx),
765767
ty = ty.print(cx),
766768
);
767769
if let Some(default) = default {
@@ -774,6 +776,7 @@ fn assoc_const(
774776
// Find a way to print constants here without all that jazz.
775777
write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx))));
776778
}
779+
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
777780
}
778781

779782
fn assoc_type(
@@ -986,19 +989,22 @@ fn render_assoc_item(
986989
clean::MethodItem(m, _) => {
987990
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
988991
}
989-
kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const(
990-
w,
991-
item,
992-
ty,
993-
match kind {
994-
clean::TyAssocConstItem(_) => None,
995-
clean::AssocConstItem(_, default) => Some(default),
996-
_ => unreachable!(),
997-
},
998-
link,
999-
if parent == ItemType::Trait { " " } else { "" },
1000-
cx,
1001-
),
992+
kind @ (clean::TyAssocConstItem(generics, ty) | clean::AssocConstItem(generics, ty, _)) => {
993+
assoc_const(
994+
w,
995+
item,
996+
generics,
997+
ty,
998+
match kind {
999+
clean::TyAssocConstItem(..) => None,
1000+
clean::AssocConstItem(.., default) => Some(default),
1001+
_ => unreachable!(),
1002+
},
1003+
link,
1004+
if parent == ItemType::Trait { 4 } else { 0 },
1005+
cx,
1006+
)
1007+
}
10021008
clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
10031009
w,
10041010
item,
@@ -1565,7 +1571,8 @@ fn render_impl(
15651571
w.write_str("</section>");
15661572
}
15671573
}
1568-
kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
1574+
kind @ (clean::TyAssocConstItem(generics, ty)
1575+
| clean::AssocConstItem(generics, ty, _)) => {
15691576
let source_id = format!("{}.{}", item_type, name);
15701577
let id = cx.derive_id(source_id.clone());
15711578
write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
@@ -1578,14 +1585,15 @@ fn render_impl(
15781585
assoc_const(
15791586
w,
15801587
item,
1588+
generics,
15811589
ty,
15821590
match kind {
1583-
clean::TyAssocConstItem(_) => None,
1584-
clean::AssocConstItem(_, default) => Some(default),
1591+
clean::TyAssocConstItem(..) => None,
1592+
clean::AssocConstItem(.., default) => Some(default),
15851593
_ => unreachable!(),
15861594
},
15871595
link.anchor(if trait_.is_some() { &source_id } else { &id }),
1588-
"",
1596+
0,
15891597
cx,
15901598
);
15911599
w.write_str("</h4>");

src/librustdoc/html/render/print_item.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1543,10 +1543,12 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
15431543

15441544
write!(
15451545
w,
1546-
"{vis}const {name}: {typ}",
1546+
"{vis}const {name}{generics}: {typ}{where_clause}",
15471547
vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
15481548
name = it.name.unwrap(),
1549+
generics = c.generics.print(cx),
15491550
typ = c.type_.print(cx),
1551+
where_clause = print_where_clause(&c.generics, cx, 0, Ending::NoNewline),
15501552
);
15511553

15521554
// FIXME: The code below now prints

src/librustdoc/html/render/span_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
219219
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
220220
match item.kind {
221221
ItemKind::Static(_, _, _)
222-
| ItemKind::Const(_, _)
222+
| ItemKind::Const(_, _, _)
223223
| ItemKind::Fn(_, _, _)
224224
| ItemKind::Macro(_, _)
225225
| ItemKind::TyAlias(_, _)

src/librustdoc/json/conversions.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg {
171171
}
172172

173173
impl FromWithTcx<clean::Constant> for Constant {
174+
// FIXME(generic_const_items): Add support for generic const items.
174175
fn from_tcx(constant: clean::Constant, tcx: TyCtxt<'_>) -> Self {
175176
let expr = constant.expr(tcx);
176177
let value = constant.value(tcx);
@@ -321,8 +322,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
321322
impls: Vec::new(), // Added in JsonRenderer::item
322323
})
323324
}
324-
TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None },
325-
AssocConstItem(ty, default) => {
325+
// FIXME(generic_const_items): Add support for generic associated consts.
326+
TyAssocConstItem(_generics, ty) => {
327+
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None }
328+
}
329+
// FIXME(generic_const_items): Add support for generic associated consts.
330+
AssocConstItem(_generics, ty, default) => {
326331
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) }
327332
}
328333
TyAssocTypeItem(g, b) => ItemEnum::AssocType {

0 commit comments

Comments
 (0)