From eeb2a6203b9b7072d088fbc5339f4c8311e57097 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 30 Oct 2021 21:21:35 -0700 Subject: [PATCH 1/3] Extract function for expanding private type aliases --- src/librustdoc/clean/mod.rs | 189 +++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 91 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9ea3112f178be..3adc067005b38 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1148,7 +1148,6 @@ impl Clean for ty::AssocItem { } fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { - use rustc_hir::GenericParamCount; let hir::Ty { hir_id: _, span, ref kind } = *hir_ty; let qpath = match kind { hir::TyKind::Path(qpath) => qpath, @@ -1166,97 +1165,12 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { } } - let mut alias = None; - if let Res::Def(DefKind::TyAlias, def_id) = path.res { - // Substitute private type aliases - if let Some(def_id) = def_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); - if !cx.cache.access_levels.is_exported(def_id.to_def_id()) { - alias = Some(&cx.tcx.hir().expect_item(hir_id).kind); - } - } - }; - - if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias { - let provided_params = &path.segments.last().expect("segments were empty"); - let mut ty_substs = FxHashMap::default(); - let mut lt_substs = FxHashMap::default(); - let mut ct_substs = FxHashMap::default(); - let generic_args = provided_params.args(); - { - let mut indices: GenericParamCount = Default::default(); - for param in generics.params.iter() { - match param.kind { - hir::GenericParamKind::Lifetime { .. } => { - let mut j = 0; - let lifetime = generic_args.args.iter().find_map(|arg| match arg { - hir::GenericArg::Lifetime(lt) => { - if indices.lifetimes == j { - return Some(lt); - } - j += 1; - None - } - _ => None, - }); - 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() - }; - lt_substs.insert(lt_def_id.to_def_id(), cleaned); - } - indices.lifetimes += 1; - } - hir::GenericParamKind::Type { ref default, .. } => { - let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); - let mut j = 0; - let type_ = generic_args.args.iter().find_map(|arg| match arg { - hir::GenericArg::Type(ty) => { - if indices.types == j { - return Some(ty); - } - j += 1; - None - } - _ => None, - }); - if let Some(ty) = type_ { - ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx)); - } else if let Some(default) = *default { - ty_substs - .insert(ty_param_def_id.to_def_id(), default.clean(cx)); - } - indices.types += 1; - } - hir::GenericParamKind::Const { .. } => { - let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); - let mut j = 0; - let const_ = generic_args.args.iter().find_map(|arg| match arg { - hir::GenericArg::Const(ct) => { - if indices.consts == j { - return Some(ct); - } - j += 1; - None - } - _ => None, - }); - if let Some(ct) = const_ { - ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx)); - } - // FIXME(const_generics_defaults) - indices.consts += 1; - } - } - } - } - return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx)); + if let Some(expanded) = maybe_expand_private_type_alias(cx, path) { + expanded + } else { + let path = path.clean(cx); + resolve_type(cx, path) } - let path = path.clean(cx); - resolve_type(cx, path) } hir::QPath::Resolved(Some(ref qself), p) => { // Try to normalize `::T` to a type @@ -1300,6 +1214,99 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { } } +fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>) -> Option { + let mut alias = None; + if let Res::Def(DefKind::TyAlias, def_id) = path.res { + // Substitute private type aliases + if let Some(def_id) = def_id.as_local() { + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + if !cx.cache.access_levels.is_exported(def_id.to_def_id()) { + alias = Some(&cx.tcx.hir().expect_item(hir_id).kind); + } + } + }; + + if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias { + let provided_params = &path.segments.last().expect("segments were empty"); + let mut ty_substs = FxHashMap::default(); + let mut lt_substs = FxHashMap::default(); + let mut ct_substs = FxHashMap::default(); + let generic_args = provided_params.args(); + { + let mut indices: hir::GenericParamCount = Default::default(); + for param in generics.params.iter() { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => { + let mut j = 0; + let lifetime = generic_args.args.iter().find_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) => { + if indices.lifetimes == j { + return Some(lt); + } + j += 1; + None + } + _ => None, + }); + 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() + }; + lt_substs.insert(lt_def_id.to_def_id(), cleaned); + } + indices.lifetimes += 1; + } + hir::GenericParamKind::Type { ref default, .. } => { + let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); + let mut j = 0; + let type_ = generic_args.args.iter().find_map(|arg| match arg { + hir::GenericArg::Type(ty) => { + if indices.types == j { + return Some(ty); + } + j += 1; + None + } + _ => None, + }); + if let Some(ty) = type_ { + ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx)); + } else if let Some(default) = *default { + ty_substs.insert(ty_param_def_id.to_def_id(), default.clean(cx)); + } + indices.types += 1; + } + hir::GenericParamKind::Const { .. } => { + let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); + let mut j = 0; + let const_ = generic_args.args.iter().find_map(|arg| match arg { + hir::GenericArg::Const(ct) => { + if indices.consts == j { + return Some(ct); + } + j += 1; + None + } + _ => None, + }); + if let Some(ct) = const_ { + ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx)); + } + // FIXME(const_generics_defaults) + indices.consts += 1; + } + } + } + } + Some(cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx))) + } else { + None + } +} + impl Clean for hir::Ty<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> Type { use rustc_hir::*; From bbc58e8ccc5d590c80f3fa07f8fe5cb2f3813aaa Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 30 Oct 2021 21:26:38 -0700 Subject: [PATCH 2/3] Reduce rightward drift --- src/librustdoc/clean/mod.rs | 152 ++++++++++++++++++------------------ src/librustdoc/lib.rs | 1 + 2 files changed, 75 insertions(+), 78 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3adc067005b38..508407144c216 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1215,96 +1215,92 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { } fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>) -> Option { - let mut alias = None; - if let Res::Def(DefKind::TyAlias, def_id) = path.res { - // Substitute private type aliases - if let Some(def_id) = def_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); - if !cx.cache.access_levels.is_exported(def_id.to_def_id()) { - alias = Some(&cx.tcx.hir().expect_item(hir_id).kind); - } - } + let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None }; + // Substitute private type aliases + let Some(def_id) = def_id.as_local() else { return None }; + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) { + &cx.tcx.hir().expect_item(hir_id).kind + } else { + return None; }; + let hir::ItemKind::TyAlias(ty, generics) = alias else { return None }; - if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias { - let provided_params = &path.segments.last().expect("segments were empty"); - let mut ty_substs = FxHashMap::default(); - let mut lt_substs = FxHashMap::default(); - let mut ct_substs = FxHashMap::default(); - let generic_args = provided_params.args(); - { - let mut indices: hir::GenericParamCount = Default::default(); - for param in generics.params.iter() { - match param.kind { - hir::GenericParamKind::Lifetime { .. } => { - let mut j = 0; - let lifetime = generic_args.args.iter().find_map(|arg| match arg { - hir::GenericArg::Lifetime(lt) => { - if indices.lifetimes == j { - return Some(lt); - } - j += 1; - None - } - _ => None, - }); - 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() - }; - lt_substs.insert(lt_def_id.to_def_id(), cleaned); + let provided_params = &path.segments.last().expect("segments were empty"); + let mut ty_substs = FxHashMap::default(); + let mut lt_substs = FxHashMap::default(); + let mut ct_substs = FxHashMap::default(); + let generic_args = provided_params.args(); + + let mut indices: hir::GenericParamCount = Default::default(); + for param in generics.params.iter() { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => { + let mut j = 0; + let lifetime = generic_args.args.iter().find_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) => { + if indices.lifetimes == j { + return Some(lt); } - indices.lifetimes += 1; + j += 1; + None } - hir::GenericParamKind::Type { ref default, .. } => { - let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); - let mut j = 0; - let type_ = generic_args.args.iter().find_map(|arg| match arg { - hir::GenericArg::Type(ty) => { - if indices.types == j { - return Some(ty); - } - j += 1; - None - } - _ => None, - }); - if let Some(ty) = type_ { - ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx)); - } else if let Some(default) = *default { - ty_substs.insert(ty_param_def_id.to_def_id(), default.clean(cx)); + _ => None, + }); + 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() + }; + lt_substs.insert(lt_def_id.to_def_id(), cleaned); + } + indices.lifetimes += 1; + } + hir::GenericParamKind::Type { ref default, .. } => { + let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); + let mut j = 0; + let type_ = generic_args.args.iter().find_map(|arg| match arg { + hir::GenericArg::Type(ty) => { + if indices.types == j { + return Some(ty); } - indices.types += 1; + j += 1; + None } - hir::GenericParamKind::Const { .. } => { - let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); - let mut j = 0; - let const_ = generic_args.args.iter().find_map(|arg| match arg { - hir::GenericArg::Const(ct) => { - if indices.consts == j { - return Some(ct); - } - j += 1; - None - } - _ => None, - }); - if let Some(ct) = const_ { - ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx)); + _ => None, + }); + if let Some(ty) = type_ { + ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx)); + } else if let Some(default) = *default { + ty_substs.insert(ty_param_def_id.to_def_id(), default.clean(cx)); + } + indices.types += 1; + } + hir::GenericParamKind::Const { .. } => { + let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id); + let mut j = 0; + let const_ = generic_args.args.iter().find_map(|arg| match arg { + hir::GenericArg::Const(ct) => { + if indices.consts == j { + return Some(ct); } - // FIXME(const_generics_defaults) - indices.consts += 1; + j += 1; + None } + _ => None, + }); + if let Some(ct) = const_ { + ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx)); } + // FIXME(const_generics_defaults) + indices.consts += 1; } } - Some(cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx))) - } else { - None } + + Some(cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx))) } impl Clean for hir::Ty<'_> { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b50fbf58bae29..8dceb2ec92a27 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -9,6 +9,7 @@ #![feature(control_flow_enum)] #![feature(box_syntax)] #![feature(in_band_lifetimes)] +#![feature(let_else)] #![feature(nll)] #![feature(test)] #![feature(crate_visibility_modifier)] From 5a77f3006f0e15c35e905b6f4f08a33f7005c3d1 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 30 Oct 2021 21:42:17 -0700 Subject: [PATCH 3/3] Merge `DocContext.{ty,lt,ct}_substs` into one map It should be impossible to have more than one entry with a particular key across the three maps, so they should be one map. In addition to making it impossible for multiple entries to exist, this should improve memory usage since now only one map is allocated on the stack and heap. --- src/librustdoc/clean/mod.rs | 19 +++++++++---------- src/librustdoc/clean/types.rs | 29 +++++++++++++++++++++++++++++ src/librustdoc/core.rs | 32 +++++++------------------------- 3 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 508407144c216..93bce10a2d606 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -222,7 +222,7 @@ impl Clean for hir::Lifetime { | rl::Region::Free(_, node_id), ) = def { - if let Some(lt) = cx.lt_substs.get(&node_id).cloned() { + if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() { return lt; } } @@ -1157,7 +1157,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { match qpath { hir::QPath::Resolved(None, ref path) => { if let Res::Def(DefKind::TyParam, did) = path.res { - if let Some(new_ty) = cx.ty_substs.get(&did).cloned() { + if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() { return new_ty; } if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) { @@ -1227,9 +1227,7 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_> let hir::ItemKind::TyAlias(ty, generics) = alias else { return None }; let provided_params = &path.segments.last().expect("segments were empty"); - let mut ty_substs = FxHashMap::default(); - let mut lt_substs = FxHashMap::default(); - let mut ct_substs = FxHashMap::default(); + let mut substs = FxHashMap::default(); let generic_args = provided_params.args(); let mut indices: hir::GenericParamCount = Default::default(); @@ -1254,7 +1252,7 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_> } else { self::types::Lifetime::elided() }; - lt_substs.insert(lt_def_id.to_def_id(), cleaned); + substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned)); } indices.lifetimes += 1; } @@ -1272,9 +1270,9 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_> _ => None, }); if let Some(ty) = type_ { - ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx)); + substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx))); } else if let Some(default) = *default { - ty_substs.insert(ty_param_def_id.to_def_id(), default.clean(cx)); + substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(default.clean(cx))); } indices.types += 1; } @@ -1292,7 +1290,8 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_> _ => None, }); if let Some(ct) = const_ { - ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx)); + substs + .insert(const_param_def_id.to_def_id(), SubstParam::Constant(ct.clean(cx))); } // FIXME(const_generics_defaults) indices.consts += 1; @@ -1300,7 +1299,7 @@ fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_> } } - Some(cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx))) + Some(cx.enter_alias(substs, |cx| ty.clean(cx))) } impl Clean for hir::Ty<'_> { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 88fffaecb937b..e91d0aa839d95 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2247,3 +2247,32 @@ impl TypeBinding { } } } + +/// The type, lifetime, or constant that a private type alias's parameter should be +/// replaced with when expanding a use of that type alias. +/// +/// For example: +/// +/// ``` +/// type PrivAlias = Vec; +/// +/// pub fn public_fn() -> PrivAlias { vec![] } +/// ``` +/// +/// `public_fn`'s docs will show it as returning `Vec`, since `PrivAlias` is private. +/// [`SubstParam`] is used to record that `T` should be mapped to `i32`. +crate enum SubstParam { + Type(Type), + Lifetime(Lifetime), + Constant(Constant), +} + +impl SubstParam { + crate fn as_ty(&self) -> Option<&Type> { + if let Self::Type(ty) = self { Some(ty) } else { None } + } + + crate fn as_lt(&self) -> Option<&Lifetime> { + if let Self::Lifetime(lt) = self { Some(lt) } else { None } + } +} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b7251e8f57151..7fa6484d23896 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -54,14 +54,10 @@ crate struct DocContext<'tcx> { /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. crate active_extern_traits: FxHashSet, - // The current set of type and lifetime substitutions, + // The current set of parameter substitutions, // for expanding type aliases at the HIR level: - /// Table `DefId` of type parameter -> substituted type - crate ty_substs: FxHashMap, - /// Table `DefId` of lifetime parameter -> substituted lifetime - crate lt_substs: FxHashMap, - /// Table `DefId` of const parameter -> substituted const - crate ct_substs: FxHashMap, + /// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const + crate substs: FxHashMap, /// Table synthetic type parameter for `impl Trait` in argument position -> bounds crate impl_trait_bounds: FxHashMap>, /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. @@ -104,25 +100,13 @@ impl<'tcx> DocContext<'tcx> { /// Call the closure with the given parameters set as /// the substitutions for a type alias' RHS. - crate fn enter_alias( - &mut self, - ty_substs: FxHashMap, - lt_substs: FxHashMap, - ct_substs: FxHashMap, - f: F, - ) -> R + crate fn enter_alias(&mut self, substs: FxHashMap, f: F) -> R where F: FnOnce(&mut Self) -> R, { - let (old_tys, old_lts, old_cts) = ( - mem::replace(&mut self.ty_substs, ty_substs), - mem::replace(&mut self.lt_substs, lt_substs), - mem::replace(&mut self.ct_substs, ct_substs), - ); + let old_substs = mem::replace(&mut self.substs, substs); let r = f(self); - self.ty_substs = old_tys; - self.lt_substs = old_lts; - self.ct_substs = old_cts; + self.substs = old_substs; r } @@ -350,9 +334,7 @@ crate fn run_global_ctxt( param_env: ParamEnv::empty(), external_traits: Default::default(), active_extern_traits: Default::default(), - ty_substs: Default::default(), - lt_substs: Default::default(), - ct_substs: Default::default(), + substs: Default::default(), impl_trait_bounds: Default::default(), generated_synthetics: Default::default(), auto_traits: tcx