diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fcece84b09fb5..29c11c7b28a5f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -402,16 +402,7 @@ fn projection_to_path_segment(ty: ty::ProjectionTy<'_>, cx: &mut DocContext<'_>) PathSegment { name: item.name, args: GenericArgs::AngleBracketed { - args: ty.substs[generics.parent_count..] - .iter() - .map(|ty| match ty.unpack() { - ty::subst::GenericArgKind::Lifetime(lt) => { - GenericArg::Lifetime(lt.clean(cx).unwrap()) - } - ty::subst::GenericArgKind::Type(ty) => GenericArg::Type(ty.clean(cx)), - ty::subst::GenericArgKind::Const(c) => GenericArg::Const(Box::new(c.clean(cx))), - }) - .collect(), + args: substs_to_args(cx, &ty.substs[generics.parent_count..], false), bindings: Default::default(), }, } @@ -1379,11 +1370,7 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_> }); if let Some(lt) = lifetime.cloned() { let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id); - let cleaned = if !lt.is_elided() { - lt.clean(cx) - } else { - self::types::Lifetime::elided() - }; + let cleaned = if !lt.is_elided() { lt.clean(cx) } else { Lifetime::elided() }; substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned)); } indices.lifetimes += 1; diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 20eea32560b27..7861b915e9627 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -77,16 +77,12 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { Crate { module, primitives, external_traits: cx.external_traits.clone() } } -fn external_generic_args( +crate fn substs_to_args( cx: &mut DocContext<'_>, - did: DefId, - has_self: bool, - bindings: Vec, - substs: SubstsRef<'_>, -) -> GenericArgs { - let mut skip_self = has_self; - let mut ty_kind = None; - let args: Vec<_> = substs + substs: &[ty::subst::GenericArg<'_>], + mut skip_first: bool, +) -> Vec { + substs .iter() .filter_map(|kind| match kind.unpack() { GenericArgKind::Lifetime(lt) => match *lt { @@ -95,23 +91,32 @@ fn external_generic_args( } _ => lt.clean(cx).map(GenericArg::Lifetime), }, - GenericArgKind::Type(_) if skip_self => { - skip_self = false; + GenericArgKind::Type(_) if skip_first => { + skip_first = false; None } - GenericArgKind::Type(ty) => { - ty_kind = Some(ty.kind()); - Some(GenericArg::Type(ty.clean(cx))) - } + GenericArgKind::Type(ty) => Some(GenericArg::Type(ty.clean(cx))), GenericArgKind::Const(ct) => Some(GenericArg::Const(Box::new(ct.clean(cx)))), }) - .collect(); + .collect() +} + +fn external_generic_args( + cx: &mut DocContext<'_>, + did: DefId, + has_self: bool, + bindings: Vec, + substs: SubstsRef<'_>, +) -> GenericArgs { + let args = substs_to_args(cx, &substs, has_self); if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() { - let inputs = match ty_kind.unwrap() { - ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect(), - _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() }, - }; + let inputs = + // The trait's first substitution is the one after self, if there is one. + match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() { + ty::Tuple(tys) => tys.iter().map(|t| t.clean(cx)).collect(), + _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() }, + }; let output = None; // FIXME(#20299) return type comes from a projection now // match types[1].kind { diff --git a/src/test/rustdoc/generic-associated-types/issue-94683.rs b/src/test/rustdoc/generic-associated-types/issue-94683.rs new file mode 100644 index 0000000000000..38ecf5283108f --- /dev/null +++ b/src/test/rustdoc/generic-associated-types/issue-94683.rs @@ -0,0 +1,13 @@ +#![crate_name = "foo"] +#![feature(generic_associated_types)] + +pub trait Trait { + type Gat<'a>; +} + +// Make sure that the elided lifetime shows up + +// @has foo/type.T.html +// @has - "pub type T = " +// @has - "<'_>" +pub type T = fn(&<() as Trait>::Gat<'_>);