From 70c520efb0ad8b62e4a69fda56a6ed85b887370c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 28 Apr 2022 23:11:13 +0200 Subject: [PATCH] Print all generic parameter bounds as where predicates in rustdoc. --- src/librustdoc/clean/auto_trait.rs | 20 +-- src/librustdoc/clean/mod.rs | 186 ++++++--------------- src/librustdoc/clean/types.rs | 25 +-- src/librustdoc/html/format.rs | 26 +-- src/librustdoc/html/render/search_index.rs | 21 +-- src/librustdoc/json/conversions.rs | 9 +- src/rustdoc-json-types/lib.rs | 7 +- 7 files changed, 70 insertions(+), 224 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index fb178cbd95e7b..d2d74e7e6c264 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -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, } }) @@ -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`. 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 { .. } => {} @@ -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 } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fd30691c32489..40e9fc7bb80e7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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; @@ -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; @@ -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(); @@ -239,12 +237,9 @@ impl<'tcx> Clean<'tcx, Option> for ty::Region<'tcx> { } } -impl<'tcx> Clean<'tcx, Option> for hir::WherePredicate<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { - 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 @@ -275,7 +270,7 @@ impl<'tcx> Clean<'tcx, Option> for hir::WherePredicate<'tcx> { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx).into(), }, - }) + } } } @@ -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))) @@ -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, }, @@ -472,59 +464,25 @@ 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 } @@ -532,83 +490,35 @@ fn clean_generic_param<'tcx>( 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::>(); + } + } 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 ¶m.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 } } } @@ -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(), } } @@ -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) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 83ab9acd3005a..317fe32cc1ad8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1362,17 +1362,11 @@ impl WherePredicate { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) enum GenericParamDefKind { - Lifetime { outlives: Vec }, - Type { did: DefId, bounds: Vec, default: Option>, synthetic: bool }, + Lifetime, + Type { did: DefId, default: Option>, synthetic: bool }, Const { did: DefId, ty: Box, default: Option> }, } -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, @@ -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? diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0c0920ae63e4e..263298a83a563 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -182,32 +182,10 @@ impl clean::GenericParamDef { cx: &'a Context<'tcx>, ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| match &self.kind { - clean::GenericParamDefKind::Lifetime { outlives } => { - write!(f, "{}", self.name)?; - - if !outlives.is_empty() { - f.write_str(": ")?; - for (i, lt) in outlives.iter().enumerate() { - if i != 0 { - f.write_str(" + ")?; - } - write!(f, "{}", lt.print())?; - } - } - - Ok(()) - } - clean::GenericParamDefKind::Type { bounds, default, .. } => { + clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name), + clean::GenericParamDefKind::Type { default, .. } => { f.write_str(self.name.as_str())?; - if !bounds.is_empty() { - if f.alternate() { - write!(f, ": {:#}", print_generic_bounds(bounds, cx))?; - } else { - write!(f, ": {}", print_generic_bounds(bounds, cx))?; - } - } - if let Some(ref ty) = default { if f.alternate() { write!(f, " = {:#}", ty.print(cx))?; diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 9f302cc256659..0d42f0d9c7a3c 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -351,7 +351,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( // If this argument is a type parameter and not a trait bound or a type, we need to look // for its bounds. - if let Type::Generic(arg_s) = *arg { + if let Type::Generic(_) = *arg { // First we check if the bounds are in a `where` predicate... if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g { WherePredicate::BoundPredicate { ty, .. } => ty.def_id(cache) == arg.def_id(cache), @@ -381,25 +381,6 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( } insert_ty(res, tcx, arg.clone(), ty_generics, cache); } - // Otherwise we check if the trait bounds are "inlined" like `T: Option`... - if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { - let mut ty_generics = Vec::new(); - for bound in bound.get_bounds().unwrap_or(&[]) { - if let Some(path) = bound.get_trait_path() { - let ty = Type::Path { path }; - add_generics_and_bounds_as_types( - self_, - generics, - &ty, - tcx, - recurse + 1, - &mut ty_generics, - cache, - ); - } - } - insert_ty(res, tcx, arg.clone(), ty_generics, cache); - } } else if let Type::ImplTrait(ref bounds) = *arg { let mut ty_generics = Vec::new(); for bound in bounds { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 4fde63c99d4b9..c26582e58e8f5 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -351,11 +351,8 @@ impl FromWithTcx for GenericParamDefKind { fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self { use clean::GenericParamDefKind::*; match kind { - Lifetime { outlives } => GenericParamDefKind::Lifetime { - outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(), - }, - Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type { - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + Lifetime => GenericParamDefKind::Lifetime, + Type { did: _, default, synthetic } => GenericParamDefKind::Type { default: default.map(|x| (*x).into_tcx(tcx)), synthetic, }, @@ -378,7 +375,7 @@ impl FromWithTcx for WherePredicate { .into_iter() .map(|x| GenericParamDef { name: x.0.to_string(), - kind: GenericParamDefKind::Lifetime { outlives: vec![] }, + kind: GenericParamDefKind::Lifetime, }) .collect(), }, diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index eb2c8e5bae1c4..ecba90f1dc45e 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 15; +pub const FORMAT_VERSION: u32 = 16; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -346,11 +346,8 @@ pub struct GenericParamDef { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] pub enum GenericParamDefKind { - Lifetime { - outlives: Vec, - }, + Lifetime, Type { - bounds: Vec, default: Option, /// This is normally `false`, which means that this generic parameter is /// declared in the Rust source text.