about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/clean/mod.rs14
-rw-r--r--src/librustdoc/clean/utils.rs31
2 files changed, 29 insertions, 16 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 520d60f5b9b..9cc2d9cecb7 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1988,8 +1988,9 @@ pub(crate) enum ContainerTy<'tcx> {
     Ref(ty::Region<'tcx>),
     Regular {
         ty: DefId,
+        /// The arguments *have* to contain an arg for the self type if the corresponding generics
+        /// contain a self type.
         args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>,
-        has_self: bool,
         arg: usize,
     },
 }
@@ -1998,7 +1999,7 @@ impl<'tcx> ContainerTy<'tcx> {
     fn object_lifetime_default(self, tcx: TyCtxt<'tcx>) -> ObjectLifetimeDefault<'tcx> {
         match self {
             Self::Ref(region) => ObjectLifetimeDefault::Arg(region),
-            Self::Regular { ty: container, args, has_self, arg: index } => {
+            Self::Regular { ty: container, args, arg: index } => {
                 let (DefKind::Struct
                 | DefKind::Union
                 | DefKind::Enum
@@ -2011,14 +2012,7 @@ impl<'tcx> ContainerTy<'tcx> {
                 let generics = tcx.generics_of(container);
                 debug_assert_eq!(generics.parent_count, 0);
 
-                // If the container is a trait object type, the arguments won't contain the self type but the
-                // generics of the corresponding trait will. In such a case, offset the index by one.
-                // For comparison, if the container is a trait inside a bound, the arguments do contain the
-                // self type.
-                let offset =
-                    if !has_self && generics.parent.is_none() && generics.has_self { 1 } else { 0 };
-                let param = generics.params[index + offset].def_id;
-
+                let param = generics.params[index].def_id;
                 let default = tcx.object_lifetime_default(param);
                 match default {
                     rbv::ObjectLifetimeDefault::Param(lifetime) => {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index cb5cfef6382..aadc308d5ec 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -78,7 +78,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
 pub(crate) fn clean_middle_generic_args<'tcx>(
     cx: &mut DocContext<'tcx>,
     args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>,
-    has_self: bool,
+    mut has_self: bool,
     owner: DefId,
 ) -> Vec<GenericArg> {
     if args.skip_binder().is_empty() {
@@ -86,12 +86,30 @@ pub(crate) fn clean_middle_generic_args<'tcx>(
         return Vec::new();
     }
 
-    let params = &cx.tcx.generics_of(owner).params;
+    let generics = cx.tcx.generics_of(owner);
     let mut elision_has_failed_once_before = false;
 
     let offset = if has_self { 1 } else { 0 };
     let mut clean_args = Vec::with_capacity(args.skip_binder().len().saturating_sub(offset));
 
+    // If the container is a trait object type, the arguments won't contain the self type but the
+    // generics of the corresponding trait will. In such a case, prepend a dummy self type in order
+    // to align the arguments and parameters for the iteration below and to enable us to correctly
+    // instantiate the generic parameter default later.
+    let args = if !has_self && generics.parent.is_none() && generics.has_self {
+        has_self = true;
+        // FIXME(fmease): Don't arena-allocate the args (blocked on further refactorings)!
+        args.map_bound(|args| {
+            &*cx.tcx.arena.alloc_from_iter(
+                [cx.tcx.types.trait_object_dummy_self.into()]
+                    .into_iter()
+                    .chain(args.iter().copied()),
+            )
+        })
+    } else {
+        args
+    };
+
     let clean_arg = |(index, arg): (usize, &ty::GenericArg<'tcx>)| match arg.unpack() {
         GenericArgKind::Lifetime(lt) => {
             Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
@@ -99,7 +117,7 @@ pub(crate) fn clean_middle_generic_args<'tcx>(
         GenericArgKind::Type(_) if has_self && index == 0 => None,
         GenericArgKind::Type(ty) => {
             if !elision_has_failed_once_before
-                && let Some(default) = params[index].default_value(cx.tcx)
+                && let Some(default) = generics.param_at(index, cx.tcx).default_value(cx.tcx)
             {
                 let default = args.map_bound(|args| default.instantiate(cx.tcx, args).expect_ty());
 
@@ -114,17 +132,18 @@ pub(crate) fn clean_middle_generic_args<'tcx>(
                 args.rebind(ty),
                 cx,
                 None,
-                Some(crate::clean::ContainerTy::Regular { ty: owner, args, has_self, arg: index }),
+                Some(crate::clean::ContainerTy::Regular { ty: owner, args, arg: index }),
             )))
         }
         GenericArgKind::Const(ct) => {
-            if let ty::GenericParamDefKind::Const { is_host_effect: true, .. } = params[index].kind
+            if let ty::GenericParamDefKind::Const { is_host_effect: true, .. } =
+                generics.param_at(index, cx.tcx).kind
             {
                 return None;
             }
 
             if !elision_has_failed_once_before
-                && let Some(default) = params[index].default_value(cx.tcx)
+                && let Some(default) = generics.param_at(index, cx.tcx).default_value(cx.tcx)
             {
                 let default =
                     args.map_bound(|args| default.instantiate(cx.tcx, args).expect_const());