about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-03 01:45:33 +0000
committerbors <bors@rust-lang.org>2023-01-03 01:45:33 +0000
commit481c9bad80754670197cf28d8c6d43825d4404f0 (patch)
tree167683988db3fd23fc0934e428ea1236c6a6a176
parent67d16171d7eebc08057a46aeed887252e7cc286b (diff)
parentd4cf00f03d35c651b7853935309342a4905943f4 (diff)
downloadrust-481c9bad80754670197cf28d8c6d43825d4404f0.tar.gz
rust-481c9bad80754670197cf28d8c6d43825d4404f0.zip
Auto merge of #106386 - compiler-errors:rollup-dxjv18b, r=compiler-errors
Rollup of 8 pull requests

Successful merges:

 - #95985 (Add PhantomData marker to Context to make Context !Send and !Sync)
 - #104298 (Add notes and examples about non-intuitive `PathBuf::set_extension` behavior)
 - #105558 (Reduce HIR debug output)
 - #106315 (Cleanup `mingw-tidy` docker job)
 - #106354 (Rustdoc-Json: Report discriminant on all kinds of enum variant.)
 - #106366 (Fix rustdoc ICE on bad typedef with mismatching types)
 - #106376 (Update books)
 - #106383 (Document some of the AST nodes)

Failed merges:

 - #106356 (clean: Remove `ctor_kind` from `VariantStruct`.)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast/src/ast.rs15
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs9
-rw-r--r--compiler/rustc_hir/src/hir.rs16
-rw-r--r--compiler/rustc_hir/src/hir_id.rs21
-rw-r--r--library/core/src/task/wake.rs5
-rw-r--r--library/core/tests/task.rs8
-rw-r--r--library/std/src/path.rs33
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile1
-rwxr-xr-xsrc/ci/run.sh4
m---------src/doc/book0
m---------src/doc/nomicon0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/librustdoc/clean/mod.rs44
-rw-r--r--src/librustdoc/clean/types.rs24
-rw-r--r--src/librustdoc/fold.rs26
-rw-r--r--src/librustdoc/html/render/print_item.rs37
-rw-r--r--src/librustdoc/json/conversions.rs17
-rw-r--r--src/librustdoc/passes/stripper.rs5
-rw-r--r--src/librustdoc/visit.rs8
-rw-r--r--src/rustdoc-json-types/lib.rs17
-rw-r--r--src/test/rustdoc-json/enums/discriminant/basic.rs12
-rw-r--r--src/test/rustdoc-json/enums/discriminant/expr.rs36
-rw-r--r--src/test/rustdoc-json/enums/discriminant/limits.rs32
-rw-r--r--src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs16
-rw-r--r--src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs8
-rw-r--r--src/test/rustdoc-json/enums/discriminant/struct.rs15
-rw-r--r--src/test/rustdoc-json/enums/discriminant/tuple.rs15
-rw-r--r--src/test/rustdoc-json/enums/field_hidden.rs4
-rw-r--r--src/test/rustdoc-json/enums/kind.rs17
-rw-r--r--src/test/rustdoc-json/enums/struct_field_hidden.rs9
-rw-r--r--src/test/rustdoc-json/enums/tuple_fields_hidden.rs69
-rw-r--r--src/test/rustdoc-json/enums/variant_struct.rs9
-rw-r--r--src/test/rustdoc-json/enums/variant_tuple_struct.rs4
-rw-r--r--src/test/rustdoc-ui/issue-105334.rs2
-rw-r--r--src/test/rustdoc-ui/issue-105334.stderr9
-rw-r--r--src/test/rustdoc-ui/issue-105737.rs4
-rw-r--r--src/test/rustdoc-ui/issue-105737.stderr12
-rw-r--r--src/test/rustdoc-ui/issue-105742.rs40
-rw-r--r--src/test/rustdoc-ui/issue-105742.stderr385
-rw-r--r--src/test/rustdoc-ui/issue-106226.rs3
-rw-r--r--src/test/rustdoc-ui/issue-106226.stderr9
-rw-r--r--src/test/rustdoc-ui/issue-96287.rs17
-rw-r--r--src/test/rustdoc-ui/issue-96287.stderr15
-rw-r--r--src/test/ui/thir-tree.stdout7
-rw-r--r--src/tools/jsondoclint/src/validator.rs36
46 files changed, 849 insertions, 226 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 9cc81f39167..c1b26ca0925 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2743,8 +2743,19 @@ impl Item {
 /// `extern` qualifier on a function item or function type.
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub enum Extern {
+    /// No explicit extern keyword was used
+    ///
+    /// E.g. `fn foo() {}`
     None,
+    /// An explicit extern keyword was used, but with implicit ABI
+    ///
+    /// E.g. `extern fn foo() {}`
+    ///
+    /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`)
     Implicit(Span),
+    /// An explicit extern keyword was used with an explicit ABI
+    ///
+    /// E.g. `extern "C" fn foo() {}`
     Explicit(StrLit, Span),
 }
 
@@ -2763,9 +2774,13 @@ impl Extern {
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct FnHeader {
+    /// The `unsafe` keyword, if any
     pub unsafety: Unsafe,
+    /// The `async` keyword, if any
     pub asyncness: Async,
+    /// The `const` keyword, if any
     pub constness: Const,
+    /// The `extern` keyword and corresponding ABI string, if any
     pub ext: Extern,
 }
 
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 05f059c89d5..c63caa06818 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -1,6 +1,7 @@
 use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
 use std::borrow::Borrow;
 use std::cmp::Ordering;
+use std::fmt::Debug;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
 
@@ -16,7 +17,7 @@ pub use index_map::SortedIndexMultiMap;
 /// stores data in a more compact way. It also supports accessing contiguous
 /// ranges of elements as a slice, and slices of already sorted elements can be
 /// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub struct SortedMap<K, V> {
     data: Vec<(K, V)>,
 }
@@ -314,5 +315,11 @@ impl<K: HashStable<CTX> + StableOrd, V: HashStable<CTX>, CTX> HashStable<CTX> fo
     }
 }
 
+impl<K: Debug, V: Debug> Debug for SortedMap<K, V> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_map().entries(self.data.iter().map(|(a, b)| (a, b))).finish()
+    }
+}
+
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index e923ec26a48..034f06bb889 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -854,7 +854,11 @@ impl fmt::Debug for OwnerNodes<'_> {
                 &self
                     .nodes
                     .iter_enumerated()
-                    .map(|(id, parented_node)| (id, parented_node.as_ref().map(|node| node.parent)))
+                    .map(|(id, parented_node)| {
+                        let parented_node = parented_node.as_ref().map(|node| node.parent);
+
+                        debug_fn(move |f| write!(f, "({id:?}, {parented_node:?})"))
+                    })
                     .collect::<Vec<_>>(),
             )
             .field("bodies", &self.bodies)
@@ -3615,3 +3619,13 @@ mod size_asserts {
     static_assert_size!(TyKind<'_>, 32);
     // tidy-alphabetical-end
 }
+
+fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
+    struct DebugFn<F>(F);
+    impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
+        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+            (self.0)(fmt)
+        }
+    }
+    DebugFn(f)
+}
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 03bcaa69468..5d05adfb556 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -1,14 +1,21 @@
 use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_span::{def_id::DefPathHash, HashStableContext};
-use std::fmt;
+use std::fmt::{self, Debug};
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable)]
 pub struct OwnerId {
     pub def_id: LocalDefId,
 }
 
+impl Debug for OwnerId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: DefId(0:1 ~ aa[7697]::{use#0})
+        Debug::fmt(&self.def_id, f)
+    }
+}
+
 impl From<OwnerId> for HirId {
     fn from(owner: OwnerId) -> HirId {
         HirId { owner, local_id: ItemLocalId::from_u32(0) }
@@ -60,7 +67,7 @@ impl<CTX: HashStableContext> ToStableHashKey<CTX> for OwnerId {
 /// the `local_id` part of the `HirId` changing, which is a very useful property in
 /// incremental compilation where we have to persist things through changes to
 /// the code base.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub struct HirId {
@@ -68,6 +75,14 @@ pub struct HirId {
     pub local_id: ItemLocalId,
 }
 
+impl Debug for HirId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Example: HirId(DefId(0:1 ~ aa[7697]::{use#0}).10)
+        // Don't use debug_tuple to always keep this on one line.
+        write!(f, "HirId({:?}.{:?})", self.owner, self.local_id)
+    }
+}
+
 impl HirId {
     /// Signal local id which should never be used.
     pub const INVALID: HirId =
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 1b7578376b4..a4425fd234a 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -181,6 +181,9 @@ pub struct Context<'a> {
     // are contravariant while return-position lifetimes are
     // covariant).
     _marker: PhantomData<fn(&'a ()) -> &'a ()>,
+    // Ensure `Context` is `!Send` and `!Sync` in order to allow
+    // for future `!Send` and / or `!Sync` fields.
+    _marker2: PhantomData<*mut ()>,
 }
 
 impl<'a> Context<'a> {
@@ -190,7 +193,7 @@ impl<'a> Context<'a> {
     #[must_use]
     #[inline]
     pub const fn from_waker(waker: &'a Waker) -> Self {
-        Context { waker, _marker: PhantomData }
+        Context { waker, _marker: PhantomData, _marker2: PhantomData }
     }
 
     /// Returns a reference to the [`Waker`] for the current task.
diff --git a/library/core/tests/task.rs b/library/core/tests/task.rs
index 56be30e9282..163b34c9648 100644
--- a/library/core/tests/task.rs
+++ b/library/core/tests/task.rs
@@ -1,4 +1,4 @@
-use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+use core::task::{Poll, RawWaker, RawWakerVTable, Waker};
 
 #[test]
 fn poll_const() {
@@ -21,9 +21,5 @@ fn waker_const() {
 
     static WAKER: Waker = unsafe { Waker::from_raw(VOID_WAKER) };
 
-    static CONTEXT: Context<'static> = Context::from_waker(&WAKER);
-
-    static WAKER_REF: &'static Waker = CONTEXT.waker();
-
-    WAKER_REF.wake_by_ref();
+    WAKER.wake_by_ref();
 }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index ef8a14be73d..19d8f1edaf4 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1414,7 +1414,8 @@ impl PathBuf {
         self.push(file_name);
     }
 
-    /// Updates [`self.extension`] to `extension`.
+    /// Updates [`self.extension`] to `Some(extension)` or to `None` if
+    /// `extension` is empty.
     ///
     /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
     /// returns `true` and updates the extension otherwise.
@@ -1422,6 +1423,20 @@ impl PathBuf {
     /// If [`self.extension`] is [`None`], the extension is added; otherwise
     /// it is replaced.
     ///
+    /// If `extension` is the empty string, [`self.extension`] will be [`None`]
+    /// afterwards, not `Some("")`.
+    ///
+    /// # Caveats
+    ///
+    /// The new `extension` may contain dots and will be used in its entirety,
+    /// but only the part after the final dot will be reflected in
+    /// [`self.extension`].
+    ///
+    /// If the file stem contains internal dots and `extension` is empty, part
+    /// of the old file stem will be considered the new [`self.extension`].
+    ///
+    /// See the examples below.
+    ///
     /// [`self.file_name`]: Path::file_name
     /// [`self.extension`]: Path::extension
     ///
@@ -1435,8 +1450,20 @@ impl PathBuf {
     /// p.set_extension("force");
     /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
     ///
-    /// p.set_extension("dark_side");
-    /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+    /// p.set_extension("dark.side");
+    /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path());
+    ///
+    /// p.set_extension("cookie");
+    /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the.dark"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
+    ///
+    /// p.set_extension("");
+    /// assert_eq!(Path::new("/feel/the"), p.as_path());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
index c340294fc73..dc0e591cad6 100644
--- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile
@@ -32,5 +32,4 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
 COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
 COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 
-ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest
diff --git a/src/ci/run.sh b/src/ci/run.sh
index b6430027750..0db9c993eec 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -184,11 +184,11 @@ if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
   $SRC/configure --set rust.parallel-compiler
 
   # Save the build metrics before we wipe the directory
-  if [ $HAS_METRICS = 1 ]; then
+  if [ "$HAS_METRICS" = 1 ]; then
     mv build/metrics.json .
   fi
   rm -rf build
-  if [ $HAS_METRICS = 1 ]; then
+  if [ "$HAS_METRICS" = 1 ]; then
     mkdir build
     mv metrics.json build
   fi
diff --git a/src/doc/book b/src/doc/book
-Subproject a60f4316ec923a5ac2ed6a2eba6960edb832d85
+Subproject 2bd5d42c9956369132228da6409f0e68da56c51
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject dd37e21ccee43918ed18a71581bb2af537ffe4f
+Subproject 8ca261268068d80c0969260fff15199bad87b58
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 995df09b65c582eb6290ab7ea5d9485983eb4c3
+Subproject 8888f9428fe9a48f31de6bd2cef9b9bf80791ed
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 8b42eb5f57d3d8ed2257a22d0e850d9db52afed
+Subproject b3e2a6e6c8a3aae5b5d950c63046f23bae07096
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 8f409965356..07a9c48365f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1853,7 +1853,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Placeholder(..) => panic!("Placeholder"),
         ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
         ty::Infer(..) => panic!("Infer"),
-        ty::Error(_) => panic!("Error"),
+        ty::Error(_) => rustc_errors::FatalError.raise(),
     }
 }
 
@@ -1949,20 +1949,28 @@ pub(crate) fn clean_field_with_def_id(
 }
 
 pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
+    let discriminant = match variant.discr {
+        ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
+        ty::VariantDiscr::Relative(_) => None,
+    };
+
     let kind = match variant.ctor_kind() {
-        Some(CtorKind::Const) => Variant::CLike(match variant.discr {
-            ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
-            ty::VariantDiscr::Relative(_) => None,
-        }),
-        Some(CtorKind::Fn) => Variant::Tuple(
+        Some(CtorKind::Const) => VariantKind::CLike,
+        Some(CtorKind::Fn) => VariantKind::Tuple(
             variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         ),
-        None => Variant::Struct(VariantStruct {
+        None => VariantKind::Struct(VariantStruct {
             ctor_kind: None,
             fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
         }),
     };
-    Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx)
+
+    Item::from_def_id_and_parts(
+        variant.def_id,
+        Some(variant.name),
+        VariantItem(Variant { kind, discriminant }),
+        cx,
+    )
 }
 
 fn clean_variant_data<'tcx>(
@@ -1970,19 +1978,23 @@ fn clean_variant_data<'tcx>(
     disr_expr: &Option<hir::AnonConst>,
     cx: &mut DocContext<'tcx>,
 ) -> Variant {
-    match variant {
-        hir::VariantData::Struct(..) => Variant::Struct(VariantStruct {
+    let discriminant = disr_expr.map(|disr| Discriminant {
+        expr: Some(disr.body),
+        value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
+    });
+
+    let kind = match variant {
+        hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
             ctor_kind: None,
             fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
         }),
         hir::VariantData::Tuple(..) => {
-            Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
+            VariantKind::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
         }
-        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(),
-        })),
-    }
+        hir::VariantData::Unit(..) => VariantKind::CLike,
+    };
+
+    Variant { discriminant, kind }
 }
 
 fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 62217df8de7..77ec0242621 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -807,8 +807,11 @@ impl ItemKind {
         match self {
             StructItem(s) => s.fields.iter(),
             UnionItem(u) => u.fields.iter(),
-            VariantItem(Variant::Struct(v)) => v.fields.iter(),
-            VariantItem(Variant::Tuple(v)) => v.iter(),
+            VariantItem(v) => match &v.kind {
+                VariantKind::CLike => [].iter(),
+                VariantKind::Tuple(t) => t.iter(),
+                VariantKind::Struct(s) => s.fields.iter(),
+            },
             EnumItem(e) => e.variants.iter(),
             TraitItem(t) => t.items.iter(),
             ImplItem(i) => i.items.iter(),
@@ -824,7 +827,6 @@ impl ItemKind {
             | TyMethodItem(_)
             | MethodItem(_, _)
             | StructFieldItem(_)
-            | VariantItem(_)
             | ForeignFunctionItem(_)
             | ForeignStaticItem(_)
             | ForeignTypeItem
@@ -2136,17 +2138,23 @@ impl Enum {
 }
 
 #[derive(Clone, Debug)]
-pub(crate) enum Variant {
-    CLike(Option<Discriminant>),
+pub(crate) struct Variant {
+    pub kind: VariantKind,
+    pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum VariantKind {
+    CLike,
     Tuple(Vec<Item>),
     Struct(VariantStruct),
 }
 
 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,
+        match &self.kind {
+            VariantKind::Struct(struct_) => Some(struct_.has_stripped_entries()),
+            VariantKind::CLike | VariantKind::Tuple(_) => None,
         }
     }
 }
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index c6f1f9de51a..656aeefb01a 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -37,17 +37,21 @@ pub(crate) trait DocFolder: Sized {
                 i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
                 ImplItem(i)
             }
-            VariantItem(i) => match i {
-                Variant::Struct(mut j) => {
-                    j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                    VariantItem(Variant::Struct(j))
-                }
-                Variant::Tuple(fields) => {
-                    let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
-                    VariantItem(Variant::Tuple(fields))
-                }
-                Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
-            },
+            VariantItem(Variant { kind, discriminant }) => {
+                let kind = match kind {
+                    VariantKind::Struct(mut j) => {
+                        j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantKind::Struct(j)
+                    }
+                    VariantKind::Tuple(fields) => {
+                        let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantKind::Tuple(fields)
+                    }
+                    VariantKind::CLike => VariantKind::CLike,
+                };
+
+                VariantItem(Variant { kind, discriminant })
+            }
             ExternCrateItem { src: _ }
             | ImportItem(_)
             | FunctionItem(_)
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index a7b57c373e3..40dfb069750 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1220,15 +1220,15 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                     w.write_str("    ");
                     let name = v.name.unwrap();
                     match *v.kind {
-                        clean::VariantItem(ref var) => match var {
-                            // FIXME(#101337): Show discriminant
-                            clean::Variant::CLike(..) => write!(w, "{}", name),
-                            clean::Variant::Tuple(ref s) => {
+                        // FIXME(#101337): Show discriminant
+                        clean::VariantItem(ref var) => match var.kind {
+                            clean::VariantKind::CLike => write!(w, "{}", name),
+                            clean::VariantKind::Tuple(ref s) => {
                                 write!(w, "{}(", name);
                                 print_tuple_struct_fields(w, cx, s);
                                 w.write_str(")");
                             }
-                            clean::Variant::Struct(ref s) => {
+                            clean::VariantKind::Struct(ref s) => {
                                 render_struct(
                                     w,
                                     v,
@@ -1286,25 +1286,28 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                 " rightside",
             );
             write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap());
-            if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
+
+            let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
+
+            if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
                 w.write_str("(");
                 print_tuple_struct_fields(w, cx, s);
                 w.write_str(")");
             }
             w.write_str("</h3></section>");
 
-            use crate::clean::Variant;
-
-            let heading_and_fields = match &*variant.kind {
-                clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
-                // Documentation on tuple variant fields is rare, so to reduce noise we only emit
-                // the section if at least one field is documented.
-                clean::VariantItem(Variant::Tuple(fields))
-                    if fields.iter().any(|f| f.doc_value().is_some()) =>
-                {
-                    Some(("Tuple Fields", fields))
+            let heading_and_fields = match &variant_data.kind {
+                clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)),
+                clean::VariantKind::Tuple(fields) => {
+                    // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+                    // the section if at least one field is documented.
+                    if fields.iter().any(|f| f.doc_value().is_some()) {
+                        Some(("Tuple Fields", fields))
+                    } else {
+                        None
+                    }
                 }
-                _ => None,
+                clean::VariantKind::CLike => None,
             };
 
             if let Some((heading, fields)) = heading_and_fields {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index d7184053c87..84af194904d 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -646,15 +646,20 @@ impl FromWithTcx<clean::Enum> for Enum {
 
 impl FromWithTcx<clean::Variant> for Variant {
     fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
-        use clean::Variant::*;
-        match variant {
-            CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
-            Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)),
-            Struct(s) => Variant::Struct {
+        use clean::VariantKind::*;
+
+        let discriminant = variant.discriminant.map(|d| d.into_tcx(tcx));
+
+        let kind = match variant.kind {
+            CLike => VariantKind::Plain,
+            Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)),
+            Struct(s) => VariantKind::Struct {
                 fields_stripped: s.has_stripped_entries(),
                 fields: ids(s.fields, tcx),
             },
-        }
+        };
+
+        Variant { kind, discriminant }
     }
 }
 
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 995fb5dcc1c..bf111133b9f 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -132,7 +132,10 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
             // implementations of traits are always public.
             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
             // Variant fields have inherited visibility
-            clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true,
+            clean::VariantItem(clean::Variant {
+                kind: clean::VariantKind::Struct(..) | clean::VariantKind::Tuple(..),
+                ..
+            }) => true,
             _ => false,
         };
 
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index d29ceead4f3..390b9436121 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -17,10 +17,10 @@ pub(crate) trait DocVisitor: Sized {
             EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
             TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
             ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
-            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(_) => {}
+            VariantItem(i) => match &i.kind {
+                VariantKind::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+                VariantKind::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+                VariantKind::CLike => {}
             },
             ExternCrateItem { src: _ }
             | ImportItem(_)
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 1ee96b8231c..387d5787dfc 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 = 23;
+pub const FORMAT_VERSION: u32 = 24;
 
 /// 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
@@ -334,10 +334,17 @@ pub struct Enum {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct Variant {
+    /// Whether the variant is plain, a tuple-like, or struct-like. Contains the fields.
+    pub kind: VariantKind,
+    /// The discriminant, if explicitly specified.
+    pub discriminant: Option<Discriminant>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
-#[serde(tag = "variant_kind", content = "variant_inner")]
-pub enum Variant {
-    /// A variant with no parentheses, and possible discriminant.
+pub enum VariantKind {
+    /// A variant with no parentheses
     ///
     /// ```rust
     /// enum Demo {
@@ -345,7 +352,7 @@ pub enum Variant {
     ///     PlainWithDiscriminant = 1,
     /// }
     /// ```
-    Plain(Option<Discriminant>),
+    Plain,
     /// A variant with unnamed fields.
     ///
     /// Unlike most of json, `#[doc(hidden)]` fields will be given as `None`
diff --git a/src/test/rustdoc-json/enums/discriminant/basic.rs b/src/test/rustdoc-json/enums/discriminant/basic.rs
index 8c221615aa7..06906df3b2c 100644
--- a/src/test/rustdoc-json/enums/discriminant/basic.rs
+++ b/src/test/rustdoc-json/enums/discriminant/basic.rs
@@ -1,12 +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"'
+    // @is "$.index[*][?(@.name=='Less')].inner.discriminant.expr" '"-1"'
+    // @is "$.index[*][?(@.name=='Less')].inner.discriminant.value" '"-1"'
     Less = -1,
-    // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
-    // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
+    // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.expr" '"0"'
+    // @is "$.index[*][?(@.name=='Equal')].inner.discriminant.value" '"0"'
     Equal = 0,
-    // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
-    // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
+    // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.expr" '"1"'
+    // @is "$.index[*][?(@.name=='Greater')].inner.discriminant.value" '"1"'
     Greater = 1,
 }
diff --git a/src/test/rustdoc-json/enums/discriminant/expr.rs b/src/test/rustdoc-json/enums/discriminant/expr.rs
index 235b0b47381..e639965e79b 100644
--- a/src/test/rustdoc-json/enums/discriminant/expr.rs
+++ b/src/test/rustdoc-json/enums/discriminant/expr.rs
@@ -1,30 +1,30 @@
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='Addition')].inner.discriminant.expr" '"{ _ }"'
     Addition = 0 + 0,
