diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6160783f652f1..2c63f381851f4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1991,6 +1991,7 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::Trait(_, _, generics, bounds, item_ids) => { let items = item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect(); + TraitItem(Trait { def_id, items, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 81cc12c9d5596..dcd2eaac7ea60 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1,9 +1,5 @@ use clean::AttributesExt; -use std::cmp::Ordering; -use std::fmt; -use std::rc::Rc; - use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -15,6 +11,9 @@ use rustc_middle::ty::{Adt, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants}; +use std::cmp::Ordering; +use std::fmt; +use std::rc::Rc; use super::{ collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section, @@ -37,6 +36,7 @@ use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; use crate::html::url_parts_builder::UrlPartsBuilder; use askama::Template; +use itertools::Itertools; const ITEM_TABLE_OPEN: &str = "
"; const ITEM_TABLE_CLOSE: &str = "
"; @@ -539,6 +539,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let count_types = required_types.len() + provided_types.len(); let count_consts = required_consts.len() + provided_consts.len(); let count_methods = required_methods.len() + provided_methods.len(); + let must_implement_one_of_functions = + cx.tcx().trait_def(t.def_id).must_implement_one_of.clone(); // Output the trait definition wrap_into_docblock(w, |w| { @@ -784,13 +786,22 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } // Output the documentation for each function individually - if !required_methods.is_empty() { + if !required_methods.is_empty() || must_implement_one_of_functions.is_some() { write_small_section_header( w, "required-methods", "Required Methods", "
", ); + + if let Some(list) = must_implement_one_of_functions.as_deref() { + write!( + w, + "
At least one of the `{}` methods is required.
", + list.iter().join("`, `") + ); + } + for m in required_methods { trait_item(w, cx, m, it); } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 7ff8063904ace..c42cac59bd6fa 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -205,11 +205,13 @@ details.rustdoc-toggle > summary::before { /* Created this empty rule to satisfy the theme checks. */ .stab.empty-impl {} +.stab.must_implement {} .stab.unstable, .stab.deprecated, .stab.portability, -.stab.empty-impl { +.stab.empty-impl, +.stab.must_implement { color: #c5c5c5; background: #314559 !important; border-style: none !important; diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 8e753f5768206..62d9eaa02e6a7 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -180,6 +180,7 @@ details.rustdoc-toggle > summary::before { .stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; } +.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } .stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } .stab.portability > code { background: none; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 40d965c39c390..b751acff152cb 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -163,6 +163,7 @@ details.rustdoc-toggle > summary::before { .stab.empty-impl { background: #FFF5D6; border-color: #FFC600; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; } +.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; } .stab.portability { background: #F3DFFF; border-color: #b07bdb; } .stab.portability > code { background: none; } diff --git a/src/test/rustdoc/must_implement_one_of.rs b/src/test/rustdoc/must_implement_one_of.rs new file mode 100644 index 0000000000000..1f1dd5d5796ee --- /dev/null +++ b/src/test/rustdoc/must_implement_one_of.rs @@ -0,0 +1,10 @@ +#![crate_name = "c"] +#![feature(rustc_attrs)] + +#[rustc_must_implement_one_of(a, b)] +// @matches c/trait.Trait.html '//*[@class="stab must_implement"]' \ +// 'At least one of the `a`, `b` methods is required.$' +pub trait Trait { + fn a() {} + fn b() {} +}