From f5a68f63aacab357e89070305cccbea5a82ba8f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 27 Aug 2023 17:23:10 +0200 Subject: [PATCH] rustdoc: correctly deal with self ty params when eliding default object lifetimes --- src/librustdoc/clean/mod.rs | 27 ++++++++++++++----- src/librustdoc/clean/utils.rs | 4 ++- .../inline_cross/auxiliary/dyn_trait.rs | 19 +++++++++++++ tests/rustdoc/inline_cross/dyn_trait.rs | 15 +++++++++++ 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1e85284371db5..b584c32a4c7db 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1959,31 +1959,44 @@ fn can_elide_trait_object_lifetime_bound<'tcx>( #[derive(Debug)] pub(crate) enum ContainerTy<'tcx> { Ref(ty::Region<'tcx>), - Regular { ty: DefId, args: 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, args, 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::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 = args.skip_binder()[index as usize].expect_region(); ObjectLifetimeDefault::Arg(arg) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 80a7a33d2bda2..a86bbcc7679b3 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -77,9 +77,10 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { pub(crate) fn ty_args_to_args<'tcx>( cx: &mut DocContext<'tcx>, args: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, - mut skip_first: bool, + has_self: bool, container: Option, ) -> Vec { + let mut skip_first = has_self; let mut ret_val = Vec::with_capacity(args.skip_binder().len().saturating_sub(if skip_first { 1 } else { 0 })); @@ -99,6 +100,7 @@ pub(crate) fn ty_args_to_args<'tcx>( container.map(|container| crate::clean::ContainerTy::Regular { ty: container, 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 644d0699e9d07..df88530071be7 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 {} +pub trait Base { + type Type; +} +impl Base for () { + type Type = (); +} + +pub type NestedTraitObjects = dyn Outer; + +pub fn apit_rpit(o: impl Outer) -> impl Outer { + o +} + +pub type AssocTy = <() as Base>::Type; diff --git a/tests/rustdoc/inline_cross/dyn_trait.rs b/tests/rustdoc/inline_cross/dyn_trait.rs index 1de01af83d13e..679972f035ad4 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;" +pub use dyn_trait::NestedTraitObjects; + +// @has user/fn.apit_rpit.html +// @has - '//pre[@class="rust item-decl"]' \ +// "apit_rpit(o: impl Outer) -> impl Outer" +pub use dyn_trait::apit_rpit; + +// @has user/type.AssocTy.html +// @has - '//*[@class="rust item-decl"]//code' "<() as Base>::Type" +pub use dyn_trait::AssocTy;