-    // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
-    // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
+    // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.value" '"1"'
+    // @is "$.index[*][?(@.name=='Bin')].inner.discriminant.expr" '"0b1"'
     Bin = 0b1,
-    // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
-    // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
+    // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.value" '"2"'
+    // @is "$.index[*][?(@.name=='Oct')].inner.discriminant.expr" '"0o2"'
     Oct = 0o2,
-    // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
-    // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
+    // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.value" '"3"'
+    // @is "$.index[*][?(@.name=='PubConst')].inner.discriminant.expr" '"THREE"'
     PubConst = THREE,
-    // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
-    // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
+    // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.value" '"4"'
+    // @is "$.index[*][?(@.name=='Hex')].inner.discriminant.expr" '"0x4"'
     Hex = 0x4,
-    // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
-    // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.value" '"5"'
+    // @is "$.index[*][?(@.name=='Cast')].inner.discriminant.expr" '"{ _ }"'
     Cast = 5 as isize,
-    // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
-    // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.value" '"6"'
+    // @is "$.index[*][?(@.name=='PubCall')].inner.discriminant.expr" '"{ _ }"'
     PubCall = six(),
-    // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
-    // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
+    // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.value" '"7"'
+    // @is "$.index[*][?(@.name=='PrivCall')].inner.discriminant.expr" '"{ _ }"'
     PrivCall = seven(),
