Skip to content
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

[rustdoc] Show enum discriminant if it is a C-like variant #116142

Merged
merged 9 commits into from
Oct 9, 2023
7 changes: 3 additions & 4 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2091,9 +2091,8 @@ impl Discriminant {
pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
self.expr.map(|body| rendered_const(tcx, body))
}
/// Will always be a machine readable number, without underscores or suffixes.
pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String {
print_evaluated_const(tcx, self.value, false).unwrap()
pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String {
print_evaluated_const(tcx, self.value, with_underscores, false).unwrap()
}
}

Expand Down Expand Up @@ -2348,7 +2347,7 @@ impl ConstantKind {
match *self {
ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
print_evaluated_const(tcx, def_id, true)
print_evaluated_const(tcx, def_id, true, true)
}
}
}
Expand Down
40 changes: 29 additions & 11 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
pub(crate) fn print_evaluated_const(
tcx: TyCtxt<'_>,
def_id: DefId,
underscores_and_type: bool,
with_underscores: bool,
with_type: bool,
) -> Option<String> {
tcx.const_eval_poly(def_id).ok().and_then(|val| {
let ty = tcx.type_of(def_id).instantiate_identity();
Expand All @@ -284,7 +285,7 @@ pub(crate) fn print_evaluated_const(
(mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
(mir::ConstValue::Scalar(_), _) => {
let const_ = mir::Const::from_value(val, ty);
Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
Some(print_const_with_custom_print_scalar(tcx, const_, with_underscores, with_type))
}
_ => None,
}
Expand Down Expand Up @@ -320,14 +321,25 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
fn print_const_with_custom_print_scalar<'tcx>(
tcx: TyCtxt<'tcx>,
ct: mir::Const<'tcx>,
underscores_and_type: bool,
with_underscores: bool,
with_type: bool,
) -> String {
// Use a slightly different format for integer types which always shows the actual value.
// For all other types, fallback to the original `pretty_print_const`.
match (ct, ct.ty().kind()) {
(mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => {
if underscores_and_type {
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
if with_underscores {
if with_type {
format!(
"{}{}",
format_integer_with_underscore_sep(&int.to_string()),
ui.name_str()
)
} else {
format_integer_with_underscore_sep(&int.to_string())
}
} else if with_type {
format!("{}{}", int.to_string(), ui.name_str())
} else {
int.to_string()
}
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -337,12 +349,18 @@ fn print_const_with_custom_print_scalar<'tcx>(
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
let data = int.assert_bits(size);
let sign_extended_data = size.sign_extend(data) as i128;
if underscores_and_type {
format!(
"{}{}",
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
i.name_str()
)
if with_underscores {
if with_type {
format!(
"{}{}",
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
i.name_str()
)
} else {
format_integer_with_underscore_sep(&sign_extended_data.to_string())
}
} else if with_type {
format!("{}{}", sign_extended_data.to_string(), i.name_str())
} else {
sign_extended_data.to_string()
}
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
106 changes: 91 additions & 15 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1257,13 +1257,14 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c
w,
cx,
Some(&t.generics),
variants_iter(),
&variants,
variants_count,
has_stripped_entries,
*is_non_exhaustive,
it.def_id().unwrap(),
)
});
item_variants(w, cx, it, variants_iter());
item_variants(w, cx, it, &variants);
}
clean::TypeAliasInnerType::Union { fields } => {
wrap_item(w, |w| {
Expand Down Expand Up @@ -1416,36 +1417,83 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
it.name.unwrap(),
e.generics.print(cx),
);

render_enum_fields(
w,
cx,
Some(&e.generics),
e.variants(),
&e.variants,
count_variants,
e.has_stripped_entries(),
it.is_non_exhaustive(),
it.def_id().unwrap(),
);
});

write!(w, "{}", document(cx, it, None, HeadingOffset::H2));

if count_variants != 0 {
item_variants(w, cx, it, e.variants());
item_variants(w, cx, it, &e.variants);
}
let def_id = it.item_id.expect_def_id();
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
write!(w, "{}", document_type_layout(cx, def_id));
}

fn render_enum_fields<'a>(
/// It'll return true if all variants are C-like variants and if at least one of them has a value
/// set.
fn should_show_c_like_variants_value(
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
variants: &rustc_index::IndexVec<rustc_target::abi::VariantIdx, clean::Item>,
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
) -> bool {
let mut has_variants_with_value = false;
for variant in variants {
if let clean::VariantItem(ref var) = *variant.kind &&
matches!(var.kind, clean::VariantKind::CLike)
{
has_variants_with_value |= var.discriminant.is_some();
} else {
return false;
}
}
has_variants_with_value
}

fn display_c_like_variant(
w: &mut Buffer,
cx: &mut Context<'_>,
item: &clean::Item,
variant: &clean::Variant,
index: rustc_target::abi::VariantIdx,
should_show_c_like_variants_value: bool,
enum_def_id: DefId,
) {
let name = item.name.unwrap();
if let Some(ref value) = variant.discriminant {
write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true));
} else if should_show_c_like_variants_value {
let adt_def = cx.tcx().adt_def(enum_def_id);
let discr = adt_def.discriminant_for_variant(cx.tcx(), index);
if discr.ty.is_signed() {
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
write!(w, "{} = {}", name.as_str(), discr.val as i128);
} else {
write!(w, "{} = {}", name.as_str(), discr.val);
}
} else {
w.write_str(name.as_str());
}
}

fn render_enum_fields(
mut w: &mut Buffer,
cx: &mut Context<'_>,
g: Option<&clean::Generics>,
variants: impl Iterator<Item = &'a clean::Item>,
variants: &rustc_index::IndexVec<rustc_target::abi::VariantIdx, clean::Item>,
count_variants: usize,
has_stripped_entries: bool,
is_non_exhaustive: bool,
enum_def_id: DefId,
) {
let should_show_c_like_variants_value = should_show_c_like_variants_value(variants);
if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) {
// If there wasn't a `where` clause, we add a whitespace.
w.write_str(" ");
Expand All @@ -1461,15 +1509,24 @@ fn render_enum_fields<'a>(
toggle_open(&mut w, format_args!("{count_variants} variants"));
}
const TAB: &str = " ";
for v in variants {
for (index, v) in variants.iter_enumerated() {
if v.is_stripped() {
continue;
}
w.write_str(TAB);
let name = v.name.unwrap();
match *v.kind {
// FIXME(#101337): Show discriminant
clean::VariantItem(ref var) => match var.kind {
clean::VariantKind::CLike => w.write_str(name.as_str()),
clean::VariantKind::CLike => display_c_like_variant(
w,
cx,
v,
var,
index,
should_show_c_like_variants_value,
enum_def_id,
),
clean::VariantKind::Tuple(ref s) => {
write!(w, "{name}({})", print_tuple_struct_fields(cx, s),);
write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s));
}
clean::VariantKind::Struct(ref s) => {
render_struct(w, v, None, None, &s.fields, TAB, false, cx);
Expand All @@ -1490,11 +1547,11 @@ fn render_enum_fields<'a>(
}
}

fn item_variants<'a>(
fn item_variants(
w: &mut Buffer,
cx: &mut Context<'_>,
it: &clean::Item,
variants: impl Iterator<Item = &'a clean::Item>,
variants: &rustc_index::IndexVec<rustc_target::abi::VariantIdx, clean::Item>,
) {
let tcx = cx.tcx();
write!(
Expand All @@ -1507,7 +1564,11 @@ fn item_variants<'a>(
document_non_exhaustive_header(it),
document_non_exhaustive(it)
);
for variant in variants {
let should_show_c_like_variants_value = should_show_c_like_variants_value(variants);
for (index, variant) in variants.iter_enumerated() {
if variant.is_stripped() {
continue;
}
let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
write!(
w,
Expand All @@ -1522,7 +1583,22 @@ fn item_variants<'a>(
it.const_stable_since(tcx),
" rightside",
);
write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
w.write_str("<h3 class=\"code-header\">");
if let clean::VariantItem(ref var) = *variant.kind &&
let clean::VariantKind::CLike = var.kind
{
display_c_like_variant(
w,
cx,
variant,
var,
index,
should_show_c_like_variants_value,
it.def_id().unwrap(),
);
} else {
w.write_str(variant.name.unwrap().as_str());
}

let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ impl FromWithTcx<clean::Discriminant> for Discriminant {
// `rustc_middle` types, not `rustc_hir`, but because JSON never inlines
// the expr is always some.
expr: disr.expr(tcx).unwrap(),
value: disr.value(tcx),
value: disr.value(tcx, false),
}
}
}
Expand Down
24 changes: 24 additions & 0 deletions tests/rustdoc/auxiliary/enum-variant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![crate_name = "bar"]

pub enum E {
A = 12,
B,
C = 1245,
}

pub enum F {
A,
B,
}

#[repr(u32)]
pub enum G {
A = 12,
B,
C(u32),
}

pub enum H {
A,
C(u32),
}
Loading