about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2023-08-27 17:23:10 +0200
committerMark Rousskov <mark.simulacrum@gmail.com>2023-09-12 10:56:04 -0400
commit7eed169745cf7d7316dd06403b1de4c987e54b95 (patch)
treebaab99c883d0e5a8029338d36142c55045af4003
parent61d4817d5ff01953a170e6ed11ac678c1c9763c8 (diff)
downloadrust-7eed169745cf7d7316dd06403b1de4c987e54b95.tar.gz
rust-7eed169745cf7d7316dd06403b1de4c987e54b95.zip
rustdoc: correctly deal with self ty params when eliding default object lifetimes
-rw-r--r--src/librustdoc/clean/mod.rs34
-rw-r--r--src/librustdoc/clean/utils.rs19
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs19
-rw-r--r--tests/rustdoc/inline_cross/dyn_trait.rs15
4 files changed, 65 insertions, 22 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0182d50773d..8ad1ed09597 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -167,8 +167,7 @@ fn clean_generic_bound<'tcx>(
             let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(cx.tcx, def_id));
 
             let generic_args = clean_generic_args(generic_args, cx);
-            let GenericArgs::AngleBracketed { bindings, .. } = generic_args
-            else {
+            let GenericArgs::AngleBracketed { bindings, .. } = generic_args else {
                 bug!("clean: parenthesized `GenericBound::LangItemTrait`");
             };
 
@@ -1818,33 +1817,46 @@ fn can_elide_trait_object_lifetime_bound<'tcx>(
 #[derive(Debug)]
 pub(crate) enum ContainerTy<'tcx> {
     Ref(ty::Region<'tcx>),
-    Regular { ty: DefId, substs: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, arg: usize },
+    Regular {
+        ty: DefId,
+        args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>,
+        has_self: bool,
+        arg: usize,
+    },
 }
 
 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, substs, arg: index } => {
+            Self::Regular { ty: container, args, has_self, arg: index } => {
                 let (DefKind::Struct
                 | DefKind::Union
                 | DefKind::Enum
-                | DefKind::TyAlias
-                | DefKind::Trait
-                | DefKind::AssocTy
-                | DefKind::Variant) = tcx.def_kind(container)
+                | DefKind::TyAlias { .. }
+                | DefKind::Trait) = tcx.def_kind(container)
                 else {
                     return ObjectLifetimeDefault::Empty;
                 };
 
                 let generics = tcx.generics_of(container);
-                let param = generics.params[index].def_id;
-                let default = tcx.object_lifetime_default(param);
+                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 default = tcx.object_lifetime_default(param);
                 match default {
                     rbv::ObjectLifetimeDefault::Param(lifetime) => {
+                        // The index is relative to the parent generics but since we don't have any,
+                        // we don't need to translate it.
                         let index = generics.param_def_id_to_index[&lifetime];
-                        let arg = substs.skip_binder()[index as usize].expect_region();
+                        let arg = args.skip_binder()[index as usize].expect_region();
                         ObjectLifetimeDefault::Arg(arg)
                     }
                     rbv::ObjectLifetimeDefault::Empty => ObjectLifetimeDefault::Empty,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index f375f0efbd1..b786ecbe38f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -54,8 +54,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
     let primitives = local_crate.primitives(cx.tcx);
     let keywords = local_crate.keywords(cx.tcx);
     {
-        let ItemKind::ModuleItem(ref mut m) = *module.kind
-        else { unreachable!() };
+        let ItemKind::ModuleItem(ref mut m) = *module.kind else { unreachable!() };
         m.items.extend(primitives.iter().map(|&(def_id, prim)| {
             Item::from_def_id_and_parts(
                 def_id,
@@ -74,18 +73,15 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
 
 pub(crate) fn substs_to_args<'tcx>(
     cx: &mut DocContext<'tcx>,
-    substs: ty::Binder<'tcx, &'tcx [ty::subst::GenericArg<'tcx>]>,
-    mut skip_first: bool,
+    args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>,
+    has_self: bool,
     container: Option<DefId>,
 ) -> Vec<GenericArg> {
+    let mut skip_first = has_self;
     let mut ret_val =
-        Vec::with_capacity(substs.skip_binder().len().saturating_sub(if skip_first {
-            1
-        } else {
-            0
-        }));
+        Vec::with_capacity(args.skip_binder().len().saturating_sub(if skip_first { 1 } else { 0 }));
 
-    ret_val.extend(substs.iter().enumerate().filter_map(|(index, kind)| {
+    ret_val.extend(args.iter().enumerate().filter_map(|(index, kind)| {
         match kind.skip_binder().unpack() {
             GenericArgKind::Lifetime(lt) => {
                 Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
@@ -100,7 +96,8 @@ pub(crate) fn substs_to_args<'tcx>(
                 None,
                 container.map(|container| crate::clean::ContainerTy::Regular {
                     ty: container,
-                    substs,
+                    args,
+                    has_self,
                     arg: index,
                 }),
             ))),
diff --git a/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs b/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs
index 644d0699e9d..df88530071b 100644
--- a/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/dyn_trait.rs
@@ -65,3 +65,22 @@ pub trait HigherRankedBoundTrait1<'e> where for<'l> Self: 'e + 'l {}
 pub trait AmbiguousBoundTrait<'a, 'b>: 'a + 'b {}
 
 pub struct AmbiguousBoundWrapper<'a, 'b, T: ?Sized + 'a + 'b>(&'a T, &'b T);
+
+// Trait objects inside of another trait object, a trait bound or an associated type.
+
+pub trait Inner {}
+pub trait Outer<T: ?Sized> {}
+pub trait Base {
+    type Type<T: ?Sized>;
+}
+impl Base for () {
+    type Type<T: ?Sized> = ();
+}
+
+pub type NestedTraitObjects = dyn Outer<dyn Inner>;
+
+pub fn apit_rpit(o: impl Outer<dyn Inner>) -> impl Outer<dyn Inner> {
+    o
+}
+
+pub type AssocTy = <() as Base>::Type<dyn Inner>;
diff --git a/tests/rustdoc/inline_cross/dyn_trait.rs b/tests/rustdoc/inline_cross/dyn_trait.rs
index 1de01af83d1..679972f035a 100644
--- a/tests/rustdoc/inline_cross/dyn_trait.rs
+++ b/tests/rustdoc/inline_cross/dyn_trait.rs
@@ -128,3 +128,18 @@ pub use dyn_trait::BareAmbiguousBoundEarly1;
 // @has user/type.BareAmbiguousBoundStatic.html
 // @has - '//*[@class="rust item-decl"]//code' "dyn AmbiguousBoundTrait<'o, 'o> + 'static;"
 pub use dyn_trait::BareAmbiguousBoundStatic;
+
+// Regression test for issue #115179:
+
+// @has user/type.NestedTraitObjects.html
+// @has - '//*[@class="rust item-decl"]//code' "dyn Outer<dyn Inner>;"
+pub use dyn_trait::NestedTraitObjects;
+
+// @has user/fn.apit_rpit.html
+// @has - '//pre[@class="rust item-decl"]' \
+//     "apit_rpit(o: impl Outer<dyn Inner>) -> impl Outer<dyn Inner>"
+pub use dyn_trait::apit_rpit;
+
+// @has user/type.AssocTy.html
+// @has - '//*[@class="rust item-decl"]//code' "<() as Base>::Type<dyn Inner>"
+pub use dyn_trait::AssocTy;