-    // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
-    // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
+    // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.value" '"8"'
+    // @is "$.index[*][?(@.name=='PrivConst')].inner.discriminant.expr" '"EIGHT"'
     PrivConst = EIGHT,
 }
 
diff --git a/src/test/rustdoc-json/enums/discriminant/limits.rs b/src/test/rustdoc-json/enums/discriminant/limits.rs
index 8df73d78d23..e56d5594f2f 100644
--- a/src/test/rustdoc-json/enums/discriminant/limits.rs
+++ b/src/test/rustdoc-json/enums/discriminant/limits.rs
@@ -4,40 +4,40 @@
 
 #[repr(u64)]
 pub enum U64 {
-    // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
-    // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
+    // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='U64Min')].inner.discriminant.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"'
+    // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.value" '"18446744073709551615"'
+    // @is "$.index[*][?(@.name=='U64Max')].inner.discriminant.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"'
+    // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.value" '"-9223372036854775808"'
+    // @is "$.index[*][?(@.name=='I64Min')].inner.discriminant.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"'
+    // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.value" '"9223372036854775807"'
+    // @is "$.index[*][?(@.name=='I64Max')].inner.discriminant.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"'
+    // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='U128Min')].inner.discriminant.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"'
+    // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.value" '"340282366920938463463374607431768211455"'
+    // @is "$.index[*][?(@.name=='U128Max')].inner.discriminant.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"'
+    // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.value" '"-170141183460469231731687303715884105728"'
+    // @is "$.index[*][?(@.name=='I128Min')].inner.discriminant.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"'
+    // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.value" '"170141183460469231731687303715884105727"'
+    // @is "$.index[*][?(@.name=='I128Max')].inner.discriminant.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
index 3417baa0760..6889b305ffb 100644
--- a/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
+++ b/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs
@@ -1,15 +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"'
+    // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.value" '"0"'
+    // @is "$.index[*][?(@.name=='Basic')].inner.discriminant.expr" '"0"'
     Basic = 0,
-    // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
-    // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
+    // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.value" '"10"'
+    // @is "$.index[*][?(@.name=='Suffix')].inner.discriminant.expr" '"10u32"'
     Suffix = 10u32,
-    // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
-    // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
+    // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.value" '"100"'
+    // @is "$.index[*][?(@.name=='Underscore')].inner.discriminant.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"'
+    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.value" '"1000"'
+    // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.discriminant.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
index 6af944a2219..6a4f54de617 100644
--- a/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
+++ b/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs
@@ -1,10 +1,10 @@
 pub enum Foo {
-    // @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
+    // @is "$.index[*][?(@.name=='Has')].inner.discriminant" '{"expr":"0", "value":"0"}'
     Has = 0,
-    // @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='Doesnt')].inner.discriminant" null
     Doesnt,
-    // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.discriminant" null
     AlsoDoesnt,
-    // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
+    // @is "$.index[*][?(@.name=='AlsoHas')].inner.discriminant" '{"expr":"44", "value":"44"}'
     AlsoHas = 44,
 }
diff --git a/src/test/rustdoc-json/enums/discriminant/struct.rs b/src/test/rustdoc-json/enums/discriminant/struct.rs
new file mode 100644
index 00000000000..e91a632a3b3
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/struct.rs
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#[repr(i32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
+pub enum Foo {
+    // @is    "$.index[*][?(@.name=='Struct')].inner.discriminant" null
+    // @count "$.index[*][?(@.name=='Struct')].inner.kind.struct.fields[*]" 0
+    Struct {},
+    // @is    "$.index[*][?(@.name=='StructWithDiscr')].inner.discriminant" '{"expr": "42", "value": "42"}'
+    // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.kind.struct.fields[*]" 1
+    StructWithDiscr { x: i32 } = 42,
+    // @is    "$.index[*][?(@.name=='StructWithHexDiscr')].inner.discriminant"  '{"expr": "0x42", "value": "66"}'
+    // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.kind.struct.fields[*]" 2
+    StructWithHexDiscr { x: i32, y: bool } = 0x42,
+}
diff --git a/src/test/rustdoc-json/enums/discriminant/tuple.rs b/src/test/rustdoc-json/enums/discriminant/tuple.rs
new file mode 100644
index 00000000000..b94d5739eab
--- /dev/null
+++ b/src/test/rustdoc-json/enums/discriminant/tuple.rs
@@ -0,0 +1,15 @@
+// ignore-tidy-linelength
+
+#[repr(u32)]
+// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
+pub enum Foo {
+    // @is    "$.index[*][?(@.name=='Tuple')].inner.discriminant" null
+    // @count "$.index[*][?(@.name=='Tuple')].inner.kind.tuple[*]" 0
+    Tuple(),
+    // @is    "$.index[*][?(@.name=='TupleWithDiscr')].inner.discriminant" '{"expr": "1", "value": "1"}'
+    // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.kind.tuple[*]" 1
+    TupleWithDiscr(i32) = 1,
+    // @is    "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.discriminant" '{"expr": "0b10", "value": "2"}'
+    // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.kind.tuple[*]" 2
+    TupleWithBinDiscr(i32, i32) = 0b10,
+}
diff --git a/src/test/rustdoc-json/enums/field_hidden.rs b/src/test/rustdoc-json/enums/field_hidden.rs
index e6310cc3b99..78a05431472 100644
--- a/src/test/rustdoc-json/enums/field_hidden.rs
+++ b/src/test/rustdoc-json/enums/field_hidden.rs
@@ -5,8 +5,8 @@
 
 // @has "$.index[*][?(@.name=='ParseError')]"
 // @has "$.index[*][?(@.name=='UnexpectedEndTag')]"
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_kind" '"tuple"'
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.kind.tuple" [null]
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.discriminant" null
 
 pub enum ParseError {
     UnexpectedEndTag(#[doc(hidden)] u32),
diff --git a/src/test/rustdoc-json/enums/kind.rs b/src/test/rustdoc-json/enums/kind.rs
index e9ea3ae23c2..1787a859c8b 100644
--- a/src/test/rustdoc-json/enums/kind.rs
+++ b/src/test/rustdoc-json/enums/kind.rs
@@ -5,27 +5,22 @@
 
 pub enum Foo {
     // @set Unit = "$.index[*][?(@.name=='Unit')].id"
-    // @is "$.index[*][?(@.name=='Unit')].inner.variant_kind" '"plain"'
-    // @is "$.index[*][?(@.name=='Unit')].inner.variant_inner" null
+    // @is "$.index[*][?(@.name=='Unit')].inner.kind" '"plain"'
     Unit,
     // @set Named = "$.index[*][?(@.name=='Named')].id"
-    // @is "$.index[*][?(@.name=='Named')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='Named')].inner.variant_inner" '{"fields": [], "fields_stripped": false}'
+    // @is "$.index[*][?(@.name=='Named')].inner.kind.struct" '{"fields": [], "fields_stripped": false}'
     Named {},
     // @set Tuple = "$.index[*][?(@.name=='Tuple')].id"
-    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_kind" '"tuple"'
-    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_inner" []
+    // @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" []
     Tuple(),
     // @set NamedField = "$.index[*][?(@.name=='NamedField')].id"
     // @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id"
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields[*]" $x
-    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields_stripped" false
+    // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields[*]" $x
+    // @is "$.index[*][?(@.name=='NamedField')].inner.kind.struct.fields_stripped" false
     NamedField { x: i32 },
     // @set TupleField = "$.index[*][?(@.name=='TupleField')].id"
-    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_kind" '"tuple"'
     // @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id"
-    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_inner[*]" $tup_field
+    // @is "$.index[*][?(@.name=='TupleField')].inner.kind.tuple[*]" $tup_field
     TupleField(i32),
 }
 
diff --git a/src/test/rustdoc-json/enums/struct_field_hidden.rs b/src/test/rustdoc-json/enums/struct_field_hidden.rs
index f612a34a492..de939cde2e7 100644
--- a/src/test/rustdoc-json/enums/struct_field_hidden.rs
+++ b/src/test/rustdoc-json/enums/struct_field_hidden.rs
@@ -9,9 +9,8 @@ pub enum Foo {
         // @set y = "$.index[*][?(@.name=='y')].id"
         y: i32,
     },
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_kind" '"struct"'
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields_stripped" true
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[0]" $b
-    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[1]" $y
-    // @count "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[*]" 2
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields_stripped" true
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[0]" $b
+    // @is "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[1]" $y
+    // @count "$.index[*][?(@.name=='Variant')].inner.kind.struct.fields[*]" 2
 }
diff --git a/src/test/rustdoc-json/enums/tuple_fields_hidden.rs b/src/test/rustdoc-json/enums/tuple_fields_hidden.rs
index f546eaa0d17..70bfbb81826 100644
--- a/src/test/rustdoc-json/enums/tuple_fields_hidden.rs
+++ b/src/test/rustdoc-json/enums/tuple_fields_hidden.rs
@@ -14,61 +14,50 @@
 // @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id"
 
 pub enum EnumWithStrippedTupleVariants {
-    // @is    "$.index[*][?(@.name=='None')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='None')].inner.variant_inner[*]" 0
+    // @count "$.index[*][?(@.name=='None')].inner.kind.tuple[*]" 0
     None(),
 
-    // @is    "$.index[*][?(@.name=='One')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='One')].inner.variant_inner[*]" 1
-    // @is    "$.index[*][?(@.name=='One')].inner.variant_inner[0]" $1.1.0
+    // @count "$.index[*][?(@.name=='One')].inner.kind.tuple[*]" 1
+    // @is    "$.index[*][?(@.name=='One')].inner.kind.tuple[0]" $1.1.0
     One(/** 1.1.0*/ bool),
-    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[*]" 1
-    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[0]" null
+    // @count "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[*]" 1
+    // @is    "$.index[*][?(@.name=='OneHidden')].inner.kind.tuple[0]" null
     OneHidden(#[doc(hidden)] bool),
 
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Two')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[0]" $2.1.0
-    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[1]" $2.1.1
+    // @count "$.index[*][?(@.name=='Two')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='Two')].inner.kind.tuple[0]" $2.1.0
+    // @is    "$.index[*][?(@.name=='Two')].inner.kind.tuple[1]" $2.1.1
     Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool),
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[1]" $2.2.1
+    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.kind.tuple[1]" $2.2.1
     TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool),
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[0]" $2.3.0
-    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[1]" null
+    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[0]" $2.3.0
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.kind.tuple[1]" null
     TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool),
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[*]" 2
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[1]" null
+    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.kind.tuple[1]" null
     TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool),
 
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three1')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[0]" null
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[1]" $3.1.1
-    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[2]" $3.1.2
+    // @count "$.index[*][?(@.name=='Three1')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[0]" null
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[1]" $3.1.1
+    // @is    "$.index[*][?(@.name=='Three1')].inner.kind.tuple[2]" $3.1.2
     Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool),
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three2')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[0]" $3.2.0
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[1]" null
-    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[2]" $3.2.2
+    // @count "$.index[*][?(@.name=='Three2')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[0]" $3.2.0
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[1]" null
+    // @is    "$.index[*][?(@.name=='Three2')].inner.kind.tuple[2]" $3.2.2
     Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool),
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_kind" '"tuple"'
-    // @count "$.index[*][?(@.name=='Three3')].inner.variant_inner[*]" 3
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[0]" $3.3.0
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[1]" $3.3.1
-    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[2]" null
+    // @count "$.index[*][?(@.name=='Three3')].inner.kind.tuple[*]" 3
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[0]" $3.3.0
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[1]" $3.3.1
+    // @is    "$.index[*][?(@.name=='Three3')].inner.kind.tuple[2]" null
     Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool),
 }
 
