diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3cc0745b195e6..87f52d2cfa20e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -495,6 +495,11 @@ impl Item { self.stability.as_ref().map(|s| &s.since[..]) } + pub fn is_non_exhaustive(&self) -> bool { + self.attrs.other_attrs.iter() + .any(|a| a.name().as_str() == "non_exhaustive") + } + /// Returns a documentation-level item type from the item. pub fn type_(&self) -> ItemType { ItemType::from(self) diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 54c57c9ac6eeb..899714a8873e3 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -90,7 +90,16 @@ pub trait DocFolder : Sized { /// don't override! fn fold_item_recur(&mut self, item: Item) -> Option { - let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item; + let Item { + attrs, + name, + source, + visibility, + def_id, + inner, + stability, + deprecation, + } = item; let inner = match inner { StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)), diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 130451d07af86..9ae92d06dbd76 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2262,6 +2262,37 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) Ok(()) } +fn document_non_exhaustive_header(item: &clean::Item) -> &str { + if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" } +} + +fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { + if item.is_non_exhaustive() { + write!(w, "
", { + if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" } + })?; + + if item.is_struct() { + write!(w, "Non-exhaustive structs could have additional fields added in future. \ + Therefore, non-exhaustive structs cannot be constructed in external crates \ + using the traditional Struct {{ .. }} syntax; cannot be \ + matched against without a wildcard ..; and \ + struct update syntax will not work.")?; + } else if item.is_enum() { + write!(w, "Non-exhaustive enums could have additional variants added in future. \ + Therefore, when matching against variants of non-exhaustive enums, an \ + extra wildcard arm must be added to account for any future variants.")?; + } else { + write!(w, "This type will require a wildcard arm in any match statements or \ + constructors.")?; + } + + write!(w, "
")?; + } + + Ok(()) +} + fn name_key(name: &str) -> (&str, u64, usize) { // find number at end let split = name.bytes().rposition(|b| b < b'0' || b'9' < b).map_or(0, |s| s + 1); @@ -3122,7 +3153,9 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, if let doctree::Plain = s.struct_type { if fields.peek().is_some() { write!(w, "

- Fields

")?; + Fields{}", + document_non_exhaustive_header(it))?; + document_non_exhaustive(w, it)?; for (field, ty) in fields { let id = derive_id(format!("{}.{}", ItemType::StructField, @@ -3254,7 +3287,9 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, document(w, cx, it)?; if !e.variants.is_empty() { write!(w, "

- Variants

\n")?; + Variants{}\n", + document_non_exhaustive_header(it))?; + document_non_exhaustive(w, it)?; for variant in &e.variants { let id = derive_id(format!("{}.{}", ItemType::Variant, @@ -3355,7 +3390,8 @@ const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[ "must_use", "no_mangle", "repr", - "unsafe_destructor_blind_to_params" + "unsafe_destructor_blind_to_params", + "non_exhaustive" ]; fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index bb996e00d352a..af994229edf30 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1993,7 +1993,7 @@ onEach(e.getElementsByClassName('associatedconstant'), func); }); - function createToggle(otherMessage, extraClass) { + function createToggle(otherMessage, fontSize, extraClass) { var span = document.createElement('span'); span.className = 'toggle-label'; span.style.display = 'none'; @@ -2001,7 +2001,10 @@ span.innerHTML = ' Expand description'; } else { span.innerHTML = otherMessage; - span.style.fontSize = '20px'; + } + + if (fontSize) { + span.style.fontSize = fontSize; } var mainToggle = toggle.cloneNode(true); @@ -2040,13 +2043,27 @@ } if (e.parentNode.id === "main") { var otherMessage; + var fontSize; var extraClass; + if (hasClass(e, "type-decl")) { + fontSize = "20px"; otherMessage = ' Show declaration'; + } else if (hasClass(e, "non-exhaustive")) { + otherMessage = ' This '; + if (hasClass(e, "non-exhaustive-struct")) { + otherMessage += 'struct'; + } else if (hasClass(e, "non-exhaustive-enum")) { + otherMessage += 'enum'; + } else if (hasClass(e, "non-exhaustive-type")) { + otherMessage += 'type'; + } + otherMessage += ' is marked as non-exhaustive'; } else if (hasClass(e.childNodes[0], "impl-items")) { extraClass = "marg-left"; } - e.parentNode.insertBefore(createToggle(otherMessage, extraClass), e); + + e.parentNode.insertBefore(createToggle(otherMessage, fontSize, extraClass), e); if (otherMessage && getCurrentValue('rustdoc-item-declarations') !== "false") { collapseDocs(e.previousSibling.childNodes[0], "toggle"); } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 575a7ea27921f..b689e2fa3854e 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1358,4 +1358,8 @@ kbd { } #all-types > p { margin: 5px 0; -} \ No newline at end of file +} + +.non-exhaustive { + margin-bottom: 1em; +} diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 7add0e21f548c..3aea30c767f61 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -406,4 +406,4 @@ kbd { } .search-results td span.grey { color: #ccc; -} \ No newline at end of file +} diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 7d9980363de9c..e84e3cb56636e 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -400,4 +400,4 @@ kbd { } .search-results td span.grey { color: #999; -} \ No newline at end of file +}