about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-05 04:16:08 +0000
committerbors <bors@rust-lang.org>2022-09-05 04:16:08 +0000
commit406e03fd02faf5cc8409a8b6b04c26990d6227e6 (patch)
treea5bc2e3620752963f8f93755d8ec114573b8c005
parent9358d09a55307e47bde0276e2390c603c35d5fb6 (diff)
parentefbd8f62ed2f9201d410721fae69e6233d385ba6 (diff)
downloadrust-406e03fd02faf5cc8409a8b6b04c26990d6227e6.tar.gz
rust-406e03fd02faf5cc8409a8b6b04c26990d6227e6.zip
Auto merge of #101386 - aDotInTheVoid:rdj-discriminant, r=GuillaumeGomez
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`
-rw-r--r--src/librustdoc/clean/mod.rs13
-rw-r--r--src/librustdoc/clean/types.rs26
-rw-r--r--src/librustdoc/clean/utils.rs34
-rw-r--r--src/librustdoc/fold.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs3
-rw-r--r--src/librustdoc/json/conversions.rs14
-rw-r--r--src/librustdoc/visit.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs21
-rw-r--r--src/test/rustdoc-json/enums/discriminant/basic.rs12
-rw-r--r--src/test/rustdoc-json/enums/discriminant/expr.rs39
-rw-r--r--src/test/rustdoc-json/enums/discriminant/limits.rs43
-rw-r--r--src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs15
-rw-r--r--src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs10
13 files changed, 213 insertions, 21 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ebf6c55ee35..be2227f47af 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -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(),
         ),
@@ -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 {
@@ -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(),
+        })),
     }
 }
 
@@ -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
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 2808b400a0b..d6bb7c6c4fc 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2098,7 +2098,7 @@ impl Enum {
 
 #[derive(Clone, Debug)]
 pub(crate) enum Variant {
-    CLike,
+    CLike(Option<Discriminant>),
     Tuple(Vec<Item>),
     Struct(VariantStruct),
 }
@@ -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)]
@@ -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)
             }
         }
     }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index ac9ab339616..a9d511ae11e 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -261,7 +261,11 @@ 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()) {
@@ -269,7 +273,7 @@ pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<St
             (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,
         }
@@ -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(),
     }
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index 6b7e67e2ce3..ed702f5c4a9 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -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(_)
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index d63d4c2d159..cfa4509428f 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -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);
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 5c0c023c64e..4d009316730 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -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()
@@ -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::*;
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index 0bb41977c97..c40274394f3 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -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(_)
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 7dcad66b1f9..d25f68b3743 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -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
@@ -308,12 +308,29 @@ 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 {
     Plain,
diff --git a/src/test/rustdoc-json/enums/discriminant/basic.rs b/src/test/rustdoc-json/enums/discriminant/basic.rs
new file mode 100644
index 00000000000..8c221615aa7
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/basic.rs
@@ -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,
+}
diff --git a/src/test/rustdoc-json/enums/discriminant/expr.rs b/src/test/rustdoc-json/enums/discriminant/expr.rs
new file mode 100644
index 00000000000..235b0b47381
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/expr.rs
@@ -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
+}
diff --git a/src/test/rustdoc-json/enums/discriminant/limits.rs b/src/test/rustdoc-json/enums/discriminant/limits.rs
new file mode 100644
index 00000000000..8df73d78d23
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/limits.rs
@@ -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,
+}
diff --git a/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs b/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
new file mode 100644
index 00000000000..3417baa0760
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
@@ -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,
+}
diff --git a/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs b/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
new file mode 100644
index 00000000000..6af944a2219
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
@@ -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,
+}