Skip to content

Merge DocContext.{ty,lt,ct}_substs into one map #90443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 95 additions & 93 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl Clean<Lifetime> 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() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could've made this unwrap the Option returned by as_lt since it's a rustdoc bug for it to be None here, but it seemed simpler to just use and_then. Let me know if you want me to use unwrap as a sort of assertion. (Likewise with as_ty below.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's fine... Maybe add a FIXME on it so we can come back to it later on?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's either leave it as-is or switch it to unwrap. I don't think it's worth a FIXME either way, and it's not actionable.

return lt;
}
}
Expand Down Expand Up @@ -1148,7 +1148,6 @@ impl Clean<Item> 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,
Expand All @@ -1158,105 +1157,20 @@ 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()) {
return ImplTrait(bounds);
}
}

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 `<X as Y>::T` to a type
Expand Down Expand Up @@ -1300,6 +1214,94 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
}
}

fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>) -> Option<Type> {
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 };

let provided_params = &path.segments.last().expect("segments were empty");
let mut 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()
};
substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(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_ {
substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx)));
} else if let Some(default) = *default {
substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(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_ {
substs
.insert(const_param_def_id.to_def_id(), SubstParam::Constant(ct.clean(cx)));
}
// FIXME(const_generics_defaults)
indices.consts += 1;
}
}
}

Some(cx.enter_alias(substs, |cx| ty.clean(cx)))
}

impl Clean<Type> for hir::Ty<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Type {
use rustc_hir::*;
Expand Down
29 changes: 29 additions & 0 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> = Vec<T>;
///
/// pub fn public_fn() -> PrivAlias<i32> { vec![] }
/// ```
///
/// `public_fn`'s docs will show it as returning `Vec<i32>`, 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 }
}
}
32 changes: 7 additions & 25 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<DefId>,
// 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<DefId, clean::Type>,
/// Table `DefId` of lifetime parameter -> substituted lifetime
crate lt_substs: FxHashMap<DefId, clean::Lifetime>,
/// Table `DefId` of const parameter -> substituted const
crate ct_substs: FxHashMap<DefId, clean::Constant>,
/// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const
crate substs: FxHashMap<DefId, clean::SubstParam>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
Expand Down Expand Up @@ -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<F, R>(
&mut self,
ty_substs: FxHashMap<DefId, clean::Type>,
lt_substs: FxHashMap<DefId, clean::Lifetime>,
ct_substs: FxHashMap<DefId, clean::Constant>,
f: F,
) -> R
crate fn enter_alias<F, R>(&mut self, substs: FxHashMap<DefId, clean::SubstParam>, 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
}

Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down