-
 // @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"'
 // @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"'
 // @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"'
diff --git a/src/test/rustdoc-json/enums/variant_struct.rs b/src/test/rustdoc-json/enums/variant_struct.rs
index 23b854d8d17..bc870c502a0 100644
--- a/src/test/rustdoc-json/enums/variant_struct.rs
+++ b/src/test/rustdoc-json/enums/variant_struct.rs
@@ -1,11 +1,10 @@
 // @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
 // @is "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
 pub enum EnumStruct {
-    // @is "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
     // @is "$.index[*][?(@.name=='x')].kind" \"struct_field\"
+    // @set x = "$.index[*][?(@.name=='x')].id"
     // @is "$.index[*][?(@.name=='y')].kind" \"struct_field\"
-    VariantS {
-        x: u32,
-        y: String,
-    },
+    // @set y = "$.index[*][?(@.name=='y')].id"
+    // @ismany "$.index[*][?(@.name=='VariantS')].inner.kind.struct.fields[*]" $x $y
+    VariantS { x: u32, y: String },
 }
diff --git a/src/test/rustdoc-json/enums/variant_tuple_struct.rs b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
index b71ec47a804..d1207bbfb18 100644
--- a/src/test/rustdoc-json/enums/variant_tuple_struct.rs
+++ b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
@@ -1,8 +1,10 @@
 // @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
 // @is "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
 pub enum EnumTupleStruct {
-    // @is "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
     // @is "$.index[*][?(@.name=='0')].kind" \"struct_field\"
+    // @set f0 = "$.index[*][?(@.name=='0')].id"
     // @is "$.index[*][?(@.name=='1')].kind" \"struct_field\"
+    // @set f1 = "$.index[*][?(@.name=='1')].id"
+    // @ismany "$.index[*][?(@.name=='VariantA')].inner.kind.tuple[*]" $f0 $f1
     VariantA(u32, String),
 }
