Skip to content
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

Render all trait bounds in where clauses in rustdoc #96680

Closed
wants to merge 2 commits into from
Closed
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
20 changes: 10 additions & 10 deletions src/librustdoc/clean/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
match br {
// We only care about named late bound regions, as we need to add them
// to the 'for<>' section
ty::BrNamed(_, name) => Some(GenericParamDef {
name,
kind: GenericParamDefKind::Lifetime { outlives: vec![] },
}),
ty::BrNamed(_, name) => {
Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime })
}
_ => None,
}
})
Expand Down Expand Up @@ -610,18 +609,15 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
};
}

let final_bounds = self.make_final_bounds(ty_to_bounds, ty_to_fn, lifetime_to_bounds);

existing_predicates.extend(final_bounds);

for param in generic_params.iter_mut() {
match param.kind {
GenericParamDefKind::Type { ref mut default, ref mut bounds, .. } => {
GenericParamDefKind::Type { ref mut default, .. } => {
// We never want something like `impl<T=Foo>`.
default.take();
let generic_ty = Type::Generic(param.name);
if !has_sized.contains(&generic_ty) {
bounds.insert(0, GenericBound::maybe_sized(self.cx));
let b = GenericBound::maybe_sized(self.cx);
ty_to_bounds.entry(generic_ty).or_default().insert(b);
}
}
GenericParamDefKind::Lifetime { .. } => {}
Expand All @@ -632,6 +628,10 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
}
}

let final_bounds = self.make_final_bounds(ty_to_bounds, ty_to_fn, lifetime_to_bounds);

existing_predicates.extend(final_bounds);

self.sort_where_predicates(&mut existing_predicates);

Generics { params: generic_params, where_predicates: existing_predicates }
Expand Down
186 changes: 48 additions & 138 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::PredicateOrigin;
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
Expand All @@ -33,7 +32,7 @@ use std::collections::hash_map::Entry;
use std::collections::BTreeMap;
use std::default::Default;
use std::hash::Hash;
use std::{mem, vec};
use std::vec;

use crate::core::{self, DocContext, ImplTraitParam};
use crate::formats::item_type::ItemType;
Expand Down Expand Up @@ -167,10 +166,9 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
.collect_referenced_late_bound_regions(&poly_trait_ref)
.into_iter()
.filter_map(|br| match br {
ty::BrNamed(_, name) => Some(GenericParamDef {
name,
kind: GenericParamDefKind::Lifetime { outlives: vec![] },
}),
ty::BrNamed(_, name) => {
Some(GenericParamDef { name, kind: GenericParamDefKind::Lifetime })
}
_ => None,
})
.collect();
Expand Down Expand Up @@ -239,12 +237,9 @@ impl<'tcx> Clean<'tcx, Option<Lifetime>> for ty::Region<'tcx> {
}
}

impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
if !self.in_where_clause() {
return None;
}
Some(match *self {
impl<'tcx> Clean<'tcx, WherePredicate> for hir::WherePredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> WherePredicate {
match *self {
hir::WherePredicate::BoundPredicate(ref wbp) => {
let bound_params = wbp
.bound_generic_params
Expand Down Expand Up @@ -275,7 +270,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
lhs: wrp.lhs_ty.clean(cx),
rhs: wrp.rhs_ty.clean(cx).into(),
},
})
}
}
}

