Skip to content

Commit

Permalink
Auto merge of #101386 - aDotInTheVoid:rdj-discriminant, r=GuillaumeGomez
Browse files Browse the repository at this point in the history
Rustdoc-Json: Add enum discriminant

Does the first part of #101337, by adding it to `clean`, but doesn't change HTML output, as

1. [No Consensus has appeared on the UI for this](https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/Enum.20discriminant.20values.20in.20HTML.20output)
2. [When inlining across crates, information is lost](https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/.60clean_variant_def.20.60vs.20.60clean_variant_data.60)

JSON doesn't have either of these limitations.

r? `@GuillaumeGomez`
  • Loading branch information
bors committed Sep 5, 2022
2 parents 9358d09 + efbd8f6 commit 406e03f
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 21 deletions.
13 changes: 10 additions & 3 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1786,7 +1786,10 @@ pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {

pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
let kind = match variant.ctor_kind {
CtorKind::Const => Variant::CLike,
CtorKind::Const => Variant::CLike(match variant.discr {
ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
ty::VariantDiscr::Relative(_) => None,
}),
CtorKind::Fn => Variant::Tuple(
variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
),
Expand All @@ -1803,6 +1806,7 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont

fn clean_variant_data<'tcx>(
variant: &hir::VariantData<'tcx>,
disr_expr: &Option<hir::AnonConst>,
cx: &mut DocContext<'tcx>,
) -> Variant {
match variant {
Expand All @@ -1813,7 +1817,10 @@ fn clean_variant_data<'tcx>(
hir::VariantData::Tuple(..) => {
Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
}
hir::VariantData::Unit(..) => Variant::CLike,
hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant {
expr: Some(disr.body),
value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
})),
}
}

Expand Down Expand Up @@ -1967,7 +1974,7 @@ fn clean_maybe_renamed_item<'tcx>(
}

fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
let kind = VariantItem(clean_variant_data(&variant.data, cx));
let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
let what_rustc_thinks =
Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx);
// don't show `pub` for variants, which are always public
Expand Down
26 changes: 23 additions & 3 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2098,7 +2098,7 @@ impl Enum {

#[derive(Clone, Debug)]
pub(crate) enum Variant {
CLike,
CLike(Option<Discriminant>),
Tuple(Vec<Item>),
Struct(VariantStruct),
}
Expand All @@ -2107,11 +2107,31 @@ impl Variant {
pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
match *self {
Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
Self::CLike | Self::Tuple(_) => None,
Self::CLike(..) | Self::Tuple(_) => None,
}
}
}

#[derive(Clone, Debug)]
pub(crate) struct Discriminant {
// In the case of cross crate re-exports, we don't have the nessesary information
// to reconstruct the expression of the discriminant, only the value.
pub(super) expr: Option<BodyId>,
pub(super) value: DefId,
}

impl Discriminant {
/// Will be `None` in the case of cross-crate reexports, and may be
/// simplified
pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option<String> {
self.expr.map(|body| print_const_expr(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()
}
}

/// Small wrapper around [`rustc_span::Span`] that adds helper methods
/// and enforces calling [`rustc_span::Span::source_callsite()`].
#[derive(Copy, Clone, Debug)]
Expand Down Expand Up @@ -2338,7 +2358,7 @@ impl ConstantKind {
match *self {
ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
print_evaluated_const(tcx, def_id)
print_evaluated_const(tcx, def_id, true)
}
}
}
Expand Down
34 changes: 25 additions & 9 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,15 +261,19 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
}
}

pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
pub(crate) fn print_evaluated_const(
tcx: TyCtxt<'_>,
def_id: DefId,
underscores_and_type: bool,
) -> Option<String> {
tcx.const_eval_poly(def_id).ok().and_then(|val| {
let ty = tcx.type_of(def_id);
match (val, ty.kind()) {
(_, &ty::Ref(..)) => None,
(ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
(ConstValue::Scalar(_), _) => {
let const_ = mir::ConstantKind::from_value(val, ty);
Some(print_const_with_custom_print_scalar(tcx, const_))
Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
}
_ => None,
}
Expand Down Expand Up @@ -302,23 +306,35 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
.collect()
}

fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: mir::ConstantKind<'_>) -> String {
fn print_const_with_custom_print_scalar(
tcx: TyCtxt<'_>,
ct: mir::ConstantKind<'_>,
underscores_and_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::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => {
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
if underscores_and_type {
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
} else {
int.to_string()
}
}
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => {
let ty = tcx.lift(ct.ty()).unwrap();
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;
format!(
"{}{}",
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
i.name_str()
)
if underscores_and_type {
format!(
"{}{}",
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
i.name_str()
)
} else {
sign_extended_data.to_string()
}
}
_ => ct.to_string(),
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub(crate) trait DocFolder: Sized {
let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
VariantItem(Variant::Tuple(fields))
}
Variant::CLike => VariantItem(Variant::CLike),
Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
},
ExternCrateItem { src: _ }
| ImportItem(_)
Expand Down
3 changes: 2 additions & 1 deletion src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,8 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
let name = v.name.unwrap();
match *v.kind {
clean::VariantItem(ref var) => match var {
clean::Variant::CLike => write!(w, "{}", name),
// FIXME(#101337): Show discriminant
clean::Variant::CLike(..) => write!(w, "{}", name),
clean::Variant::Tuple(ref s) => {
write!(w, "{}(", name);
print_tuple_struct_fields(w, cx, s);
Expand Down
14 changes: 13 additions & 1 deletion src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ impl FromWithTcx<clean::Variant> for Variant {
fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
use clean::Variant::*;
match variant {
CLike => Variant::Plain,
CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
Tuple(fields) => Variant::Tuple(
fields
.into_iter()
Expand All @@ -678,6 +678,18 @@ impl FromWithTcx<clean::Variant> for Variant {
}
}

impl FromWithTcx<clean::Discriminant> for Discriminant {
fn from_tcx(disr: clean::Discriminant, tcx: TyCtxt<'_>) -> Self {
Discriminant {
// expr is only none if going throught the inlineing path, which gets
// `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),
}
}
}

impl FromWithTcx<clean::Import> for Import {
fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
use clean::ImportKind::*;
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub(crate) trait DocVisitor: Sized {
VariantItem(i) => match i {
Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
Variant::CLike => {}
Variant::CLike(_) => {}
},
ExternCrateItem { src: _ }
| ImportItem(_)
Expand Down
21 changes: 19 additions & 2 deletions src/rustdoc-json-types/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::path::PathBuf;
use serde::{Deserialize, Serialize};

/// rustdoc format-version.
pub const FORMAT_VERSION: u32 = 18;
pub const FORMAT_VERSION: u32 = 19;

/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
Expand Down Expand Up @@ -308,11 +308,28 @@ pub struct Enum {
#[serde(rename_all = "snake_case")]
#[serde(tag = "variant_kind", content = "variant_inner")]
pub enum Variant {
Plain,
Plain(Option<Discriminant>),
Tuple(Vec<Type>),
Struct(Vec<Id>),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Discriminant {
/// The expression that produced the discriminant.
///
/// Unlike `value`, this preserves the original formatting (eg suffixes,
/// hexadecimal, and underscores), making it unsuitable to be machine
/// interpreted.
///
/// In some cases, when the value is to complex, this may be `"{ _ }"`.
/// When this occurs is unstable, and may change without notice.
pub expr: String,
/// The numerical value of the discriminant. Stored as a string due to
/// JSON's poor support for large integers, and the fact that it would need
/// to store from [`i128::MIN`] to [`u128::MAX`].
pub value: String,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum StructType {
Expand Down
12 changes: 12 additions & 0 deletions src/test/rustdoc-json/enums/discriminant/basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#[repr(i8)]
pub enum Ordering {
// @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
// @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
Less = -1,
// @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
// @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
Equal = 0,
// @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
// @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
Greater = 1,
}
39 changes: 39 additions & 0 deletions src/test/rustdoc-json/enums/discriminant/expr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
pub enum Foo {
// @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
// @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
Addition = 0 + 0,
// @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
// @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
Bin = 0b1,
// @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
// @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
Oct = 0o2,
// @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
// @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
PubConst = THREE,
// @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
// @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
Hex = 0x4,
// @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
// @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
Cast = 5 as isize,
// @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
// @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
PubCall = six(),
// @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
// @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
PrivCall = seven(),
// @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
// @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
PrivConst = EIGHT,
}

pub const THREE: isize = 3;
const EIGHT: isize = 8;

pub const fn six() -> isize {
6
}
const fn seven() -> isize {
7
}
43 changes: 43 additions & 0 deletions src/test/rustdoc-json/enums/discriminant/limits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// ignore-tidy-linelength
#![feature(repr128)]
#![allow(incomplete_features)]

#[repr(u64)]
pub enum U64 {
// @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
// @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
U64Min = u64::MIN,
// @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
// @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
U64Max = u64::MAX,
}

#[repr(i64)]
pub enum I64 {
// @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
// @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
I64Min = i64::MIN,
// @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
// @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
I64Max = i64::MAX,
}

#[repr(u128)]
pub enum U128 {
// @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
// @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
U128Min = u128::MIN,
// @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
// @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
U128Max = u128::MAX,
}

#[repr(i128)]
pub enum I128 {
// @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
// @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
I128Min = i128::MIN,
// @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
// @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
I128Max = i128::MAX,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#[repr(u32)]
pub enum Foo {
// @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
// @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
Basic = 0,
// @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
// @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
Suffix = 10u32,
// @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
// @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
Underscore = 1_0_0,
// @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
// @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
SuffixUnderscore = 1_0_0_0u32,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pub enum Foo {
// @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
Has = 0,
// @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
Doesnt,
// @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
AlsoDoesnt,
// @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
AlsoHas = 44,
}

0 comments on commit 406e03f

Please sign in to comment.