diff --git a/src/test/rustdoc-ui/issue-105334.rs b/src/test/rustdoc-ui/issue-105334.rs
new file mode 100644
index 00000000000..ee1adc6a029
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105334.rs
@@ -0,0 +1,2 @@
+impl Vec< br##"*.."## > {}
+//~^ ERROR
diff --git a/src/test/rustdoc-ui/issue-105334.stderr b/src/test/rustdoc-ui/issue-105334.stderr
new file mode 100644
index 00000000000..e163bb4db9e
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105334.stderr
@@ -0,0 +1,9 @@
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-105334.rs:1:11
+   |
+LL | impl Vec< br##"*.."## > {}
+   |           ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/rustdoc-ui/issue-105737.rs b/src/test/rustdoc-ui/issue-105737.rs
new file mode 100644
index 00000000000..154f069d8ff
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105737.rs
@@ -0,0 +1,4 @@
+impl Vec<lol> {}
+//~^ ERROR
+
+pub fn lol() {}
diff --git a/src/test/rustdoc-ui/issue-105737.stderr b/src/test/rustdoc-ui/issue-105737.stderr
new file mode 100644
index 00000000000..2dd9beb17da
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105737.stderr
@@ -0,0 +1,12 @@
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-105737.rs:1:10
+   |
+LL | impl Vec<lol> {}
+   |          ^^^
+   |
+   = help: `lol` is a function item, not a type
+   = help: function item types cannot be named directly
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0747`.
diff --git a/src/test/rustdoc-ui/issue-105742.rs b/src/test/rustdoc-ui/issue-105742.rs
new file mode 100644
index 00000000000..cb1de7433cf
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105742.rs
@@ -0,0 +1,40 @@
+// compile-flags: -Znormalize-docs
+
+use std::ops::Index;
+
+pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+    let _ = s;
+}
+
+pub trait SVec: Index<
+    <Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+    Output = <Index<<Self as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+    Output = <Self as SVec>::Item> as SVec>::Item,
+//~^ ERROR
+//~^^ ERROR
+//~^^^ ERROR
+//~^^^^ ERROR
+//~^^^^^ ERROR
+//~^^^^^^ ERROR
+//~^^^^^^^ ERROR
+//~^^^^^^^^ ERROR
+> {
+    type Item<'a, T>;
+
+    fn len(&self) -> <Self as SVec>::Item;
+    //~^ ERROR
+    //~^^ ERROR
+    //~^^^ ERROR
+    //~^^^^ ERROR
+}
diff --git a/src/test/rustdoc-ui/issue-105742.stderr b/src/test/rustdoc-ui/issue-105742.stderr
new file mode 100644
index 00000000000..cc101b7ff37
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-105742.stderr
@@ -0,0 +1,385 @@
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     <Self as SVec>::Item<'a>,
+   |                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     <Self as SVec>::Item<T>,
+   |                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<'a>,
+   |                                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<T>,
+   |                                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+   |                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item<T>> as SVec>::Item,
+   |                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+   |                                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
+   |                                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:5:40
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                                        ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<'_> = T, Output = T>) {
+   |                                        ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:5:40
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                                        ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<T> = T, Output = T>) {
+   |                                        ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     <Self as SVec>::Item<'a>,
+   |                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:13:21
+   |
+LL |     <Self as SVec>::Item,
+   |                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     <Self as SVec>::Item<T>,
+   |                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<'a>,
+   |                                     ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:18:37
+   |
+LL |     Output = <Index<<Self as SVec>::Item,
+   |                                     ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Index<<Self as SVec>::Item<T>,
+   |                                     ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item<'a>> as SVec>::Item,
+   |                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:30
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item<T>> as SVec>::Item,
+   |                              ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<'a>,
+   |                                              ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:23:46
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item,
+   |                                              ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     Output = <Self as SVec>::Item> as SVec>::Item<T>,
+   |                                              ~~~~~~~
+
+error[E0038]: the trait `SVec` cannot be made into an object
+  --> $DIR/issue-105742.rs:5:31
+   |
+LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-105742.rs:12:17
+   |
+LL |    pub trait SVec: Index<
+   |  ____________----__^
+   | |            |
+   | |            this trait cannot be made into an object...
+LL | |      <Self as SVec>::Item,
+LL | |
+LL | |
+...  |
+LL | |/     Output = <Index<<Self as SVec>::Item,
+LL | ||
+LL | ||
+LL | ||
+LL | ||
+LL | ||     Output = <Self as SVec>::Item> as SVec>::Item,
+   | ||_________________________________________________^ ...because it uses `Self` as a type parameter
+...  |
+LL | |
+LL | |  > {
+   | |__^ ...because it uses `Self` as a type parameter
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<'_>;
+   |                                      ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<T>;
+   |                                      ~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<'_>;
+   |                                      ~~~~~~~~
+
+error[E0107]: missing generics for associated type `SVec::Item`
+  --> $DIR/issue-105742.rs:35:38
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item;
+   |                                      ^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-105742.rs:33:10
+   |
+LL |     type Item<'a, T>;
+   |          ^^^^     -
+help: add missing generic argument
+   |
+LL |     fn len(&self) -> <Self as SVec>::Item<T>;
+   |                                      ~~~~~~~
+
+error: aborting due to 23 previous errors
+
+Some errors have detailed explanations: E0038, E0107.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/rustdoc-ui/issue-106226.rs b/src/test/rustdoc-ui/issue-106226.rs
new file mode 100644
index 00000000000..71b497a9adc
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-106226.rs
@@ -0,0 +1,3 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/106226>.
+type F = [_; ()];
+//~^ ERROR
diff --git a/src/test/rustdoc-ui/issue-106226.stderr b/src/test/rustdoc-ui/issue-106226.stderr
new file mode 100644
index 00000000000..2beffbc125b
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-106226.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-106226.rs:2:14
+   |
+LL | type F = [_; ()];
+   |              ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/rustdoc-ui/issue-96287.rs b/src/test/rustdoc-ui/issue-96287.rs
new file mode 100644
index 00000000000..8d8b4456e63
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-96287.rs
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+pub trait TraitWithAssoc {
+    type Assoc;
+}
+
+pub type Foo<V> = impl Trait<V::Assoc>;
+//~^ ERROR
+//~^^ ERROR
+
+pub trait Trait<U> {}
+
+impl<W> Trait<W> for () {}
+
+pub fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> {
+    ()
+}
diff --git a/src/test/rustdoc-ui/issue-96287.stderr b/src/test/rustdoc-ui/issue-96287.stderr
new file mode 100644
index 00000000000..0236b9fe647
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-96287.stderr
@@ -0,0 +1,15 @@
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/src/test/ui/thir-tree.stdout b/src/test/ui/thir-tree.stdout
index 7fb90581f8a..4b6915f7715 100644
--- a/src/test/ui/thir-tree.stdout
+++ b/src/test/ui/thir-tree.stdout
@@ -32,12 +32,7 @@ Thir {
             kind: Scope {
                 region_scope: Node(2),
                 lint_level: Explicit(
-                    HirId {
-                        owner: OwnerId {
-                            def_id: DefId(0:3 ~ thir_tree[8f1d]::main),
-                        },
-                        local_id: 2,
-                    },
+                    HirId(DefId(0:3 ~ thir_tree[8f1d]::main).2),
                 ),
                 value: e0,
             },
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index e15f5fe3ccc..291d02d67bd 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -5,7 +5,7 @@ use rustdoc_json_types::{
     Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
     GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Module, OpaqueTy, Path,
     Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
-    TypeBindingKind, Typedef, Union, Variant, WherePredicate,
+    TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
 };
 
 use crate::{item_kind::Kind, Error, ErrorKind};
@@ -140,24 +140,24 @@ impl<'a> Validator<'a> {
     }
 
     fn check_variant(&mut self, x: &'a Variant, id: &'a Id) {
-        match x {
-            Variant::Plain(discr) => {
-                if let Some(discr) = discr {
-                    if let (Err(_), Err(_)) =
-                        (discr.value.parse::<i128>(), discr.value.parse::<u128>())
-                    {
-                        self.fail(
-                            id,
-                            ErrorKind::Custom(format!(
-                                "Failed to parse discriminant value `{}`",
-                                discr.value
-                            )),
-                        );
-                    }
-                }
+        let Variant { kind, discriminant } = x;
+
+        if let Some(discr) = discriminant {
+            if let (Err(_), Err(_)) = (discr.value.parse::<i128>(), discr.value.parse::<u128>()) {
+                self.fail(
+                    id,
+                    ErrorKind::Custom(format!(
+                        "Failed to parse discriminant value `{}`",
+                        discr.value
+                    )),
+                );
             }
-            Variant::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
-            Variant::Struct { fields, fields_stripped: _ } => {
+        }
+
+        match kind {
+            VariantKind::Plain => {}
+            VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
+            VariantKind::Struct { fields, fields_stripped: _ } => {
                 fields.iter().for_each(|f| self.add_field_id(f))
             }
         }