diff options
| author | Guillaume Gomez <guillaume.gomez@huawei.com> | 2022-12-02 19:36:20 +0100 |
|---|---|---|
| committer | Guillaume Gomez <guillaume.gomez@huawei.com> | 2022-12-02 19:40:40 +0100 |
| commit | af45040acd86d8881fd3dfbfdb08525627d63347 (patch) | |
| tree | 5717a480a1fc7c375530bf9567d1ceb22c4a1c82 | |
| parent | 11663b1b4857ffeafbd85a9a36c234d117373b76 (diff) | |
| download | rust-af45040acd86d8881fd3dfbfdb08525627d63347.tar.gz rust-af45040acd86d8881fd3dfbfdb08525627d63347.zip | |
Merge generics and where predicates and prevent duplicates in where predicates
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 124 |
1 files changed, 91 insertions, 33 deletions
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 80909919ba2..2a2a9470d25 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -12,7 +12,7 @@ pub(crate) mod utils; use rustc_ast as ast; use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -598,47 +598,105 @@ pub(crate) fn clean_generics<'tcx>( }) .collect::<Vec<_>>(); + let mut bound_predicates = FxIndexMap::default(); + let mut region_predicates = FxIndexMap::default(); + let mut eq_predicates = ThinVec::default(); + for pred in gens.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) { + match pred { + WherePredicate::BoundPredicate { ty, bounds, bound_params } => { + match bound_predicates.entry(ty) { + IndexEntry::Vacant(v) => { + v.insert((bounds, bound_params)); + } + IndexEntry::Occupied(mut o) => { + // we merge both bounds. + for bound in bounds { + if !o.get().0.contains(&bound) { + o.get_mut().0.push(bound); + } + } + for bound_param in bound_params { + if !o.get().1.contains(&bound_param) { + o.get_mut().1.push(bound_param); + } + } + } + } + } + WherePredicate::RegionPredicate { lifetime, bounds } => { + match region_predicates.entry(lifetime) { + IndexEntry::Vacant(v) => { + v.insert(bounds); + } + IndexEntry::Occupied(mut o) => { + // we merge both bounds. + for bound in bounds { + if !o.get().contains(&bound) { + o.get_mut().push(bound); + } + } + } + } + } + WherePredicate::EqPredicate { lhs, rhs, bound_params } => { + eq_predicates.push(WherePredicate::EqPredicate { lhs, rhs, bound_params }); + } + } + } + let mut params = ThinVec::with_capacity(gens.params.len()); + // In this loop, we gather the generic parameters (`<'a, B: 'a>`) and check if they have + // bounds in the where predicates. If so, we move their bounds into the where predicates + // while also preventing duplicates. for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { - let p = clean_generic_param(cx, Some(gens), p); + let mut p = clean_generic_param(cx, Some(gens), p); + match &mut p.kind { + GenericParamDefKind::Lifetime { ref mut outlives } => { + if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) { + // We merge bounds in the `where` clause. + for outlive in outlives.drain(..) { + let outlive = GenericBound::Outlives(outlive); + if !region_pred.contains(&outlive) { + region_pred.push(outlive); + } + } + } + } + GenericParamDefKind::Type { bounds, synthetic: false, .. } => { + if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(p.name)) { + // We merge bounds in the `where` clause. + for bound in bounds.drain(..) { + if !bound_pred.0.contains(&bound) { + bound_pred.0.push(bound); + } + } + } + } + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + // nothing to do here. + } + } params.push(p); } params.extend(impl_trait_params); - let mut generics = Generics { + Generics { params, - where_predicates: gens - .predicates - .iter() - .filter_map(|x| clean_where_predicate(x, cx)) + where_predicates: bound_predicates + .into_iter() + .map(|(ty, (bounds, bound_params))| WherePredicate::BoundPredicate { + ty, + bounds, + bound_params, + }) + .chain( + region_predicates + .into_iter() + .map(|(lifetime, bounds)| WherePredicate::RegionPredicate { lifetime, bounds }), + ) + .chain(eq_predicates.into_iter()) .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, - } } - generics } fn clean_ty_generics<'tcx>( |
