diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c09e17d3787e..18f991ad43aa 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1222,11 +1222,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body)); - MethodItem(m, None) + MethodItem(m, Defaultness::from_trait_item(trait_item.defaultness)) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => { let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents)); - RequiredMethodItem(m) + RequiredMethodItem(m, Defaultness::from_trait_item(trait_item.defaultness)) } hir::TraitItemKind::Type(bounds, Some(default)) => { let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); @@ -1271,7 +1271,7 @@ pub(crate) fn clean_impl_item<'tcx>( hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final, hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness, }; - MethodItem(m, Some(defaultness)) + MethodItem(m, Defaultness::from_impl_item(defaultness)) } hir::ImplItemKind::Type(hir_ty) => { let type_ = clean_ty(hir_ty, cx); @@ -1353,18 +1353,20 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } } - let provided = match assoc_item.container { - ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true, - ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(), + let defaultness = assoc_item.defaultness(tcx); + let (provided, defaultness) = match assoc_item.container { + ty::AssocContainer::Trait => { + (defaultness.has_value(), Defaultness::from_trait_item(defaultness)) + } + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => { + (true, Defaultness::from_impl_item(defaultness)) + } }; + if provided { - let defaultness = match assoc_item.container { - ty::AssocContainer::TraitImpl(_) => Some(assoc_item.defaultness(tcx)), - ty::AssocContainer::InherentImpl | ty::AssocContainer::Trait => None, - }; MethodItem(item, defaultness) } else { - RequiredMethodItem(item) + RequiredMethodItem(item, defaultness) } } ty::AssocKind::Type { .. } => { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c145929534d9..47a1199e7fe4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -61,6 +61,29 @@ pub(crate) enum ItemId { Blanket { impl_id: DefId, for_: DefId }, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub(crate) enum Defaultness { + Implicit, + Default, + Final, +} + +impl Defaultness { + pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self { + match defaultness { + hir::Defaultness::Default { .. } => Self::Implicit, + hir::Defaultness::Final => Self::Final, + } + } + + pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self { + match defaultness { + hir::Defaultness::Default { .. } => Self::Default, + hir::Defaultness::Final => Self::Implicit, + } + } +} + impl ItemId { #[inline] pub(crate) fn is_local(self) -> bool { @@ -703,12 +726,12 @@ impl Item { ItemType::from(self) } - pub(crate) fn is_default(&self) -> bool { + pub(crate) fn defaultness(&self) -> Option { match self.kind { - ItemKind::MethodItem(_, Some(defaultness)) => { - defaultness.has_value() && !defaultness.is_final() + ItemKind::MethodItem(_, defaultness) | ItemKind::RequiredMethodItem(_, defaultness) => { + Some(defaultness) } - _ => false, + _ => None, } } @@ -770,8 +793,8 @@ impl Item { } } ItemKind::FunctionItem(_) - | ItemKind::MethodItem(_, _) - | ItemKind::RequiredMethodItem(_) => { + | ItemKind::MethodItem(..) + | ItemKind::RequiredMethodItem(..) => { let def_id = self.def_id().unwrap(); build_fn_header(def_id, tcx, tcx.asyncness(def_id)) } @@ -855,11 +878,11 @@ pub(crate) enum ItemKind { TraitAliasItem(TraitAlias), ImplItem(Box), /// A required method in a trait declaration meaning it's only a function signature. - RequiredMethodItem(Box), + RequiredMethodItem(Box, Defaultness), /// A method in a trait impl or a provided method in a trait declaration. /// /// Compared to [RequiredMethodItem], it also contains a method body. - MethodItem(Box, Option), + MethodItem(Box, Defaultness), StructFieldItem(Type), VariantItem(Variant), /// `fn`s from an extern block @@ -917,8 +940,8 @@ impl ItemKind { | StaticItem(_) | ConstantItem(_) | TraitAliasItem(_) - | RequiredMethodItem(_) - | MethodItem(_, _) + | RequiredMethodItem(..) + | MethodItem(..) | StructFieldItem(_) | ForeignFunctionItem(_, _) | ForeignStaticItem(_, _) diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index ee5f260615db..c970fdbbc93a 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -82,8 +82,8 @@ pub(crate) trait DocFolder: Sized { | StaticItem(_) | ConstantItem(..) | TraitAliasItem(_) - | RequiredMethodItem(_) - | MethodItem(_, _) + | RequiredMethodItem(..) + | MethodItem(..) | StructFieldItem(_) | ForeignFunctionItem(..) | ForeignStaticItem(..) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f38a21bd1ff3..7646375cbf7a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1566,10 +1566,6 @@ pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display { }) } -pub(crate) fn print_default_space(v: bool) -> &'static str { - if v { "default " } else { "" } -} - fn print_generic_arg(generic_arg: &clean::GenericArg, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| match generic_arg { clean::GenericArg::Lifetime(lt) => f.write_str(print_lifetime(lt)), diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 86e8167dc3cd..c03a3e8980e1 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -66,7 +66,7 @@ use tracing::{debug, info}; pub(crate) use self::context::*; pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources}; pub(crate) use self::write_shared::*; -use crate::clean::{self, ItemId, RenderedLink}; +use crate::clean::{self, Defaultness, ItemId, RenderedLink}; use crate::display::{Joined as _, MaybeDisplay as _}; use crate::error::Error; use crate::formats::Impl; @@ -75,8 +75,8 @@ use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::format::{ Ending, HrefError, HrefInfo, PrintWithSpace, full_print_fn_decl, href, print_abi_with_space, - print_constness_with_space, print_default_space, print_generic_bounds, print_generics, - print_impl, print_path, print_type, print_where_clause, visibility_print_with_space, + print_constness_with_space, print_generic_bounds, print_generics, print_impl, print_path, + print_type, print_where_clause, visibility_print_with_space, }; use crate::html::markdown::{ HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, @@ -1109,7 +1109,11 @@ fn assoc_method( let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item"); let name = meth.name.as_ref().unwrap(); let vis = visibility_print_with_space(meth, cx).to_string(); - let defaultness = print_default_space(meth.is_default()); + let defaultness = match meth.defaultness().expect("Expected assoc method to have defaultness") { + Defaultness::Implicit => "", + Defaultness::Final => "final ", + Defaultness::Default => "default ", + }; // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove // this condition. let constness = match render_mode { @@ -1260,7 +1264,7 @@ fn render_assoc_item( ) -> impl fmt::Display { fmt::from_fn(move |f| match &item.kind { clean::StrippedItem(..) => Ok(()), - clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => { + clean::RequiredMethodItem(m, _) | clean::MethodItem(m, _) => { assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f) } clean::RequiredAssocConstItem(generics, ty) => assoc_const( @@ -1585,7 +1589,7 @@ fn render_deref_methods( fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool { let self_type_opt = match item.kind { clean::MethodItem(ref method, _) => method.decl.receiver_type(), - clean::RequiredMethodItem(ref method) => method.decl.receiver_type(), + clean::RequiredMethodItem(ref method, _) => method.decl.receiver_type(), _ => None, }; @@ -1855,7 +1859,7 @@ fn render_impl( deprecation_class = ""; } match &item.kind { - clean::MethodItem(..) | clean::RequiredMethodItem(_) => { + clean::MethodItem(..) | clean::RequiredMethodItem(..) => { // Only render when the method is not static or we allow static methods if render_method_item { let id = cx.derive_id(format!("{item_type}.{name}")); @@ -2033,7 +2037,9 @@ fn render_impl( if !impl_.is_negative_trait_impl() { for impl_item in &impl_.items { match impl_item.kind { - clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(impl_item), + clean::MethodItem(..) | clean::RequiredMethodItem(..) => { + methods.push(impl_item) + } clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => { assoc_types.push(impl_item) } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 30b534003da1..766109b65bea 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1968,7 +1968,7 @@ pub(crate) fn get_function_type_for_search( clean::ForeignFunctionItem(ref f, _) | clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) - | clean::RequiredMethodItem(ref f) => { + | clean::RequiredMethodItem(ref f, _) => { get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache) } clean::ConstantItem(ref c) => make_nullary_fn(&c.type_), diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 2edf7891be40..599d7b10005d 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -296,7 +296,7 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum MethodItem(m, _) => { ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer)) } - RequiredMethodItem(m) => { + RequiredMethodItem(m, _) => { ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer)) } ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)), diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index 4d31409afe82..9f6bf009a054 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -35,8 +35,8 @@ pub(crate) trait DocVisitor<'a>: Sized { | StaticItem(_) | ConstantItem(..) | TraitAliasItem(_) - | RequiredMethodItem(_) - | MethodItem(_, _) + | RequiredMethodItem(..) + | MethodItem(..) | StructFieldItem(_) | ForeignFunctionItem(..) | ForeignStaticItem(..) diff --git a/tests/rustdoc-html/final-trait-method.rs b/tests/rustdoc-html/final-trait-method.rs new file mode 100644 index 000000000000..016578a8b0e7 --- /dev/null +++ b/tests/rustdoc-html/final-trait-method.rs @@ -0,0 +1,22 @@ +#![feature(final_associated_functions)] + +//@ has final_trait_method/trait.Item.html +pub trait Item { + //@ has - '//*[@id="method.foo"]' 'final fn foo()' + //@ !has - '//*[@id="method.foo"]' 'default fn foo()' + final fn foo() {} + + //@ has - '//*[@id="method.bar"]' 'fn bar()' + //@ !has - '//*[@id="method.bar"]' 'default fn bar()' + //@ !has - '//*[@id="method.bar"]' 'final fn bar()' + fn bar() {} +} + +//@ has final_trait_method/struct.Foo.html +pub struct Foo; +impl Item for Foo { + //@ has - '//*[@id="method.bar"]' 'fn bar()' + //@ !has - '//*[@id="method.bar"]' 'final fn bar()' + //@ !has - '//*[@id="method.bar"]' 'default fn bar()' + fn bar() {} +}