summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/clean
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:13:23 +0000
commit20431706a863f92cb37dc512fef6e48d192aaf2c (patch)
tree2867f13f5fd5437ba628c67d7f87309ccadcd286 /src/librustdoc/clean
parentReleasing progress-linux version 1.65.0+dfsg1-2~progress7.99u1. (diff)
downloadrustc-20431706a863f92cb37dc512fef6e48d192aaf2c.tar.xz
rustc-20431706a863f92cb37dc512fef6e48d192aaf2c.zip
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/librustdoc/clean')
-rw-r--r--src/librustdoc/clean/auto_trait.rs15
-rw-r--r--src/librustdoc/clean/blanket_impl.rs209
-rw-r--r--src/librustdoc/clean/inline.rs53
-rw-r--r--src/librustdoc/clean/mod.rs339
-rw-r--r--src/librustdoc/clean/simplify.rs60
-rw-r--r--src/librustdoc/clean/types.rs56
-rw-r--r--src/librustdoc/clean/utils.rs19
7 files changed, 428 insertions, 323 deletions
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 175472797..764a6d3aa 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -148,7 +148,7 @@ where
})
.collect();
// We are only interested in case the type *doesn't* implement the Sized trait.
- if !ty.is_sized(tcx.at(rustc_span::DUMMY_SP), param_env) {
+ if !ty.is_sized(tcx, param_env) {
// In case `#![no_core]` is used, `sized_trait` returns nothing.
if let Some(item) = tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
self.generate_for_trait(ty, sized_trait_did, param_env, item_def_id, &f, true)
@@ -475,6 +475,12 @@ where
let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
+ // FIXME: This code shares much of the logic found in `clean_ty_generics` and
+ // `simplify::where_clause`. Consider deduplicating it to avoid diverging
+ // implementations.
+ // Further, the code below does not merge (partially re-sugared) bounds like
+ // `Tr<A = T>` & `Tr<B = U>` and it does not render higher-ranked parameters
+ // originating from equality predicates.
for p in clean_where_predicates {
let (orig_p, p) = (p, clean_predicate(p, self.cx));
if p.is_none() {
@@ -549,8 +555,8 @@ where
WherePredicate::RegionPredicate { lifetime, bounds } => {
lifetime_to_bounds.entry(lifetime).or_default().extend(bounds);
}
- WherePredicate::EqPredicate { lhs, rhs } => {
- match lhs {
+ WherePredicate::EqPredicate { lhs, rhs, bound_params } => {
+ match *lhs {
Type::QPath(box QPathData {
ref assoc, ref self_type, ref trait_, ..
}) => {
@@ -585,13 +591,14 @@ where
GenericArgs::AngleBracketed { ref mut bindings, .. } => {
bindings.push(TypeBinding {
assoc: assoc.clone(),
- kind: TypeBindingKind::Equality { term: rhs },
+ kind: TypeBindingKind::Equality { term: *rhs },
});
}
GenericArgs::Parenthesized { .. } => {
existing_predicates.push(WherePredicate::EqPredicate {
lhs: lhs.clone(),
rhs,
+ bound_params,
});
continue; // If something other than a Fn ends up
// with parentheses, leave it alone
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index cc734389e..8b63c3db3 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -2,7 +2,6 @@ use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtE
use rustc_hir as hir;
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
use rustc_infer::traits;
-use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::ToPredicate;
use rustc_span::DUMMY_SP;
@@ -14,122 +13,124 @@ pub(crate) struct BlanketImplFinder<'a, 'tcx> {
impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
- let param_env = self.cx.tcx.param_env(item_def_id);
- let ty = self.cx.tcx.bound_type_of(item_def_id);
+ let cx = &mut self.cx;
+ let param_env = cx.tcx.param_env(item_def_id);
+ let ty = cx.tcx.bound_type_of(item_def_id);
trace!("get_blanket_impls({:?})", ty);
let mut impls = Vec::new();
- self.cx.with_all_traits(|cx, all_traits| {
- for &trait_def_id in all_traits {
- if !cx.cache.access_levels.is_public(trait_def_id)
- || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some()
- {
+ for trait_def_id in cx.tcx.all_traits() {
+ if !cx.cache.effective_visibilities.is_directly_public(trait_def_id)
+ || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some()
+ {
+ continue;
+ }
+ // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
+ let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
+ 'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
+ trace!(
+ "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
+ trait_def_id,
+ impl_def_id
+ );
+ let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
+ if !matches!(trait_ref.0.self_ty().kind(), ty::Param(_)) {
continue;
}
- // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
- let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
- for &impl_def_id in trait_impls.blanket_impls() {
- trace!(
- "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
- trait_def_id,
- impl_def_id
- );
- let trait_ref = cx.tcx.bound_impl_trait_ref(impl_def_id).unwrap();
- let is_param = matches!(trait_ref.0.self_ty().kind(), ty::Param(_));
- let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
- let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
- let ty = ty.subst(infcx.tcx, substs);
- let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs);
+ let infcx = cx.tcx.infer_ctxt().build();
+ let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
+ let impl_ty = ty.subst(infcx.tcx, substs);
+ let param_env = EarlyBinder(param_env).subst(infcx.tcx, substs);
- let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
- let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
+ let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+ let impl_trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
- // Require the type the impl is implemented on to match
- // our type, and ignore the impl if there was a mismatch.
- let cause = traits::ObligationCause::dummy();
- let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
- if let Ok(InferOk { value: (), obligations }) = eq_result {
- // FIXME(eddyb) ignoring `obligations` might cause false positives.
- drop(obligations);
+ // Require the type the impl is implemented on to match
+ // our type, and ignore the impl if there was a mismatch.
+ let cause = traits::ObligationCause::dummy();
+ let Ok(eq_result) = infcx.at(&cause, param_env).eq(impl_trait_ref.self_ty(), impl_ty) else {
+ continue
+ };
+ let InferOk { value: (), obligations } = eq_result;
+ // FIXME(eddyb) ignoring `obligations` might cause false positives.
+ drop(obligations);
- trace!(
- "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
- param_env,
- trait_ref,
- ty
- );
- let predicates = cx
- .tcx
- .predicates_of(impl_def_id)
- .instantiate(cx.tcx, impl_substs)
- .predicates
- .into_iter()
- .chain(Some(
- ty::Binder::dummy(trait_ref)
- .to_poly_trait_predicate()
- .map_bound(ty::PredicateKind::Trait)
- .to_predicate(infcx.tcx),
- ));
- for predicate in predicates {
- debug!("testing predicate {:?}", predicate);
- let obligation = traits::Obligation::new(
- traits::ObligationCause::dummy(),
- param_env,
- predicate,
- );
- match infcx.evaluate_obligation(&obligation) {
- Ok(eval_result) if eval_result.may_apply() => {}
- Err(traits::OverflowError::Canonical) => {}
- Err(traits::OverflowError::ErrorReporting) => {}
- _ => {
- return false;
- }
- }
- }
- true
- } else {
- false
- }
- });
- debug!(
- "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
- may_apply, trait_ref, ty
+ trace!(
+ "invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}",
+ param_env,
+ impl_trait_ref,
+ impl_ty
+ );
+ let predicates = cx
+ .tcx
+ .predicates_of(impl_def_id)
+ .instantiate(cx.tcx, impl_substs)
+ .predicates
+ .into_iter()
+ .chain(Some(
+ ty::Binder::dummy(impl_trait_ref)
+ .to_poly_trait_predicate()
+ .map_bound(ty::PredicateKind::Trait)
+ .to_predicate(infcx.tcx),
+ ));
+ for predicate in predicates {
+ debug!("testing predicate {:?}", predicate);
+ let obligation = traits::Obligation::new(
+ traits::ObligationCause::dummy(),
+ param_env,
+ predicate,
);
- if !may_apply {
- continue;
+ match infcx.evaluate_obligation(&obligation) {
+ Ok(eval_result) if eval_result.may_apply() => {}
+ Err(traits::OverflowError::Canonical) => {}
+ Err(traits::OverflowError::ErrorReporting) => {}
+ _ => continue 'blanket_impls,
}
+ }
+ debug!(
+ "get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}",
+ trait_ref, ty
+ );
- cx.generated_synthetics.insert((ty.0, trait_def_id));
+ cx.generated_synthetics.insert((ty.0, trait_def_id));
- impls.push(Item {
- name: None,
- attrs: Default::default(),
- visibility: Inherited,
- item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
- kind: Box::new(ImplItem(Box::new(Impl {
- unsafety: hir::Unsafety::Normal,
- generics: clean_ty_generics(
- cx,
- cx.tcx.generics_of(impl_def_id),
- cx.tcx.explicit_predicates_of(impl_def_id),
- ),
- // FIXME(eddyb) compute both `trait_` and `for_` from
- // the post-inference `trait_ref`, as it's more accurate.
- trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, ThinVec::new())),
- for_: clean_middle_ty(ty.0, cx, None),
- items: cx.tcx
- .associated_items(impl_def_id)
- .in_definition_order()
- .map(|x| clean_middle_assoc_item(x, cx))
- .collect::<Vec<_>>(),
- polarity: ty::ImplPolarity::Positive,
- kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))),
- }))),
- cfg: None,
- });
- }
+ impls.push(Item {
+ name: None,
+ attrs: Default::default(),
+ visibility: Inherited,
+ item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
+ kind: Box::new(ImplItem(Box::new(Impl {
+ unsafety: hir::Unsafety::Normal,
+ generics: clean_ty_generics(
+ cx,
+ cx.tcx.generics_of(impl_def_id),
+ cx.tcx.explicit_predicates_of(impl_def_id),
+ ),
+ // FIXME(eddyb) compute both `trait_` and `for_` from
+ // the post-inference `trait_ref`, as it's more accurate.
+ trait_: Some(clean_trait_ref_with_bindings(
+ cx,
+ trait_ref.0,
+ ThinVec::new(),
+ )),
+ for_: clean_middle_ty(ty.0, cx, None),
+ items: cx
+ .tcx
+ .associated_items(impl_def_id)
+ .in_definition_order()
+ .map(|x| clean_middle_assoc_item(x, cx))
+ .collect::<Vec<_>>(),
+ polarity: ty::ImplPolarity::Positive,
+ kind: ImplKind::Blanket(Box::new(clean_middle_ty(
+ trait_ref.0.self_ty(),
+ cx,
+ None,
+ ))),
+ }))),
+ cfg: None,
+ });
}
- });
+ }
impls
}
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index df0e9f7cc..4e2031a91 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -55,12 +55,39 @@ pub(crate) fn try_inline(
let mut ret = Vec::new();
debug!("attrs={:?}", attrs);
- let attrs_clone = attrs;
+
+ let attrs_without_docs = attrs.map(|attrs| {
+ attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>()
+ });
+ // We need this ugly code because:
+ //
+ // ```
+ // attrs_without_docs.map(|a| a.as_slice())
+ // ```
+ //
+ // will fail because it returns a temporary slice and:
+ //
+ // ```
+ // attrs_without_docs.map(|s| {
+ // vec = s.as_slice();
+ // vec
+ // })
+ // ```
+ //
+ // will fail because we're moving an uninitialized variable into a closure.
+ let vec;
+ let attrs_without_docs = match attrs_without_docs {
+ Some(s) => {
+ vec = s;
+ Some(vec.as_slice())
+ }
+ None => None,
+ };
let kind = match res {
Res::Def(DefKind::Trait, did) => {
record_extern_fqn(cx, did, ItemType::Trait);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::TraitItem(Box::new(build_external_trait(cx, did)))
}
Res::Def(DefKind::Fn, did) => {
@@ -69,27 +96,27 @@ pub(crate) fn try_inline(
}
Res::Def(DefKind::Struct, did) => {
record_extern_fqn(cx, did, ItemType::Struct);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::StructItem(build_struct(cx, did))
}
Res::Def(DefKind::Union, did) => {
record_extern_fqn(cx, did, ItemType::Union);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::UnionItem(build_union(cx, did))
}
Res::Def(DefKind::TyAlias, did) => {
record_extern_fqn(cx, did, ItemType::Typedef);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::TypedefItem(build_type_alias(cx, did))
}
Res::Def(DefKind::Enum, did) => {
record_extern_fqn(cx, did, ItemType::Enum);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::EnumItem(build_enum(cx, did))
}
Res::Def(DefKind::ForeignTy, did) => {
record_extern_fqn(cx, did, ItemType::ForeignType);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::ForeignTypeItem
}
// Never inline enum variants but leave them shown as re-exports.
@@ -123,7 +150,7 @@ pub(crate) fn try_inline(
_ => return None,
};
- let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
+ let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs);
cx.inlined.insert(did.into());
let mut item = clean::Item::from_def_id_and_attrs_and_parts(
did,
@@ -362,7 +389,7 @@ pub(crate) fn build_impl(
if !did.is_local() {
if let Some(traitref) = associated_trait {
let did = traitref.def_id;
- if !cx.cache.access_levels.is_public(did) {
+ if !cx.cache.effective_visibilities.is_directly_public(did) {
return;
}
@@ -391,7 +418,7 @@ pub(crate) fn build_impl(
// reachable in rustdoc generated documentation
if !did.is_local() {
if let Some(did) = for_.def_id(&cx.cache) {
- if !cx.cache.access_levels.is_public(did) {
+ if !cx.cache.effective_visibilities.is_directly_public(did) {
return;
}
@@ -425,7 +452,7 @@ pub(crate) fn build_impl(
let assoc_kind = match item.kind {
hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
- hir::ImplItemKind::TyAlias(..) => ty::AssocKind::Type,
+ hir::ImplItemKind::Type(..) => ty::AssocKind::Type,
};
let trait_item = tcx
.associated_items(associated_trait.def_id)
@@ -733,10 +760,6 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
debug!("record_extern_trait: {:?}", did);
let trait_ = build_external_trait(cx, did);
- let trait_ = clean::TraitWithExtraInfo {
- trait_,
- is_notable: clean::utils::has_doc_flag(cx.tcx, did, sym::notable_trait),
- };
cx.external_traits.borrow_mut().insert(did, trait_);
cx.active_extern_traits.remove(&did);
}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c8875c272..64a18757b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -17,16 +17,16 @@ 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_hir_analysis::hir_ty_to_ty;
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Lift, Ty, TyCtxt};
+use rustc_middle::ty::InternalSubsts;
+use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::hygiene::{AstPass, MacroKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{self, ExpnKind};
-use rustc_typeck::hir_ty_to_ty;
use std::assert_matches::assert_matches;
use std::collections::hash_map::Entry;
@@ -176,8 +176,6 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
poly_trait_ref: ty::PolyTraitRef<'tcx>,
bindings: ThinVec<TypeBinding>,
) -> GenericBound {
- let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
-
// collect any late bound regions
let late_bound_regions: Vec<_> = cx
.tcx
@@ -292,8 +290,9 @@ fn clean_where_predicate<'tcx>(
},
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
- lhs: clean_ty(wrp.lhs_ty, cx),
- rhs: clean_ty(wrp.rhs_ty, cx).into(),
+ lhs: Box::new(clean_ty(wrp.lhs_ty, cx)),
+ rhs: Box::new(clean_ty(wrp.rhs_ty, cx).into()),
+ bound_params: Vec::new(),
},
})
}
@@ -309,7 +308,9 @@ pub(crate) fn clean_predicate<'tcx>(
}
ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
- ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
+ ty::PredicateKind::Projection(pred) => {
+ Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
+ }
ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::WellFormed(..) => None,
@@ -387,13 +388,25 @@ fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Te
}
fn clean_projection_predicate<'tcx>(
- pred: ty::ProjectionPredicate<'tcx>,
+ pred: ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
cx: &mut DocContext<'tcx>,
) -> WherePredicate {
- let ty::ProjectionPredicate { projection_ty, term } = pred;
+ let late_bound_regions = cx
+ .tcx
+ .collect_referenced_late_bound_regions(&pred)
+ .into_iter()
+ .filter_map(|br| match br {
+ ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(Lifetime(name)),
+ _ => None,
+ })
+ .collect();
+
+ let ty::ProjectionPredicate { projection_ty, term } = pred.skip_binder();
+
WherePredicate::EqPredicate {
- lhs: clean_projection(projection_ty, cx, None),
- rhs: clean_middle_term(term, cx),
+ lhs: Box::new(clean_projection(projection_ty, cx, None)),
+ rhs: Box::new(clean_middle_term(term, cx)),
+ bound_params: late_bound_regions,
}
}
@@ -402,8 +415,17 @@ fn clean_projection<'tcx>(
cx: &mut DocContext<'tcx>,
def_id: Option<DefId>,
) -> Type {
- let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
- let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), ThinVec::new());
+ if cx.tcx.def_kind(ty.item_def_id) == DefKind::ImplTraitPlaceholder {
+ let bounds = cx
+ .tcx
+ .explicit_item_bounds(ty.item_def_id)
+ .iter()
+ .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.substs))
+ .collect::<Vec<_>>();
+ return clean_middle_opaque_bounds(cx, bounds);
+ }
+
+ let trait_ = clean_trait_ref_with_bindings(cx, ty.trait_ref(cx.tcx), ThinVec::new());
let self_type = clean_middle_ty(ty.self_ty(), cx, None);
let self_def_id = if let Some(def_id) = def_id {
cx.tcx.opt_parent(def_id).or(Some(def_id))
@@ -632,7 +654,7 @@ fn clean_ty_generics<'tcx>(
let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
// Bounds in the type_params and lifetimes fields are repeated in the
- // predicates field (see rustc_typeck::collect::ty_generics), so remove
+ // predicates field (see rustc_hir_analysis::collect::ty_generics), so remove
// them.
let stripped_params = gens
.params
@@ -655,8 +677,9 @@ fn clean_ty_generics<'tcx>(
})
.collect::<Vec<GenericParamDef>>();
- // param index -> [(DefId of trait, associated type name and generics, type)]
- let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, PathSegment, Ty<'_>)>>::default();
+ // param index -> [(trait DefId, associated type name & generics, type, higher-ranked params)]
+ let mut impl_trait_proj =
+ FxHashMap::<u32, Vec<(DefId, PathSegment, Ty<'_>, Vec<GenericParamDef>)>>::default();
let where_predicates = preds
.predicates
@@ -715,6 +738,14 @@ fn clean_ty_generics<'tcx>(
trait_did,
name,
rhs.ty().unwrap(),
+ p.get_bound_params()
+ .into_iter()
+ .flatten()
+ .map(|param| GenericParamDef {
+ name: param.0,
+ kind: GenericParamDefKind::Lifetime { outlives: Vec::new() },
+ })
+ .collect(),
));
}
@@ -730,15 +761,19 @@ fn clean_ty_generics<'tcx>(
// Move trait bounds to the front.
bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
- if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
- if let Some(proj) = impl_trait_proj.remove(&idx) {
- for (trait_did, name, rhs) in proj {
- let rhs = clean_middle_ty(rhs, cx, None);
- simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
- }
+ let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() };
+ if let Some(proj) = impl_trait_proj.remove(&idx) {
+ for (trait_did, name, rhs, bound_params) in proj {
+ let rhs = clean_middle_ty(rhs, cx, None);
+ simplify::merge_bounds(
+ cx,
+ &mut bounds,
+ bound_params,
+ trait_did,
+ name,
+ &Term::Type(rhs),
+ );
}
- } else {
- unreachable!();
}
cx.impl_trait_bounds.insert(param, bounds);
@@ -749,31 +784,36 @@ fn clean_ty_generics<'tcx>(
let mut where_predicates =
where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
- // Type parameters have a Sized bound by default unless removed with
- // ?Sized. Scan through the predicates and mark any type parameter with
- // a Sized bound, removing the bounds as we find them.
+ // In the surface language, all type parameters except `Self` have an
+ // implicit `Sized` bound unless removed with `?Sized`.
+ // However, in the list of where-predicates below, `Sized` appears like a
+ // normal bound: It's either present (the type is sized) or
+ // absent (the type is unsized) but never *maybe* (i.e. `?Sized`).
+ //
+ // This is unsuitable for rendering.
+ // Thus, as a first step remove all `Sized` bounds that should be implicit.
//
- // Note that associated types also have a sized bound by default, but we
+ // Note that associated types also have an implicit `Sized` bound but we
// don't actually know the set of associated types right here so that's
- // handled in cleaning associated types
+ // handled when cleaning associated types.
let mut sized_params = FxHashSet::default();
- where_predicates.retain(|pred| match *pred {
- WherePredicate::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
- if bounds.iter().any(|b| b.is_sized_bound(cx)) {
- sized_params.insert(*g);
- false
- } else {
- true
- }
+ where_predicates.retain(|pred| {
+ if let WherePredicate::BoundPredicate { ty: Generic(g), bounds, .. } = pred
+ && *g != kw::SelfUpper
+ && bounds.iter().any(|b| b.is_sized_bound(cx))
+ {
+ sized_params.insert(*g);
+ false
+ } else {
+ true
}
- _ => true,
});
- // Run through the type parameters again and insert a ?Sized
- // unbound for any we didn't find to be Sized.
+ // As a final step, go through the type parameters again and insert a
+ // `?Sized` bound for each one we didn't find to be `Sized`.
for tp in &stripped_params {
- if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
- && !sized_params.contains(&tp.name)
+ if let types::GenericParamDefKind::Type { .. } = tp.kind
+ && !sized_params.contains(&tp.name)
{
where_predicates.push(WherePredicate::BoundPredicate {
ty: Type::Generic(tp.name),
@@ -1002,7 +1042,7 @@ fn clean_poly_trait_ref<'tcx>(
}
fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
- let local_did = trait_item.def_id.to_def_id();
+ let local_did = trait_item.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match trait_item.kind {
hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
@@ -1054,7 +1094,7 @@ pub(crate) fn clean_impl_item<'tcx>(
impl_: &hir::ImplItem<'tcx>,
cx: &mut DocContext<'tcx>,
) -> Item {
- let local_did = impl_.def_id.to_def_id();
+ let local_did = impl_.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match impl_.kind {
hir::ImplItemKind::Const(ty, expr) => {
@@ -1063,10 +1103,10 @@ pub(crate) fn clean_impl_item<'tcx>(
}
hir::ImplItemKind::Fn(ref sig, body) => {
let m = clean_function(cx, sig, impl_.generics, body);
- let defaultness = cx.tcx.impl_defaultness(impl_.def_id);
+ let defaultness = cx.tcx.impl_defaultness(impl_.owner_id);
MethodItem(m, Some(defaultness))
}
- hir::ImplItemKind::TyAlias(hir_ty) => {
+ hir::ImplItemKind::Type(hir_ty) => {
let type_ = clean_ty(hir_ty, cx);
let generics = clean_generics(impl_.generics, cx);
let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
@@ -1080,7 +1120,7 @@ pub(crate) fn clean_impl_item<'tcx>(
let mut what_rustc_thinks =
Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx);
- let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id));
+ let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.owner_id.def_id));
// Trait impl items always inherit the impl's visibility --
// we don't want to show `pub`.
@@ -1177,11 +1217,18 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
if let ty::TraitContainer = assoc_item.container {
let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
- let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
- let mut generics =
- clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates);
- // Filter out the bounds that are (likely?) directly attached to the associated type,
- // as opposed to being located in the where clause.
+ let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
+ let predicates =
+ tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied());
+ let mut generics = clean_ty_generics(
+ cx,
+ tcx.generics_of(assoc_item.def_id),
+ ty::GenericPredicates { parent: None, predicates },
+ );
+ // Move bounds that are (likely) directly attached to the associated type
+ // from the where clause to the associated type.
+ // There is no guarantee that this is what the user actually wrote but we have
+ // no way of knowing.
let mut bounds = generics
.where_predicates
.drain_filter(|pred| match *pred {
@@ -1239,6 +1286,24 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
}
None => bounds.push(GenericBound::maybe_sized(cx)),
}
+ // Move bounds that are (likely) directly attached to the parameters of the
+ // (generic) associated type from the where clause to the respective parameter.
+ // There is no guarantee that this is what the user actually wrote but we have
+ // no way of knowing.
+ let mut where_predicates = Vec::new();
+ for mut pred in generics.where_predicates {
+ if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
+ && let Some(GenericParamDef {
+ kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
+ ..
+ }) = generics.params.iter_mut().find(|param| &param.name == arg)
+ {
+ param_bounds.extend(mem::take(bounds));
+ } else {
+ where_predicates.push(pred);
+ }
+ }
+ generics.where_predicates = where_predicates;
if tcx.impl_defaultness(assoc_item.def_id).has_value() {
AssocTypeItem(
@@ -1325,7 +1390,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
segments: trait_segments.iter().map(|x| clean_path_segment(x, cx)).collect(),
};
register_res(cx, trait_.res);
- let self_def_id = DefId::local(qself.hir_id.owner.local_def_index);
+ let self_def_id = DefId::local(qself.hir_id.owner.def_id.local_def_index);
let self_type = clean_ty(qself, cx);
let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type);
Type::QPath(Box::new(QPathData {
@@ -1366,7 +1431,7 @@ fn maybe_expand_private_type_alias<'tcx>(
let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
// Substitute private type aliases
let def_id = def_id.as_local()?;
- let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
+ let alias = if !cx.cache.effective_visibilities.is_exported(def_id.to_def_id()) {
&cx.tcx.hir().expect_item(def_id).kind
} else {
return None;
@@ -1480,7 +1545,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
// as we currently do not supply the parent generics to anonymous constants
// but do allow `ConstKind::Param`.
//
- // `const_eval_poly` tries to to first substitute generic parameters which
+ // `const_eval_poly` tries to first substitute generic parameters which
// results in an ICE while manually constructing the constant and using `eval`
// does nothing for `ConstKind::Param`.
let ct = ty::Const::from_anon_const(cx.tcx, def_id);
@@ -1509,13 +1574,12 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
}
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
- TyKind::Infer | TyKind::Err => Infer,
- TyKind::Typeof(..) => panic!("unimplemented type {:?}", ty.kind),
+ TyKind::Infer | TyKind::Err | TyKind::Typeof(..) => Infer,
}
}
/// Returns `None` if the type could not be normalized
-fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
+fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
// HACK: low-churn fix for #79459 while we wait for a trait normalization fix
if !cx.tcx.sess.opts.unstable_opts.normalize_docs {
return None;
@@ -1526,13 +1590,11 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
use rustc_middle::traits::ObligationCause;
// Try to normalize `<X as Y>::T` to a type
- let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
- let normalized = cx.tcx.infer_ctxt().enter(|infcx| {
- infcx
- .at(&ObligationCause::dummy(), cx.param_env)
- .normalize(lifted)
- .map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
- });
+ let infcx = cx.tcx.infer_ctxt().build();
+ let normalized = infcx
+ .at(&ObligationCause::dummy(), cx.param_env)
+ .normalize(ty)
+ .map(|resolved| infcx.resolve_vars_if_possible(resolved.value));
match normalized {
Ok(normalized_value) => {
debug!("normalized {:?} to {:?}", ty, normalized_value);
@@ -1546,12 +1608,12 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
}
pub(crate) fn clean_middle_ty<'tcx>(
- this: Ty<'tcx>,
+ ty: Ty<'tcx>,
cx: &mut DocContext<'tcx>,
def_id: Option<DefId>,
) -> Type {
- trace!("cleaning type: {:?}", this);
- let ty = normalize(cx, this).unwrap_or(this);
+ trace!("cleaning type: {:?}", ty);
+ let ty = normalize(cx, ty).unwrap_or(ty);
match *ty.kind() {
ty::Never => Primitive(PrimitiveType::Never),
ty::Bool => Primitive(PrimitiveType::Bool),
@@ -1561,8 +1623,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Float(float_ty) => Primitive(float_ty.into()),
ty::Str => Primitive(PrimitiveType::Str),
ty::Slice(ty) => Slice(Box::new(clean_middle_ty(ty, cx, None))),
- ty::Array(ty, n) => {
- let mut n = cx.tcx.lift(n).expect("array lift failed");
+ ty::Array(ty, mut n) => {
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n);
Array(Box::new(clean_middle_ty(ty, cx, None)), n)
@@ -1574,7 +1635,6 @@ pub(crate) fn clean_middle_ty<'tcx>(
type_: Box::new(clean_middle_ty(ty, cx, None)),
},
ty::FnDef(..) | ty::FnPtr(_) => {
- let ty = cx.tcx.lift(this).expect("FnPtr lift failed");
let sig = ty.fn_sig(cx.tcx);
let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
BareFunction(Box::new(BareFunctionDecl {
@@ -1608,7 +1668,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
let did = obj
.principal_def_id()
.or_else(|| dids.next())
- .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
+ .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", ty));
let substs = match obj.principal() {
Some(principal) => principal.skip_binder().substs,
// marker traits have no substs.
@@ -1632,8 +1692,6 @@ pub(crate) fn clean_middle_ty<'tcx>(
.map(|pb| TypeBinding {
assoc: projection_to_path_segment(
pb.skip_binder()
- .lift_to_tcx(cx.tcx)
- .unwrap()
// HACK(compiler-errors): Doesn't actually matter what self
// type we put here, because we're only using the GAT's substs.
.with_self_ty(cx.tcx, cx.tcx.types.self_param)
@@ -1666,66 +1724,13 @@ pub(crate) fn clean_middle_ty<'tcx>(
ty::Opaque(def_id, substs) => {
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the bounds associated with the def_id.
- let substs = cx.tcx.lift(substs).expect("Opaque lift failed");
let bounds = cx
.tcx
.explicit_item_bounds(def_id)
.iter()
.map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
.collect::<Vec<_>>();
- let mut regions = vec![];
- let mut has_sized = false;
- let mut bounds = bounds
- .iter()
- .filter_map(|bound| {
- let bound_predicate = bound.kind();
- let trait_ref = match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
- if let Some(r) = clean_middle_region(reg) {
- regions.push(GenericBound::Outlives(r));
- }
- return None;
- }
- _ => return None,
- };
-
- if let Some(sized) = cx.tcx.lang_items().sized_trait() {
- if trait_ref.def_id() == sized {
- has_sized = true;
- return None;
- }
- }
-
- let bindings: ThinVec<_> = bounds
- .iter()
- .filter_map(|bound| {
- if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
- {
- if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
- Some(TypeBinding {
- assoc: projection_to_path_segment(proj.projection_ty, cx),
- kind: TypeBindingKind::Equality {
- term: clean_middle_term(proj.term, cx),
- },
- })
- } else {
- None
- }
- } else {
- None
- }
- })
- .collect();
-
- Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
- })
- .collect::<Vec<_>>();
- bounds.extend(regions);
- if !has_sized && !bounds.is_empty() {
- bounds.insert(0, GenericBound::maybe_sized(cx));
- }
- ImplTrait(bounds)
+ clean_middle_opaque_bounds(cx, bounds)
}
ty::Closure(..) => panic!("Closure"),
@@ -1738,6 +1743,64 @@ pub(crate) fn clean_middle_ty<'tcx>(
}
}
+fn clean_middle_opaque_bounds<'tcx>(
+ cx: &mut DocContext<'tcx>,
+ bounds: Vec<ty::Predicate<'tcx>>,
+) -> Type {
+ let mut regions = vec![];
+ let mut has_sized = false;
+ let mut bounds = bounds
+ .iter()
+ .filter_map(|bound| {
+ let bound_predicate = bound.kind();
+ let trait_ref = match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
+ if let Some(r) = clean_middle_region(reg) {
+ regions.push(GenericBound::Outlives(r));
+ }
+ return None;
+ }
+ _ => return None,
+ };
+
+ if let Some(sized) = cx.tcx.lang_items().sized_trait() {
+ if trait_ref.def_id() == sized {
+ has_sized = true;
+ return None;
+ }
+ }
+
+ let bindings: ThinVec<_> = bounds
+ .iter()
+ .filter_map(|bound| {
+ if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder() {
+ if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
+ Some(TypeBinding {
+ assoc: projection_to_path_segment(proj.projection_ty, cx),
+ kind: TypeBindingKind::Equality {
+ term: clean_middle_term(proj.term, cx),
+ },
+ })
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
+ })
+ .collect::<Vec<_>>();
+ bounds.extend(regions);
+ if !has_sized && !bounds.is_empty() {
+ bounds.insert(0, GenericBound::maybe_sized(cx));
+ }
+ ImplTrait(bounds)
+}
+
pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
let def_id = cx.tcx.hir().local_def_id(field.hir_id).to_def_id();
clean_field_with_def_id(def_id, field.ident.name, clean_ty(field.ty, cx), cx)
@@ -1895,7 +1958,7 @@ fn clean_maybe_renamed_item<'tcx>(
) -> Vec<Item> {
use hir::ItemKind;
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
@@ -2037,11 +2100,11 @@ fn clean_extern_crate<'tcx>(
cx: &mut DocContext<'tcx>,
) -> Vec<Item> {
// this is the ID of the `extern crate` statement
- let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
+ let cnum = cx.tcx.extern_mod_stmt_cnum(krate.owner_id.def_id).unwrap_or(LOCAL_CRATE);
// this is the ID of the crate itself
let crate_def_id = cnum.as_def_id();
let attrs = cx.tcx.hir().attrs(krate.hir_id());
- let ty_vis = cx.tcx.visibility(krate.def_id);
+ let ty_vis = cx.tcx.visibility(krate.owner_id);
let please_inline = ty_vis.is_public()
&& attrs.iter().any(|a| {
a.has_name(sym::doc)
@@ -2059,7 +2122,7 @@ fn clean_extern_crate<'tcx>(
if let Some(items) = inline::try_inline(
cx,
cx.tcx.parent_module(krate.hir_id()).to_def_id(),
- Some(krate.def_id.to_def_id()),
+ Some(krate.owner_id.to_def_id()),
res,
name,
Some(attrs),
@@ -2095,11 +2158,11 @@ fn clean_use_statement<'tcx>(
return Vec::new();
}
- let visibility = cx.tcx.visibility(import.def_id);
+ let visibility = cx.tcx.visibility(import.owner_id);
let attrs = cx.tcx.hir().attrs(import.hir_id());
let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
let pub_underscore = visibility.is_public() && name == kw::Underscore;
- let current_mod = cx.tcx.parent_module_from_def_id(import.def_id);
+ let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id);
// The parent of the module in which this import resides. This
// is the same as `current_mod` if that's already the top
@@ -2170,7 +2233,7 @@ fn clean_use_statement<'tcx>(
}
if !denied {
let mut visited = FxHashSet::default();
- let import_def_id = import.def_id.to_def_id();
+ let import_def_id = import.owner_id.to_def_id();
if let Some(mut items) = inline::try_inline(
cx,
@@ -2193,7 +2256,7 @@ fn clean_use_statement<'tcx>(
Import::new_simple(name, resolve_use_source(cx, path), true)
};
- vec![Item::from_def_id_and_parts(import.def_id.to_def_id(), None, ImportItem(inner), cx)]
+ vec![Item::from_def_id_and_parts(import.owner_id.to_def_id(), None, ImportItem(inner), cx)]
}
fn clean_maybe_renamed_foreign_item<'tcx>(
@@ -2201,7 +2264,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
item: &hir::ForeignItem<'tcx>,
renamed: Option<Symbol>,
) -> Item {
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
hir::ForeignItemKind::Fn(decl, names, generics) => {
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index af7813a77..1bcb9fcd5 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -14,7 +14,6 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def_id::DefId;
use rustc_middle::ty;
-use rustc_span::Symbol;
use crate::clean;
use crate::clean::GenericArgs as PP;
@@ -26,38 +25,37 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
//
// We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to
// the order of the generated bounds.
- let mut params: FxIndexMap<Symbol, (Vec<_>, Vec<_>)> = FxIndexMap::default();
+ let mut tybounds = FxIndexMap::default();
let mut lifetimes = Vec::new();
let mut equalities = Vec::new();
- let mut tybounds = Vec::new();
for clause in clauses {
match clause {
- WP::BoundPredicate { ty, bounds, bound_params } => match ty {
- clean::Generic(s) => {
- let (b, p) = params.entry(s).or_default();
- b.extend(bounds);
- p.extend(bound_params);
- }
- t => tybounds.push((t, (bounds, bound_params))),
- },
+ WP::BoundPredicate { ty, bounds, bound_params } => {
+ let (b, p): &mut (Vec<_>, Vec<_>) = tybounds.entry(ty).or_default();
+ b.extend(bounds);
+ p.extend(bound_params);
+ }
WP::RegionPredicate { lifetime, bounds } => {
lifetimes.push((lifetime, bounds));
}
- WP::EqPredicate { lhs, rhs } => equalities.push((lhs, rhs)),
+ WP::EqPredicate { lhs, rhs, bound_params } => equalities.push((lhs, rhs, bound_params)),
}
}
// Look for equality predicates on associated types that can be merged into
- // general bound predicates
- equalities.retain(|&(ref lhs, ref rhs)| {
- let Some((self_, trait_did, name)) = lhs.projection() else {
- return true;
- };
- let clean::Generic(generic) = self_ else { return true };
- let Some((bounds, _)) = params.get_mut(generic) else { return true };
-
- merge_bounds(cx, bounds, trait_did, name, rhs)
+ // general bound predicates.
+ equalities.retain(|&(ref lhs, ref rhs, ref bound_params)| {
+ let Some((ty, trait_did, name)) = lhs.projection() else { return true; };
+ let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
+ let bound_params = bound_params
+ .into_iter()
+ .map(|param| clean::GenericParamDef {
+ name: param.0,
+ kind: clean::GenericParamDefKind::Lifetime { outlives: Vec::new() },
+ })
+ .collect();
+ merge_bounds(cx, bounds, bound_params, trait_did, name, rhs)
});
// And finally, let's reassemble everything
@@ -65,23 +63,23 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
clauses.extend(
lifetimes.into_iter().map(|(lt, bounds)| WP::RegionPredicate { lifetime: lt, bounds }),
);
- clauses.extend(params.into_iter().map(|(k, (bounds, params))| WP::BoundPredicate {
- ty: clean::Generic(k),
- bounds,
- bound_params: params,
- }));
clauses.extend(tybounds.into_iter().map(|(ty, (bounds, bound_params))| WP::BoundPredicate {
ty,
bounds,
bound_params,
}));
- clauses.extend(equalities.into_iter().map(|(lhs, rhs)| WP::EqPredicate { lhs, rhs }));
+ clauses.extend(equalities.into_iter().map(|(lhs, rhs, bound_params)| WP::EqPredicate {
+ lhs,
+ rhs,
+ bound_params,
+ }));
clauses
}
pub(crate) fn merge_bounds(
cx: &clean::DocContext<'_>,
bounds: &mut Vec<clean::GenericBound>,
+ mut bound_params: Vec<clean::GenericParamDef>,
trait_did: DefId,
assoc: clean::PathSegment,
rhs: &clean::Term,
@@ -98,6 +96,14 @@ pub(crate) fn merge_bounds(
return false;
}
let last = trait_ref.trait_.segments.last_mut().expect("segments were empty");
+
+ trait_ref.generic_params.append(&mut bound_params);
+ // Since the parameters (probably) originate from `tcx.collect_*_late_bound_regions` which
+ // returns a hash set, sort them alphabetically to guarantee a stable and deterministic
+ // output (and to fully deduplicate them).
+ trait_ref.generic_params.sort_unstable_by(|p, q| p.name.as_str().cmp(q.name.as_str()));
+ trait_ref.generic_params.dedup_by_key(|p| p.name);
+
match last.args {
PP::AngleBracketed { ref mut bindings, .. } => {
bindings.push(clean::TypeBinding {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index f973fd088..cd1f972dc 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -21,6 +21,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{BodyId, Mutability};
+use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, TyCtxt};
@@ -31,7 +32,6 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{self, FileName, Loc};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
-use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
use crate::clean::cfg::Cfg;
use crate::clean::clean_visibility;
@@ -119,7 +119,7 @@ pub(crate) struct Crate {
pub(crate) module: Item,
pub(crate) primitives: ThinVec<(DefId, PrimitiveType)>,
/// Only here so that they can be filtered through the rustdoc passes.
- pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
+ pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
}
impl Crate {
@@ -132,13 +132,6 @@ impl Crate {
}
}
-/// This struct is used to wrap additional information added by rustdoc on a `trait` item.
-#[derive(Clone, Debug)]
-pub(crate) struct TraitWithExtraInfo {
- pub(crate) trait_: Trait,
- pub(crate) is_notable: bool,
-}
-
#[derive(Copy, Clone, Debug)]
pub(crate) struct ExternalCrate {
pub(crate) crate_num: CrateNum,
@@ -247,13 +240,13 @@ impl ExternalCrate {
let item = tcx.hir().item(id);
match item.kind {
hir::ItemKind::Mod(_) => {
- as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
+ as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
}
hir::ItemKind::Use(path, hir::UseKind::Single)
- if tcx.visibility(id.def_id).is_public() =>
+ if tcx.visibility(id.owner_id).is_public() =>
{
as_keyword(path.res.expect_non_local())
- .map(|(_, prim)| (id.def_id.to_def_id(), prim))
+ .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
}
_ => None,
}
@@ -315,14 +308,14 @@ impl ExternalCrate {
let item = tcx.hir().item(id);
match item.kind {
hir::ItemKind::Mod(_) => {
- as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
+ as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
}
hir::ItemKind::Use(path, hir::UseKind::Single)
- if tcx.visibility(id.def_id).is_public() =>
+ if tcx.visibility(id.owner_id).is_public() =>
{
as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
// Pretend the primitive is local.
- (id.def_id.to_def_id(), prim)
+ (id.owner_id.to_def_id(), prim)
})
}
_ => None,
@@ -689,7 +682,7 @@ impl Item {
let abi = tcx.fn_sig(self.item_id.as_def_id().unwrap()).abi();
hir::FnHeader {
unsafety: if abi == Abi::RustIntrinsic {
- intrinsic_operation_unsafety(self.name.unwrap())
+ intrinsic_operation_unsafety(tcx, self.item_id.as_def_id().unwrap())
} else {
hir::Unsafety::Unsafe
},
@@ -1357,7 +1350,7 @@ impl Lifetime {
pub(crate) enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
- EqPredicate { lhs: Type, rhs: Term },
+ EqPredicate { lhs: Box<Type>, rhs: Box<Term>, bound_params: Vec<Lifetime> },
}
impl WherePredicate {
@@ -1368,6 +1361,15 @@ impl WherePredicate {
_ => None,
}
}
+
+ pub(crate) fn get_bound_params(&self) -> Option<&[Lifetime]> {
+ match self {
+ Self::BoundPredicate { bound_params, .. } | Self::EqPredicate { bound_params, .. } => {
+ Some(bound_params)
+ }
+ _ => None,
+ }
+ }
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -1530,6 +1532,9 @@ impl Trait {
pub(crate) fn is_auto(&self, tcx: TyCtxt<'_>) -> bool {
tcx.trait_is_auto(self.def_id)
}
+ pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
+ tcx.is_doc_notable_trait(self.def_id)
+ }
pub(crate) fn unsafety(&self, tcx: TyCtxt<'_>) -> hir::Unsafety {
tcx.trait_def(self.def_id).unsafety
}
@@ -2201,8 +2206,11 @@ impl Path {
/// Checks if this is a `T::Name` path for an associated type.
pub(crate) fn is_assoc_ty(&self) -> bool {
match self.res {
- Res::SelfTy { .. } if self.segments.len() != 1 => true,
- Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true,
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
+ if self.segments.len() != 1 =>
+ {
+ true
+ }
Res::Def(DefKind::AssocTy, _) => true,
_ => false,
}
@@ -2532,15 +2540,15 @@ impl SubstParam {
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
- // These are in alphabetical order, which is easy to maintain.
+ // tidy-alphabetical-start
static_assert_size!(Crate, 72); // frequently moved by-value
static_assert_size!(DocFragment, 32);
- #[cfg(not(bootstrap))]
- static_assert_size!(GenericArg, 56);
+ static_assert_size!(GenericArg, 48);
static_assert_size!(GenericArgs, 32);
static_assert_size!(GenericParamDef, 56);
static_assert_size!(Item, 56);
- static_assert_size!(ItemKind, 96);
+ static_assert_size!(ItemKind, 88);
static_assert_size!(PathSegment, 40);
- static_assert_size!(Type, 56);
+ static_assert_size!(Type, 48);
+ // tidy-alphabetical-end
}
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 3eaedaf10..58767d3a4 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -7,7 +7,6 @@ use crate::clean::{
PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
};
use crate::core::DocContext;
-use crate::formats::item_type::ItemType;
use crate::visit_lib::LibEmbargoVisitor;
use rustc_ast as ast;
@@ -234,8 +233,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
match n.kind() {
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) => {
- assert_eq!(promoted, ());
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs: _ }) => {
let s = if let Some(def) = def.as_local() {
print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(def.did))
} else {
@@ -305,9 +303,9 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
.collect()
}
-fn print_const_with_custom_print_scalar(
- tcx: TyCtxt<'_>,
- ct: mir::ConstantKind<'_>,
+fn print_const_with_custom_print_scalar<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ct: mir::ConstantKind<'tcx>,
underscores_and_type: bool,
) -> String {
// Use a slightly different format for integer types which always shows the actual value.
@@ -321,7 +319,7 @@ fn print_const_with_custom_print_scalar(
}
}
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => {
- let ty = tcx.lift(ct.ty()).unwrap();
+ let ty = ct.ty();
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
let data = int.assert_bits(size);
let sign_extended_data = size.sign_extend(data) as i128;
@@ -455,7 +453,9 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
match path.res {
Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
- Res::SelfTy { .. } if path.segments.len() == 1 => Generic(kw::SelfUpper),
+ Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => {
+ Generic(kw::SelfUpper)
+ }
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
_ => {
let _ = register_res(cx, path.res);
@@ -503,9 +503,6 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
return did;
}
inline::record_extern_fqn(cx, did, kind);
- if let ItemType::Trait = kind {
- inline::record_extern_trait(cx, did);
- }
did
}