Expand Down Expand Up @@ -434,9 +429,7 @@ fn projection_to_path_segment<'tcx>(
impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {
fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericParamDef {
let (name, kind) = match self.kind {
ty::GenericParamDefKind::Lifetime => {
(self.name, GenericParamDefKind::Lifetime { outlives: vec![] })
}
ty::GenericParamDefKind::Lifetime => (self.name, GenericParamDefKind::Lifetime),
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
let default = if has_default {
Some(clean_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
Expand All @@ -447,7 +440,6 @@ impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {
self.name,
GenericParamDefKind::Type {
did: self.def_id,
bounds: vec![], // These are filled in from the where-clauses.
default: default.map(Box::new),
synthetic,
},
Expand All @@ -472,143 +464,61 @@ impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {

fn clean_generic_param<'tcx>(
cx: &mut DocContext<'tcx>,
generics: Option<&hir::Generics<'tcx>>,
param: &hir::GenericParam<'tcx>,
) -> GenericParamDef {
let did = cx.tcx.hir().local_def_id(param.hir_id);
let (name, kind) = match param.kind {
hir::GenericParamKind::Lifetime { .. } => {
let outlives = if let Some(generics) = generics {
generics
.outlives_for_param(did)
.filter(|bp| !bp.in_where_clause)
.flat_map(|bp| bp.bounds)
.map(|bound| match bound {
hir::GenericBound::Outlives(lt) => lt.clean(cx),
_ => panic!(),
})
.collect()
} else {
Vec::new()
};
(param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
}
hir::GenericParamKind::Type { ref default, synthetic } => {
let bounds = if let Some(generics) = generics {
generics
.bounds_for_param(did)
.filter(|bp| bp.origin != PredicateOrigin::WhereClause)
.flat_map(|bp| bp.bounds)
.filter_map(|x| x.clean(cx))
.collect()
} else {
Vec::new()
};
(
param.name.ident().name,
GenericParamDefKind::Type {
did: did.to_def_id(),
bounds,
default: default.map(|t| t.clean(cx)).map(Box::new),
synthetic,
},
)
}
hir::GenericParamKind::Const { ty, default } => (
param.name.ident().name,
GenericParamDefKind::Const {
did: did.to_def_id(),
ty: Box::new(ty.clean(cx)),
default: default.map(|ct| {
let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
}),
},
),
let name = param.name.ident().name;
let kind = match param.kind {
hir::GenericParamKind::Lifetime { .. } => GenericParamDefKind::Lifetime,
hir::GenericParamKind::Type { ref default, synthetic } => GenericParamDefKind::Type {
did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(),
default: default.map(|t| t.clean(cx)).map(Box::new),
synthetic,
},
hir::GenericParamKind::Const { ty, default } => GenericParamDefKind::Const {
did: did.to_def_id(),
ty: Box::new(ty.clean(cx)),
default: default.map(|ct| {
let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
}),
},
};

GenericParamDef { name, kind }
}

impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics {
// Synthetic type-parameters are inserted after normal ones.
// In order for normal parameters to be able to refer to synthetic ones,
// scans them first.
fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
match param.kind {
hir::GenericParamKind::Type { synthetic, .. } => synthetic,
_ => false,
}
}
/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
///
/// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information.
///
/// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param
fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
matches!(
param.kind,
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }
)
}

let impl_trait_params = self
.params
.iter()
.filter(|param| is_impl_trait(param))
.map(|param| {
let param = clean_generic_param(cx, Some(self), param);
match param.kind {
GenericParamDefKind::Lifetime { .. } => unreachable!(),
GenericParamDefKind::Type { did, ref bounds, .. } => {
cx.impl_trait_bounds.insert(did.into(), bounds.clone());
let mut impl_trait = FxHashSet::default();
for (i, p) in self.predicates.iter().enumerate() {
if let hir::WherePredicate::BoundPredicate(bp) = p {
if let Some((def_id, ident)) = bp.bounded_ty.as_generic_param() {
// Do not include predicates on `impl Trait` desugaring.
if ident.as_str().starts_with("impl ") {
let bounds = bp.bounds.iter().filter_map(|b| b.clean(cx)).collect();
cx.impl_trait_bounds.insert(def_id.into(), bounds);
impl_trait.insert(i);
}
GenericParamDefKind::Const { .. } => unreachable!(),
}
param
})
.collect::<Vec<_>>();
}
}

let mut params = Vec::with_capacity(self.params.len());
for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
let p = clean_generic_param(cx, Some(self), p);
params.push(p);
for p in self.params {
if !p.is_elided_lifetime() {
params.push(clean_generic_param(cx, p));
}
}
params.extend(impl_trait_params);

let mut generics = Generics {
params,
where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(),
};

// Some duplicates are generated for ?Sized bounds between type params and where
// predicates. The point in here is to move the bounds definitions from type params
// to where predicates when such cases occur.
for where_pred in &mut generics.where_predicates {
match *where_pred {
WherePredicate::BoundPredicate {
ty: Generic(ref name), ref mut bounds, ..
} => {
if bounds.is_empty() {
for param in &mut generics.params {
match param.kind {
GenericParamDefKind::Lifetime { .. } => {}
GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
if &param.name == name {
mem::swap(bounds, ty_bounds);
break;
}
}
GenericParamDefKind::Const { .. } => {}
}
}
}
}
_ => continue,
let mut where_predicates = Vec::with_capacity(self.predicates.len());
for (i, p) in self.predicates.iter().enumerate() {
if impl_trait.contains(&i) {
continue;
}
where_predicates.push(p.clean(cx));
}
generics
Generics { params, where_predicates }
}
}

Expand Down Expand Up @@ -991,7 +901,7 @@ impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
generic_params: self
.bound_generic_params
.iter()
.map(|x| clean_generic_param(cx, None, x))
.map(|x| clean_generic_param(cx, x))
.collect(),
}
}
Expand Down Expand Up @@ -1866,7 +1776,7 @@ impl<'tcx> Clean<'tcx, BareFunctionDecl> for hir::BareFnTy<'tcx> {
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generic_params =
self.generic_params.iter().map(|x| clean_generic_param(cx, None, x)).collect();
self.generic_params.iter().map(|x| clean_generic_param(cx, x)).collect();
let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
let decl = clean_fn_decl_with_args(cx, self.decl, args);
(generic_params, decl)
Expand Down
25 changes: 4 additions & 21 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1362,17 +1362,11 @@ impl WherePredicate {

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) enum GenericParamDefKind {
Lifetime { outlives: Vec<Lifetime> },
Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
Lifetime,
Type { did: DefId, default: Option<Box<Type>>, synthetic: bool },
Const { did: DefId, ty: Box<Type>, default: Option<Box<String>> },
}

impl GenericParamDefKind {
pub(crate) fn is_type(&self) -> bool {
matches!(self, GenericParamDefKind::Type { .. })
}
}

#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) struct GenericParamDef {
pub(crate) name: Symbol,
Expand All @@ -1381,26 +1375,15 @@ pub(crate) struct GenericParamDef {

// `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(GenericParamDef, 56);
rustc_data_structures::static_assert_size!(GenericParamDef, 40);

impl GenericParamDef {
pub(crate) fn is_synthetic_type_param(&self) -> bool {
match self.kind {
GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => false,
GenericParamDefKind::Type { synthetic, .. } => synthetic,
}
}

pub(crate) fn is_type(&self) -> bool {
self.kind.is_type()
}

pub(crate) fn get_bounds(&self) -> Option<&[GenericBound]> {
match self.kind {
GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
_ => None,
}
}
}

// maybe use a Generic enum and use Vec<Generic>?
Expand Down
Loading