Rollup merge of #134321 - dtolnay:docassocconst, r=fmease

Hide `= _` as associated constant value inside impl blocks

Closes #134320.

### Before:

<img src="https://github.com/user-attachments/assets/19d28811-45d2-4563-9726-f40c6af411c6" width="300">&nbsp;<img src="https://github.com/user-attachments/assets/1ecf8764-97ce-47f0-87fa-3b174d2fc578" width="300">

### After:

<img src="https://github.com/user-attachments/assets/6408c4ca-b1c4-42e4-884b-248833a4865f" width="300">&nbsp;<img src="https://github.com/user-attachments/assets/df2f6981-16f6-409f-8abb-73c0a4a71d6b" width="300">

r? `@fmease`
This commit is contained in:
Jacob Pratt 2024-12-20 01:36:47 -05:00 committed by GitHub
commit f14d69c853
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 201 additions and 100 deletions

View file

@ -1222,14 +1222,16 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
let local_did = trait_item.owner_id.to_def_id(); let local_did = trait_item.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| { cx.with_param_env(local_did, |cx| {
let inner = match trait_item.kind { let inner = match trait_item.kind {
hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(Box::new(Constant { hir::TraitItemKind::Const(ty, Some(default)) => {
generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)), ProvidedAssocConstItem(Box::new(Constant {
kind: ConstantKind::Local { def_id: local_did, body: default }, generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)),
type_: clean_ty(ty, cx), kind: ConstantKind::Local { def_id: local_did, body: default },
})), type_: clean_ty(ty, cx),
}))
}
hir::TraitItemKind::Const(ty, None) => { hir::TraitItemKind::Const(ty, None) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
TyAssocConstItem(generics, Box::new(clean_ty(ty, cx))) RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx)))
} }
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body)); let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
@ -1237,7 +1239,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
} }
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names)); let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names));
TyMethodItem(m) RequiredMethodItem(m)
} }
hir::TraitItemKind::Type(bounds, Some(default)) => { hir::TraitItemKind::Type(bounds, Some(default)) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
@ -1257,7 +1259,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
hir::TraitItemKind::Type(bounds, None) => { hir::TraitItemKind::Type(bounds, None) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
TyAssocTypeItem(generics, bounds) RequiredAssocTypeItem(generics, bounds)
} }
}; };
Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx) Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx)
@ -1271,7 +1273,7 @@ pub(crate) fn clean_impl_item<'tcx>(
let local_did = impl_.owner_id.to_def_id(); let local_did = impl_.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| { cx.with_param_env(local_did, |cx| {
let inner = match impl_.kind { let inner = match impl_.kind {
hir::ImplItemKind::Const(ty, expr) => AssocConstItem(Box::new(Constant { hir::ImplItemKind::Const(ty, expr) => ImplAssocConstItem(Box::new(Constant {
generics: clean_generics(impl_.generics, cx), generics: clean_generics(impl_.generics, cx),
kind: ConstantKind::Local { def_id: local_did, body: expr }, kind: ConstantKind::Local { def_id: local_did, body: expr },
type_: clean_ty(ty, cx), type_: clean_ty(ty, cx),
@ -1320,18 +1322,23 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
); );
simplify::move_bounds_to_generic_parameters(&mut generics); simplify::move_bounds_to_generic_parameters(&mut generics);
let provided = match assoc_item.container { match assoc_item.container {
ty::AssocItemContainer::Impl => true, ty::AssocItemContainer::Impl => ImplAssocConstItem(Box::new(Constant {
ty::AssocItemContainer::Trait => tcx.defaultness(assoc_item.def_id).has_value(),
};
if provided {
AssocConstItem(Box::new(Constant {
generics, generics,
kind: ConstantKind::Extern { def_id: assoc_item.def_id }, kind: ConstantKind::Extern { def_id: assoc_item.def_id },
type_: ty, type_: ty,
})) })),
} else { ty::AssocItemContainer::Trait => {
TyAssocConstItem(generics, Box::new(ty)) if tcx.defaultness(assoc_item.def_id).has_value() {
ProvidedAssocConstItem(Box::new(Constant {
generics,
kind: ConstantKind::Extern { def_id: assoc_item.def_id },
type_: ty,
}))
} else {
RequiredAssocConstItem(generics, Box::new(ty))
}
}
} }
} }
ty::AssocKind::Fn => { ty::AssocKind::Fn => {
@ -1369,7 +1376,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
}; };
MethodItem(item, defaultness) MethodItem(item, defaultness)
} else { } else {
TyMethodItem(item) RequiredMethodItem(item)
} }
} }
ty::AssocKind::Type => { ty::AssocKind::Type => {
@ -1486,7 +1493,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
bounds, bounds,
) )
} else { } else {
TyAssocTypeItem(generics, bounds) RequiredAssocTypeItem(generics, bounds)
} }
} else { } else {
AssocTypeItem( AssocTypeItem(

View file

@ -545,14 +545,14 @@ impl Item {
pub(crate) fn is_associated_type(&self) -> bool { pub(crate) fn is_associated_type(&self) -> bool {
matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..))) matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
} }
pub(crate) fn is_ty_associated_type(&self) -> bool { pub(crate) fn is_required_associated_type(&self) -> bool {
matches!(self.kind, TyAssocTypeItem(..) | StrippedItem(box TyAssocTypeItem(..))) matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
} }
pub(crate) fn is_associated_const(&self) -> bool { pub(crate) fn is_associated_const(&self) -> bool {
matches!(self.kind, AssocConstItem(..) | StrippedItem(box AssocConstItem(..))) matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
} }
pub(crate) fn is_ty_associated_const(&self) -> bool { pub(crate) fn is_required_associated_const(&self) -> bool {
matches!(self.kind, TyAssocConstItem(..) | StrippedItem(box TyAssocConstItem(..))) matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
} }
pub(crate) fn is_method(&self) -> bool { pub(crate) fn is_method(&self) -> bool {
self.type_() == ItemType::Method self.type_() == ItemType::Method
@ -669,7 +669,9 @@ impl Item {
asyncness: hir::IsAsync::NotAsync, asyncness: hir::IsAsync::NotAsync,
} }
} }
ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => { ItemKind::FunctionItem(_)
| ItemKind::MethodItem(_, _)
| ItemKind::RequiredMethodItem(_) => {
let def_id = self.def_id().unwrap(); let def_id = self.def_id().unwrap();
build_fn_header(def_id, tcx, tcx.asyncness(def_id)) build_fn_header(def_id, tcx, tcx.asyncness(def_id))
} }
@ -699,8 +701,13 @@ impl Item {
// Variants always inherit visibility // Variants always inherit visibility
VariantItem(..) | ImplItem(..) => return None, VariantItem(..) | ImplItem(..) => return None,
// Trait items inherit the trait's visibility // Trait items inherit the trait's visibility
AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..) RequiredAssocConstItem(..)
| TyMethodItem(..) | MethodItem(..) => { | ProvidedAssocConstItem(..)
| ImplAssocConstItem(..)
| AssocTypeItem(..)
| RequiredAssocTypeItem(..)
| RequiredMethodItem(..)
| MethodItem(..) => {
let assoc_item = tcx.associated_item(def_id); let assoc_item = tcx.associated_item(def_id);
let is_trait_item = match assoc_item.container { let is_trait_item = match assoc_item.container {
ty::AssocItemContainer::Trait => true, ty::AssocItemContainer::Trait => true,
@ -845,10 +852,10 @@ pub(crate) enum ItemKind {
TraitAliasItem(TraitAlias), TraitAliasItem(TraitAlias),
ImplItem(Box<Impl>), ImplItem(Box<Impl>),
/// A required method in a trait declaration meaning it's only a function signature. /// A required method in a trait declaration meaning it's only a function signature.
TyMethodItem(Box<Function>), RequiredMethodItem(Box<Function>),
/// A method in a trait impl or a provided method in a trait declaration. /// A method in a trait impl or a provided method in a trait declaration.
/// ///
/// Compared to [TyMethodItem], it also contains a method body. /// Compared to [RequiredMethodItem], it also contains a method body.
MethodItem(Box<Function>, Option<hir::Defaultness>), MethodItem(Box<Function>, Option<hir::Defaultness>),
StructFieldItem(Type), StructFieldItem(Type),
VariantItem(Variant), VariantItem(Variant),
@ -862,14 +869,16 @@ pub(crate) enum ItemKind {
ProcMacroItem(ProcMacro), ProcMacroItem(ProcMacro),
PrimitiveItem(PrimitiveType), PrimitiveItem(PrimitiveType),
/// A required associated constant in a trait declaration. /// A required associated constant in a trait declaration.
TyAssocConstItem(Generics, Box<Type>), RequiredAssocConstItem(Generics, Box<Type>),
ConstantItem(Box<Constant>), ConstantItem(Box<Constant>),
/// An associated constant in a trait impl or a provided one in a trait declaration. /// An associated constant in a trait declaration with provided default value.
AssocConstItem(Box<Constant>), ProvidedAssocConstItem(Box<Constant>),
/// An associated constant in an inherent impl or trait impl.
ImplAssocConstItem(Box<Constant>),
/// A required associated type in a trait declaration. /// A required associated type in a trait declaration.
/// ///
/// The bounds may be non-empty if there is a `where` clause. /// The bounds may be non-empty if there is a `where` clause.
TyAssocTypeItem(Generics, Vec<GenericBound>), RequiredAssocTypeItem(Generics, Vec<GenericBound>),
/// An associated type in a trait impl or a provided one in a trait declaration. /// An associated type in a trait impl or a provided one in a trait declaration.
AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>), AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
/// An item that has been stripped by a rustdoc pass /// An item that has been stripped by a rustdoc pass
@ -900,7 +909,7 @@ impl ItemKind {
| StaticItem(_) | StaticItem(_)
| ConstantItem(_) | ConstantItem(_)
| TraitAliasItem(_) | TraitAliasItem(_)
| TyMethodItem(_) | RequiredMethodItem(_)
| MethodItem(_, _) | MethodItem(_, _)
| StructFieldItem(_) | StructFieldItem(_)
| ForeignFunctionItem(_, _) | ForeignFunctionItem(_, _)
@ -909,9 +918,10 @@ impl ItemKind {
| MacroItem(_) | MacroItem(_)
| ProcMacroItem(_) | ProcMacroItem(_)
| PrimitiveItem(_) | PrimitiveItem(_)
| TyAssocConstItem(..) | RequiredAssocConstItem(..)
| AssocConstItem(..) | ProvidedAssocConstItem(..)
| TyAssocTypeItem(..) | ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..) | AssocTypeItem(..)
| StrippedItem(_) | StrippedItem(_)
| KeywordItem => [].iter(), | KeywordItem => [].iter(),

View file

@ -82,7 +82,7 @@ pub(crate) trait DocFolder: Sized {
| StaticItem(_) | StaticItem(_)
| ConstantItem(..) | ConstantItem(..)
| TraitAliasItem(_) | TraitAliasItem(_)
| TyMethodItem(_) | RequiredMethodItem(_)
| MethodItem(_, _) | MethodItem(_, _)
| StructFieldItem(_) | StructFieldItem(_)
| ForeignFunctionItem(..) | ForeignFunctionItem(..)
@ -91,9 +91,10 @@ pub(crate) trait DocFolder: Sized {
| MacroItem(_) | MacroItem(_)
| ProcMacroItem(_) | ProcMacroItem(_)
| PrimitiveItem(_) | PrimitiveItem(_)
| TyAssocConstItem(..) | RequiredAssocConstItem(..)
| AssocConstItem(..) | ProvidedAssocConstItem(..)
| TyAssocTypeItem(..) | ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..) | AssocTypeItem(..)
| KeywordItem => kind, | KeywordItem => kind,
} }

View file

@ -334,12 +334,13 @@ impl DocFolder for CacheBuilder<'_, '_> {
clean::ExternCrateItem { .. } clean::ExternCrateItem { .. }
| clean::ImportItem(..) | clean::ImportItem(..)
| clean::ImplItem(..) | clean::ImplItem(..)
| clean::TyMethodItem(..) | clean::RequiredMethodItem(..)
| clean::MethodItem(..) | clean::MethodItem(..)
| clean::StructFieldItem(..) | clean::StructFieldItem(..)
| clean::TyAssocConstItem(..) | clean::RequiredAssocConstItem(..)
| clean::AssocConstItem(..) | clean::ProvidedAssocConstItem(..)
| clean::TyAssocTypeItem(..) | clean::ImplAssocConstItem(..)
| clean::RequiredAssocTypeItem(..)
| clean::AssocTypeItem(..) | clean::AssocTypeItem(..)
| clean::StrippedItem(..) | clean::StrippedItem(..)
| clean::KeywordItem => { | clean::KeywordItem => {
@ -443,15 +444,17 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
let item_def_id = item.item_id.as_def_id().unwrap(); let item_def_id = item.item_id.as_def_id().unwrap();
let (parent_did, parent_path) = match item.kind { let (parent_did, parent_path) = match item.kind {
clean::StrippedItem(..) => return, clean::StrippedItem(..) => return,
clean::AssocConstItem(..) | clean::AssocTypeItem(..) clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::AssocTypeItem(..)
if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) => if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) =>
{ {
// skip associated items in trait impls // skip associated items in trait impls
return; return;
} }
clean::TyMethodItem(..) clean::RequiredMethodItem(..)
| clean::TyAssocConstItem(..) | clean::RequiredAssocConstItem(..)
| clean::TyAssocTypeItem(..) | clean::RequiredAssocTypeItem(..)
| clean::StructFieldItem(..) | clean::StructFieldItem(..)
| clean::VariantItem(..) => { | clean::VariantItem(..) => {
// Don't index if containing module is stripped (i.e., private), // Don't index if containing module is stripped (i.e., private),
@ -467,7 +470,10 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
let parent_path = &cache.stack[..cache.stack.len() - 1]; let parent_path = &cache.stack[..cache.stack.len() - 1];
(Some(parent_did), parent_path) (Some(parent_did), parent_path)
} }
clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { clean::MethodItem(..)
| clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::AssocTypeItem(..) => {
let last = cache.parent_stack.last().expect("parent_stack is empty 2"); let last = cache.parent_stack.last().expect("parent_stack is empty 2");
let parent_did = match last { let parent_did = match last {
// impl Trait for &T { fn method(self); } // impl Trait for &T { fn method(self); }

View file

@ -88,7 +88,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
clean::ConstantItem(..) => ItemType::Constant, clean::ConstantItem(..) => ItemType::Constant,
clean::TraitItem(..) => ItemType::Trait, clean::TraitItem(..) => ItemType::Trait,
clean::ImplItem(..) => ItemType::Impl, clean::ImplItem(..) => ItemType::Impl,
clean::TyMethodItem(..) => ItemType::TyMethod, clean::RequiredMethodItem(..) => ItemType::TyMethod,
clean::MethodItem(..) => ItemType::Method, clean::MethodItem(..) => ItemType::Method,
clean::StructFieldItem(..) => ItemType::StructField, clean::StructFieldItem(..) => ItemType::StructField,
clean::VariantItem(..) => ItemType::Variant, clean::VariantItem(..) => ItemType::Variant,
@ -96,8 +96,10 @@ impl<'a> From<&'a clean::Item> for ItemType {
clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic
clean::MacroItem(..) => ItemType::Macro, clean::MacroItem(..) => ItemType::Macro,
clean::PrimitiveItem(..) => ItemType::Primitive, clean::PrimitiveItem(..) => ItemType::Primitive,
clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst, clean::RequiredAssocConstItem(..)
clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType, | clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..) => ItemType::AssocConst,
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
clean::ForeignTypeItem => ItemType::ForeignType, clean::ForeignTypeItem => ItemType::ForeignType,
clean::KeywordItem => ItemType::Keyword, clean::KeywordItem => ItemType::Keyword,
clean::TraitAliasItem(..) => ItemType::TraitAlias, clean::TraitAliasItem(..) => ItemType::TraitAlias,

View file

@ -836,12 +836,23 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
href.map(|href| format!(" href=\"{href}\"")).unwrap_or_default() href.map(|href| format!(" href=\"{href}\"")).unwrap_or_default()
} }
#[derive(Debug)]
enum AssocConstValue<'a> {
// In trait definitions, it is relevant for the public API whether an
// associated constant comes with a default value, so even if we cannot
// render its value, the presence of a value must be shown using `= _`.
TraitDefault(&'a clean::ConstantKind),
// In impls, there is no need to show `= _`.
Impl(&'a clean::ConstantKind),
None,
}
fn assoc_const( fn assoc_const(
w: &mut Buffer, w: &mut Buffer,
it: &clean::Item, it: &clean::Item,
generics: &clean::Generics, generics: &clean::Generics,
ty: &clean::Type, ty: &clean::Type,
default: Option<&clean::ConstantKind>, value: AssocConstValue<'_>,
link: AssocItemLink<'_>, link: AssocItemLink<'_>,
indent: usize, indent: usize,
cx: &Context<'_>, cx: &Context<'_>,
@ -857,15 +868,20 @@ fn assoc_const(
generics = generics.print(cx), generics = generics.print(cx),
ty = ty.print(cx), ty = ty.print(cx),
); );
if let Some(default) = default { if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
w.write_str(" = ");
// FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
// hood which adds noisy underscores and a type suffix to number literals. // hood which adds noisy underscores and a type suffix to number literals.
// This hurts readability in this context especially when more complex expressions // This hurts readability in this context especially when more complex expressions
// are involved and it doesn't add much of value. // are involved and it doesn't add much of value.
// Find a way to print constants here without all that jazz. // Find a way to print constants here without all that jazz.
write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx)))); let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx));
if match value {
AssocConstValue::TraitDefault(_) => true, // always show
AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show
AssocConstValue::None => unreachable!(),
} {
write!(w, " = {}", Escape(&repr));
}
} }
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline)); write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
} }
@ -1076,33 +1092,43 @@ fn render_assoc_item(
) { ) {
match &item.kind { match &item.kind {
clean::StrippedItem(..) => {} clean::StrippedItem(..) => {}
clean::TyMethodItem(m) => { clean::RequiredMethodItem(m) => {
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
} }
clean::MethodItem(m, _) => { clean::MethodItem(m, _) => {
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
} }
clean::TyAssocConstItem(generics, ty) => assoc_const( clean::RequiredAssocConstItem(generics, ty) => assoc_const(
w, w,
item, item,
generics, generics,
ty, ty,
None, AssocConstValue::None,
link, link,
if parent == ItemType::Trait { 4 } else { 0 }, if parent == ItemType::Trait { 4 } else { 0 },
cx, cx,
), ),
clean::AssocConstItem(ci) => assoc_const( clean::ProvidedAssocConstItem(ci) => assoc_const(
w, w,
item, item,
&ci.generics, &ci.generics,
&ci.type_, &ci.type_,
Some(&ci.kind), AssocConstValue::TraitDefault(&ci.kind),
link, link,
if parent == ItemType::Trait { 4 } else { 0 }, if parent == ItemType::Trait { 4 } else { 0 },
cx, cx,
), ),
clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type( clean::ImplAssocConstItem(ci) => assoc_const(
w,
item,
&ci.generics,
&ci.type_,
AssocConstValue::Impl(&ci.kind),
link,
if parent == ItemType::Trait { 4 } else { 0 },
cx,
),
clean::RequiredAssocTypeItem(ref generics, ref bounds) => assoc_type(
w, w,
item, item,
generics, generics,
@ -1384,7 +1410,7 @@ fn render_deref_methods(
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool { fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
let self_type_opt = match item.kind { let self_type_opt = match item.kind {
clean::MethodItem(ref method, _) => method.decl.receiver_type(), clean::MethodItem(ref method, _) => method.decl.receiver_type(),
clean::TyMethodItem(ref method) => method.decl.receiver_type(), clean::RequiredMethodItem(ref method) => method.decl.receiver_type(),
_ => None, _ => None,
}; };
@ -1660,7 +1686,7 @@ fn render_impl(
write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>"); write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
} }
match &item.kind { match &item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => { clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
// Only render when the method is not static or we allow static methods // Only render when the method is not static or we allow static methods
if render_method_item { if render_method_item {
let id = cx.derive_id(format!("{item_type}.{name}")); let id = cx.derive_id(format!("{item_type}.{name}"));
@ -1690,7 +1716,7 @@ fn render_impl(
w.write_str("</h4></section>"); w.write_str("</h4></section>");
} }
} }
clean::TyAssocConstItem(ref generics, ref ty) => { clean::RequiredAssocConstItem(ref generics, ref ty) => {
let source_id = format!("{item_type}.{name}"); let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id); let id = cx.derive_id(&source_id);
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"); write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
@ -1705,14 +1731,14 @@ fn render_impl(
item, item,
generics, generics,
ty, ty,
None, AssocConstValue::None,
link.anchor(if trait_.is_some() { &source_id } else { &id }), link.anchor(if trait_.is_some() { &source_id } else { &id }),
0, 0,
cx, cx,
); );
w.write_str("</h4></section>"); w.write_str("</h4></section>");
} }
clean::AssocConstItem(ci) => { clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
let source_id = format!("{item_type}.{name}"); let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id); let id = cx.derive_id(&source_id);
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"); write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
@ -1727,14 +1753,18 @@ fn render_impl(
item, item,
&ci.generics, &ci.generics,
&ci.type_, &ci.type_,
Some(&ci.kind), match item.kind {
clean::ProvidedAssocConstItem(_) => AssocConstValue::TraitDefault(&ci.kind),
clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
_ => unreachable!(),
},
link.anchor(if trait_.is_some() { &source_id } else { &id }), link.anchor(if trait_.is_some() { &source_id } else { &id }),
0, 0,
cx, cx,
); );
w.write_str("</h4></section>"); w.write_str("</h4></section>");
} }
clean::TyAssocTypeItem(ref generics, ref bounds) => { clean::RequiredAssocTypeItem(ref generics, ref bounds) => {
let source_id = format!("{item_type}.{name}"); let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id); let id = cx.derive_id(&source_id);
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"); write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
@ -1809,11 +1839,13 @@ fn render_impl(
if !impl_.is_negative_trait_impl() { if !impl_.is_negative_trait_impl() {
for trait_item in &impl_.items { for trait_item in &impl_.items {
match trait_item.kind { match trait_item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => methods.push(trait_item), clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(trait_item),
clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => { clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
assoc_types.push(trait_item) assoc_types.push(trait_item)
} }
clean::TyAssocConstItem(..) | clean::AssocConstItem(_) => { clean::RequiredAssocConstItem(..)
| clean::ProvidedAssocConstItem(_)
| clean::ImplAssocConstItem(_) => {
// We render it directly since they're supposed to come first. // We render it directly since they're supposed to come first.
doc_impl_item( doc_impl_item(
&mut default_impl_items, &mut default_impl_items,

View file

@ -651,9 +651,11 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
let tcx = cx.tcx(); let tcx = cx.tcx();
let bounds = bounds(&t.bounds, false, cx); let bounds = bounds(&t.bounds, false, cx);
let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::<Vec<_>>(); let required_types =
t.items.iter().filter(|m| m.is_required_associated_type()).collect::<Vec<_>>();
let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>(); let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
let required_consts = t.items.iter().filter(|m| m.is_ty_associated_const()).collect::<Vec<_>>(); let required_consts =
t.items.iter().filter(|m| m.is_required_associated_const()).collect::<Vec<_>>();
let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>(); let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>(); let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>(); let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();

View file

@ -837,7 +837,7 @@ pub(crate) fn get_function_type_for_search(
clean::ForeignFunctionItem(ref f, _) clean::ForeignFunctionItem(ref f, _)
| clean::FunctionItem(ref f) | clean::FunctionItem(ref f)
| clean::MethodItem(ref f, _) | clean::MethodItem(ref f, _)
| clean::TyMethodItem(ref f) => { | clean::RequiredMethodItem(ref f) => {
get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache) get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
} }
_ => return None, _ => return None,
@ -1207,10 +1207,11 @@ fn simplify_fn_type<'a, 'tcx>(
&& let Type::Path { path } = arg && let Type::Path { path } = arg
&& let def_id = path.def_id() && let def_id = path.def_id()
&& let Some(trait_) = cache.traits.get(&def_id) && let Some(trait_) = cache.traits.get(&def_id)
&& trait_.items.iter().any(|at| at.is_ty_associated_type()) && trait_.items.iter().any(|at| at.is_required_associated_type())
{ {
for assoc_ty in &trait_.items { for assoc_ty in &trait_.items {
if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &assoc_ty.kind if let clean::ItemKind::RequiredAssocTypeItem(_generics, bounds) =
&assoc_ty.kind
&& let Some(name) = assoc_ty.name && let Some(name) = assoc_ty.name
{ {
let idx = -isize::try_from(rgen.len() + 1).unwrap(); let idx = -isize::try_from(rgen.len() + 1).unwrap();

View file

@ -282,10 +282,10 @@ fn sidebar_trait<'a>(
res res
} }
let req_assoc = filter_items(&t.items, |m| m.is_ty_associated_type(), "associatedtype"); let req_assoc = filter_items(&t.items, |m| m.is_required_associated_type(), "associatedtype");
let prov_assoc = filter_items(&t.items, |m| m.is_associated_type(), "associatedtype"); let prov_assoc = filter_items(&t.items, |m| m.is_associated_type(), "associatedtype");
let req_assoc_const = let req_assoc_const =
filter_items(&t.items, |m| m.is_ty_associated_const(), "associatedconstant"); filter_items(&t.items, |m| m.is_required_associated_const(), "associatedconstant");
let prov_assoc_const = let prov_assoc_const =
filter_items(&t.items, |m| m.is_associated_const(), "associatedconstant"); filter_items(&t.items, |m| m.is_associated_const(), "associatedconstant");
let req_method = filter_items(&t.items, |m| m.is_ty_method(), "tymethod"); let req_method = filter_items(&t.items, |m| m.is_ty_method(), "tymethod");

View file

@ -319,7 +319,9 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
TraitItem(t) => ItemEnum::Trait((*t).into_json(renderer)), TraitItem(t) => ItemEnum::Trait((*t).into_json(renderer)),
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)),
MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)), MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)),
TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), renderer)), RequiredMethodItem(m) => {
ItemEnum::Function(from_function(m, false, header.unwrap(), renderer))
}
ImplItem(i) => ItemEnum::Impl((*i).into_json(renderer)), ImplItem(i) => ItemEnum::Impl((*i).into_json(renderer)),
StaticItem(s) => ItemEnum::Static(convert_static(s, rustc_hir::Safety::Safe, renderer)), StaticItem(s) => ItemEnum::Static(convert_static(s, rustc_hir::Safety::Safe, renderer)),
ForeignStaticItem(s, safety) => ItemEnum::Static(convert_static(s, safety, renderer)), ForeignStaticItem(s, safety) => ItemEnum::Static(convert_static(s, safety, renderer)),
@ -339,15 +341,15 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
}) })
} }
// FIXME(generic_const_items): Add support for generic associated consts. // FIXME(generic_const_items): Add support for generic associated consts.
TyAssocConstItem(_generics, ty) => { RequiredAssocConstItem(_generics, ty) => {
ItemEnum::AssocConst { type_: (*ty).into_json(renderer), value: None } ItemEnum::AssocConst { type_: (*ty).into_json(renderer), value: None }
} }
// FIXME(generic_const_items): Add support for generic associated consts. // FIXME(generic_const_items): Add support for generic associated consts.
AssocConstItem(ci) => ItemEnum::AssocConst { ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst {
type_: ci.type_.into_json(renderer), type_: ci.type_.into_json(renderer),
value: Some(ci.kind.expr(renderer.tcx)), value: Some(ci.kind.expr(renderer.tcx)),
}, },
TyAssocTypeItem(g, b) => ItemEnum::AssocType { RequiredAssocTypeItem(g, b) => ItemEnum::AssocType {
generics: g.into_json(renderer), generics: g.into_json(renderer),
bounds: b.into_json(renderer), bounds: b.into_json(renderer),
type_: None, type_: None,

View file

@ -72,10 +72,11 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
| clean::ForeignFunctionItem(..) | clean::ForeignFunctionItem(..)
| clean::ForeignStaticItem(..) | clean::ForeignStaticItem(..)
| clean::ForeignTypeItem | clean::ForeignTypeItem
| clean::AssocConstItem(..)
| clean::AssocTypeItem(..) | clean::AssocTypeItem(..)
| clean::TyAssocConstItem(..) | clean::RequiredAssocConstItem(..)
| clean::TyAssocTypeItem(..) | clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::RequiredAssocTypeItem(..)
// check for trait impl // check for trait impl
| clean::ImplItem(box clean::Impl { trait_: Some(_), .. }) | clean::ImplItem(box clean::Impl { trait_: Some(_), .. })
) )

View file

@ -67,11 +67,12 @@ impl DocFolder for StabilityPropagator<'_, '_> {
// Don't inherit the parent's stability for these items, because they // Don't inherit the parent's stability for these items, because they
// are potentially accessible even if the parent is more unstable. // are potentially accessible even if the parent is more unstable.
ItemKind::ImplItem(..) ItemKind::ImplItem(..)
| ItemKind::TyMethodItem(..) | ItemKind::RequiredMethodItem(..)
| ItemKind::MethodItem(..) | ItemKind::MethodItem(..)
| ItemKind::TyAssocConstItem(..) | ItemKind::RequiredAssocConstItem(..)
| ItemKind::AssocConstItem(..) | ItemKind::ProvidedAssocConstItem(..)
| ItemKind::TyAssocTypeItem(..) | ItemKind::ImplAssocConstItem(..)
| ItemKind::RequiredAssocTypeItem(..)
| ItemKind::AssocTypeItem(..) | ItemKind::AssocTypeItem(..)
| ItemKind::PrimitiveItem(..) | ItemKind::PrimitiveItem(..)
| ItemKind::KeywordItem => own_stability, | ItemKind::KeywordItem => own_stability,

View file

@ -79,7 +79,10 @@ impl DocFolder for Stripper<'_, '_> {
} }
} }
clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { clean::MethodItem(..)
| clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::AssocTypeItem(..) => {
let item_id = i.item_id; let item_id = i.item_id;
if item_id.is_local() if item_id.is_local()
&& !self.effective_visibilities.is_reachable(self.tcx, item_id.expect_def_id()) && !self.effective_visibilities.is_reachable(self.tcx, item_id.expect_def_id())
@ -118,7 +121,9 @@ impl DocFolder for Stripper<'_, '_> {
clean::ImplItem(..) => {} clean::ImplItem(..) => {}
// tymethods etc. have no control over privacy // tymethods etc. have no control over privacy
clean::TyMethodItem(..) | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) => {} clean::RequiredMethodItem(..)
| clean::RequiredAssocConstItem(..)
| clean::RequiredAssocTypeItem(..) => {}
// Proc-macros are always public // Proc-macros are always public
clean::ProcMacroItem(..) => {} clean::ProcMacroItem(..) => {}

View file

@ -35,7 +35,7 @@ pub(crate) trait DocVisitor<'a>: Sized {
| StaticItem(_) | StaticItem(_)
| ConstantItem(..) | ConstantItem(..)
| TraitAliasItem(_) | TraitAliasItem(_)
| TyMethodItem(_) | RequiredMethodItem(_)
| MethodItem(_, _) | MethodItem(_, _)
| StructFieldItem(_) | StructFieldItem(_)
| ForeignFunctionItem(..) | ForeignFunctionItem(..)
@ -44,9 +44,10 @@ pub(crate) trait DocVisitor<'a>: Sized {
| MacroItem(_) | MacroItem(_)
| ProcMacroItem(_) | ProcMacroItem(_)
| PrimitiveItem(_) | PrimitiveItem(_)
| TyAssocConstItem(..) | RequiredAssocConstItem(..)
| AssocConstItem(..) | ProvidedAssocConstItem(..)
| TyAssocTypeItem(..) | ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..) | AssocTypeItem(..)
| KeywordItem => {} | KeywordItem => {}
} }

View file

@ -0,0 +1,30 @@
pub struct Struct {
_private: (),
}
pub trait Trait {
//@ has assoc_consts_underscore/trait.Trait.html '//pre[@class="rust item-decl"]' \
// 'const REQUIRED: Struct;'
//@ !has - '//*[@id="associatedconstant.REQUIRED"]' 'const REQUIRED: Struct = _'
//@ has - '//*[@id="associatedconstant.REQUIRED"]' 'const REQUIRED: Struct'
const REQUIRED: Struct;
//@ has - '//pre[@class="rust item-decl"]' 'const OPTIONAL: Struct = _;'
//@ has - '//*[@id="associatedconstant.OPTIONAL"]' 'const OPTIONAL: Struct = _'
const OPTIONAL: Struct = Struct { _private: () };
}
impl Trait for Struct {
//@ !has assoc_consts_underscore/struct.Struct.html '//*[@id="associatedconstant.REQUIRED"]' \
// 'const REQUIRED: Struct = _'
//@ has - '//*[@id="associatedconstant.REQUIRED"]' 'const REQUIRED: Struct'
const REQUIRED: Struct = Struct { _private: () };
//@ !has - '//*[@id="associatedconstant.OPTIONAL"]' 'const OPTIONAL: Struct = _'
//@ has - '//*[@id="associatedconstant.OPTIONAL"]' 'const OPTIONAL: Struct'
const OPTIONAL: Struct = Struct { _private: () };
}
impl Struct {
//@ !has - '//*[@id="associatedconstant.INHERENT"]' 'const INHERENT: Struct = _'
//@ has - '//*[@id="associatedconstant.INHERENT"]' 'const INHERENT: Struct'
pub const INHERENT: Struct = Struct { _private: () };
}

View file

@ -14,6 +14,6 @@ impl<const B: Word> Repr<B> {
// If we change back to rendering the value of consts, check this doesn't add // If we change back to rendering the value of consts, check this doesn't add
// a <b> tag, but escapes correctly // a <b> tag, but escapes correctly
//@ has foo/struct.Repr.html '//section[@id="associatedconstant.BASE"]/h4' '= _' //@ !has foo/struct.Repr.html '//section[@id="associatedconstant.BASE"]/h4' '='
pub const BASE: IBig = base_as_ibig::<B>(); pub const BASE: IBig = base_as_ibig::<B>();
} }