From a074bd7334978a7d32395c66404b8f5294b1811e Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 27 Jun 2018 20:50:59 +0100 Subject: [PATCH 1/8] Display #[non_exhaustive] in rustdoc on types. --- src/librustdoc/clean/auto_trait.rs | 1 + src/librustdoc/clean/inline.rs | 2 ++ src/librustdoc/clean/mod.rs | 25 +++++++++++++++++++++ src/librustdoc/doctree.rs | 2 ++ src/librustdoc/fold.rs | 14 ++++++++++-- src/librustdoc/html/render.rs | 23 +++++++++++++++++++ src/librustdoc/html/static/themes/light.css | 3 ++- src/librustdoc/visit_ast.rs | 8 +++++++ 8 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 272819ba2dd96..f9d0023011236 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -229,6 +229,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { def_id: self.next_def_id(def_id.krate), stability: None, deprecation: None, + non_exhaustive: false, inner: ImplItem(Impl { unsafety: hir::Unsafety::Normal, generics: new_generics, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index ad7389db729ec..3029eba06378c 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -111,6 +111,7 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa visibility: Some(clean::Public), stability: cx.tcx.lookup_stability(did).clean(cx), deprecation: cx.tcx.lookup_deprecation(did).clean(cx), + non_exhaustive: false, def_id: did, }); Some(ret) @@ -412,6 +413,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { visibility: Some(clean::Inherited), stability: tcx.lookup_stability(did).clean(cx), deprecation: tcx.lookup_deprecation(did).clean(cx), + non_exhaustive: false, def_id: did, }); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3cc0745b195e6..441a49c328a6b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -192,6 +192,7 @@ impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> visibility: Some(Public), stability: get_stability(cx, def_id), deprecation: get_deprecation(cx, def_id), + non_exhaustive: false, def_id, inner: PrimitiveItem(prim), } @@ -204,6 +205,7 @@ impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> visibility: Some(Public), stability: get_stability(cx, def_id), deprecation: get_deprecation(cx, def_id), + non_exhaustive: false, def_id, inner: KeywordItem(kw), } @@ -366,6 +368,7 @@ pub struct Item { pub def_id: DefId, pub stability: Option, pub deprecation: Option, + pub non_exhaustive: bool, } impl fmt::Debug for Item { @@ -625,6 +628,7 @@ impl Clean for doctree::Module { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, def_id: cx.tcx.hir.local_def_id(self.id), inner: ModuleItem(Module { is_crate: self.is_crate, @@ -2117,6 +2121,7 @@ impl Clean for doctree::Function { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, def_id: cx.tcx.hir.local_def_id(self.id), inner: FunctionItem(Function { decl, @@ -2298,6 +2303,7 @@ impl Clean for doctree::Trait { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, inner: TraitItem(Trait { auto: self.is_auto.clean(cx), unsafety: self.unsafety, @@ -2367,6 +2373,7 @@ impl Clean for hir::TraitItem { visibility: None, stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)), deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)), + non_exhaustive: false, inner, } } @@ -2395,6 +2402,7 @@ impl Clean for hir::ImplItem { visibility: self.vis.clean(cx), stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)), deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)), + non_exhaustive: false, inner, } } @@ -2541,6 +2549,7 @@ impl<'tcx> Clean for ty::AssociatedItem { visibility, stability: get_stability(cx, self.def_id), deprecation: get_deprecation(cx, self.def_id), + non_exhaustive: false, def_id: self.def_id, attrs: inline::load_attrs(cx, self.def_id), source: cx.tcx.def_span(self.def_id).clean(cx), @@ -3194,6 +3203,7 @@ impl Clean for hir::StructField { visibility: self.vis.clean(cx), stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)), deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)), + non_exhaustive: false, def_id: cx.tcx.hir.local_def_id(self.id), inner: StructFieldItem(self.ty.clean(cx)), } @@ -3209,6 +3219,7 @@ impl<'tcx> Clean for ty::FieldDef { visibility: self.vis.clean(cx), stability: get_stability(cx, self.did), deprecation: get_deprecation(cx, self.did), + non_exhaustive: false, def_id: self.did, inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)), } @@ -3273,6 +3284,7 @@ impl Clean> for doctree::Struct { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: self.non_exhaustive, inner: StructItem(Struct { struct_type: self.struct_type, generics: self.generics.clean(cx), @@ -3298,6 +3310,7 @@ impl Clean> for doctree::Union { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, inner: UnionItem(Union { struct_type: self.struct_type, generics: self.generics.clean(cx), @@ -3350,6 +3363,7 @@ impl Clean> for doctree::Enum { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: self.non_exhaustive, inner: EnumItem(Enum { variants: self.variants.clean(cx), generics: self.generics.clean(cx), @@ -3375,6 +3389,7 @@ impl Clean for doctree::Variant { visibility: None, stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, def_id: cx.tcx.hir.local_def_id(self.def.id()), inner: VariantItem(Variant { kind: self.def.clean(cx), @@ -3405,6 +3420,7 @@ impl<'tcx> Clean for ty::VariantDef { def_id: field.did, stability: get_stability(cx, field.did), deprecation: get_deprecation(cx, field.did), + non_exhaustive: false, inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx)) } }).collect() @@ -3420,6 +3436,7 @@ impl<'tcx> Clean for ty::VariantDef { inner: VariantItem(Variant { kind: kind }), stability: get_stability(cx, self.did), deprecation: get_deprecation(cx, self.did), + non_exhaustive: false, } } } @@ -3671,6 +3688,7 @@ impl Clean for doctree::Typedef { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, inner: TypedefItem(Typedef { type_: self.ty.clean(cx), generics: self.gen.clean(cx), @@ -3722,6 +3740,7 @@ impl Clean for doctree::Static { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, inner: StaticItem(Static { type_: self.type_.clean(cx), mutability: self.mutability.clean(cx), @@ -3747,6 +3766,7 @@ impl Clean for doctree::Constant { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, inner: ConstantItem(Constant { type_: self.type_.clean(cx), expr: print_const_expr(cx, self.expr), @@ -3835,6 +3855,7 @@ impl Clean> for doctree::Impl { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, inner: ImplItem(Impl { unsafety: self.unsafety, generics: self.generics.clean(cx), @@ -3921,6 +3942,7 @@ impl Clean for doctree::ExternCrate { visibility: self.vis.clean(cx), stability: None, deprecation: None, + non_exhaustive: false, inner: ExternCrateItem(self.name.clean(cx), self.path.clone()) } } @@ -3967,6 +3989,7 @@ impl Clean> for doctree::Import { visibility: self.vis.clean(cx), stability: None, deprecation: None, + non_exhaustive: false, inner: ImportItem(inner) }] } @@ -4035,6 +4058,7 @@ impl Clean for hir::ForeignItem { visibility: self.vis.clean(cx), stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)), deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)), + non_exhaustive: false, inner, } } @@ -4209,6 +4233,7 @@ impl Clean for doctree::Macro { visibility: Some(Public), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), + non_exhaustive: false, def_id: self.def_id, inner: MacroItem(Macro { source: format!("macro_rules! {} {{\n{}}}", diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 0807db2997626..f0eb1ffd5ab69 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -97,6 +97,7 @@ pub struct Struct { pub vis: hir::Visibility, pub stab: Option, pub depr: Option, + pub non_exhaustive: bool, pub id: NodeId, pub struct_type: StructType, pub name: Name, @@ -123,6 +124,7 @@ pub struct Enum { pub vis: hir::Visibility, pub stab: Option, pub depr: Option, + pub non_exhaustive: bool, pub variants: hir::HirVec, pub generics: hir::Generics, pub attrs: hir::HirVec, diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 54c57c9ac6eeb..8d191357cbe1f 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -90,7 +90,17 @@ 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, + non_exhaustive + } = item; let inner = match inner { StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)), @@ -98,7 +108,7 @@ pub trait DocFolder : Sized { }; Some(Item { attrs, name, source, inner, visibility, - stability, deprecation, def_id }) + stability, deprecation, non_exhaustive, def_id }) } fn fold_mod(&mut self, m: Module) -> Module { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 130451d07af86..d37f4e9393502 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2194,6 +2194,7 @@ fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Re info!("Documenting {}", name); } document_stability(w, cx, item)?; + document_non_exhaustive(w, item)?; let prefix = render_assoc_const_value(item); document_full(w, item, cx, &prefix)?; Ok(()) @@ -2262,6 +2263,28 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) Ok(()) } +fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { + if item.non_exhaustive { + write!(w, r##" +
+
+
+ + 🔬 + This type is marked as non exhaustive. + +

+ This type will require a wildcard arm in any match statements or constructors. +

+
+
+
+ "##)?; + } + + 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); diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 7d9980363de9c..3c3372aedd48c 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -188,6 +188,7 @@ a.test-arrow { border-color: #66afe9; } +.stab.non-exhaustive { background: #F5F5F5; border-color: #D3D3D3; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } .stab.portability { background: #C4ECFF; border-color: #7BA5DB; } @@ -400,4 +401,4 @@ kbd { } .search-results td span.grey { color: #999; -} \ No newline at end of file +} diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6bf1931e468de..2dbcb945b49fb 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -89,6 +89,12 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { .and_then(|def_id| self.cx.tcx.lookup_deprecation(def_id)) } + fn non_exhaustive(&self, id: ast::NodeId) -> bool { + self.cx.tcx.hir.opt_local_def_id(id) + .map(|def_id| self.cx.tcx.has_attr(def_id, "non_exhaustive")) + .unwrap_or(false) + } + pub fn visit(&mut self, krate: &hir::Crate) { self.attrs = krate.attrs.clone(); @@ -119,6 +125,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { vis: item.vis.clone(), stab: self.stability(item.id), depr: self.deprecation(item.id), + non_exhaustive: self.non_exhaustive(item.id), attrs: item.attrs.clone(), generics: generics.clone(), fields: sd.fields().iter().cloned().collect(), @@ -162,6 +169,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { vis: it.vis.clone(), stab: self.stability(it.id), depr: self.deprecation(it.id), + non_exhaustive: self.non_exhaustive(it.id), generics: params.clone(), attrs: it.attrs.clone(), id: it.id, From 039709d34f40b6602853f1627a1bc22048e1b5d3 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 27 Jun 2018 23:07:42 +0100 Subject: [PATCH 2/8] Include type in non-exhaustive message. Include new css in dark theme. --- src/librustdoc/html/render.rs | 7 ++++--- src/librustdoc/html/static/themes/dark.css | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d37f4e9393502..432aaac15aa18 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2265,21 +2265,22 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if item.non_exhaustive { + let name = item.type_(); write!(w, r##"
🔬 - This type is marked as non exhaustive. + This {} is marked as non exhaustive.

- This type will require a wildcard arm in any match statements or constructors. + This {} will require a wildcard arm in any match statements or constructors.

- "##)?; + "##, name, name)?; } Ok(()) diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 7add0e21f548c..bb33cd0302554 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -188,6 +188,7 @@ a.test-arrow { border-color: #008dfd; } +.stab.non-exhaustive { background: #2a2a2a; border-color: #707070; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #404040; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; color: #404040; } .stab.portability { background: #C4ECFF; border-color: #7BA5DB; color: #404040; } @@ -406,4 +407,4 @@ kbd { } .search-results td span.grey { color: #ccc; -} \ No newline at end of file +} From 3e59aef385ef6a418f77560458012adc179ee64a Mon Sep 17 00:00:00 2001 From: David Wood Date: Sat, 30 Jun 2018 20:03:51 +0100 Subject: [PATCH 3/8] Improved non_exhaustive message. --- src/librustdoc/html/render.rs | 45 ++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 432aaac15aa18..a79dad0f8204a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2265,22 +2265,35 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if item.non_exhaustive { - let name = item.type_(); - write!(w, r##" -
-
-
- - 🔬 - This {} is marked as non exhaustive. - -

- This {} will require a wildcard arm in any match statements or constructors. -

-
-
-
- "##, name, name)?; + write!(w, "
")?; + write!(w, "
🔬")?; + + if item.is_struct() { + write!(w, "This struct is marked as non exhaustive.")?; + } else if item.is_enum() { + write!(w, "This enum is marked as non exhaustive.")?; + } else { + write!(w, "This type is marked as non exhaustive.")?; + } + + write!(w, "

")?; + + if item.is_struct() { + write!(w, "This struct is marked as non-exhaustive as additional fields may be \ + added in the future. This means that this struct cannot be constructed in \ + external crates using the traditional Struct {{ .. }} syntax; + cannot be matched against without a wildcard ..; and \ + functional-record-updates do not work on this struct.")?; + } else if item.is_enum() { + write!(w, "This enum is marked as non-exhaustive, and additional variants may be \ + added in the future. When matching over values of this type, an extra \ + _ arm must be added to account for future extensions.")?; + } else { + write!(w, "This type will require a wildcard arm in any match statements or \ + constructors.")?; + } + + write!(w, "

")?; } Ok(()) From 5ccafa106fe1972158ce5c4dcd36e92df7c2be74 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 5 Jul 2018 22:44:58 +0100 Subject: [PATCH 4/8] Simplified checking for non_exhaustive attribute. --- src/librustdoc/clean/auto_trait.rs | 1 - src/librustdoc/clean/inline.rs | 2 -- src/librustdoc/clean/mod.rs | 31 ++++++------------------------ src/librustdoc/doctree.rs | 2 -- src/librustdoc/fold.rs | 3 +-- src/librustdoc/html/render.rs | 2 +- src/librustdoc/visit_ast.rs | 8 -------- 7 files changed, 8 insertions(+), 41 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index f9d0023011236..272819ba2dd96 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -229,7 +229,6 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { def_id: self.next_def_id(def_id.krate), stability: None, deprecation: None, - non_exhaustive: false, inner: ImplItem(Impl { unsafety: hir::Unsafety::Normal, generics: new_generics, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 3029eba06378c..ad7389db729ec 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -111,7 +111,6 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name, visited: &mut FxHa visibility: Some(clean::Public), stability: cx.tcx.lookup_stability(did).clean(cx), deprecation: cx.tcx.lookup_deprecation(did).clean(cx), - non_exhaustive: false, def_id: did, }); Some(ret) @@ -413,7 +412,6 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { visibility: Some(clean::Inherited), stability: tcx.lookup_stability(did).clean(cx), deprecation: tcx.lookup_deprecation(did).clean(cx), - non_exhaustive: false, def_id: did, }); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 441a49c328a6b..a47213a62a54b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -192,7 +192,6 @@ impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> visibility: Some(Public), stability: get_stability(cx, def_id), deprecation: get_deprecation(cx, def_id), - non_exhaustive: false, def_id, inner: PrimitiveItem(prim), } @@ -205,7 +204,6 @@ impl<'a, 'tcx, 'rcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx, 'rcx> visibility: Some(Public), stability: get_stability(cx, def_id), deprecation: get_deprecation(cx, def_id), - non_exhaustive: false, def_id, inner: KeywordItem(kw), } @@ -368,7 +366,6 @@ pub struct Item { pub def_id: DefId, pub stability: Option, pub deprecation: Option, - pub non_exhaustive: bool, } impl fmt::Debug for Item { @@ -498,6 +495,12 @@ impl Item { self.stability.as_ref().map(|s| &s.since[..]) } + pub fn is_non_exhaustive(&self) -> bool { + self.attrs.other_attrs.iter() + .filter(|a| a.name().as_str() == "non_exhaustive") + .count() > 0 + } + /// Returns a documentation-level item type from the item. pub fn type_(&self) -> ItemType { ItemType::from(self) @@ -628,7 +631,6 @@ impl Clean for doctree::Module { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, def_id: cx.tcx.hir.local_def_id(self.id), inner: ModuleItem(Module { is_crate: self.is_crate, @@ -2121,7 +2123,6 @@ impl Clean for doctree::Function { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, def_id: cx.tcx.hir.local_def_id(self.id), inner: FunctionItem(Function { decl, @@ -2303,7 +2304,6 @@ impl Clean for doctree::Trait { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, inner: TraitItem(Trait { auto: self.is_auto.clean(cx), unsafety: self.unsafety, @@ -2373,7 +2373,6 @@ impl Clean for hir::TraitItem { visibility: None, stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)), deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)), - non_exhaustive: false, inner, } } @@ -2402,7 +2401,6 @@ impl Clean for hir::ImplItem { visibility: self.vis.clean(cx), stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)), deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)), - non_exhaustive: false, inner, } } @@ -2549,7 +2547,6 @@ impl<'tcx> Clean for ty::AssociatedItem { visibility, stability: get_stability(cx, self.def_id), deprecation: get_deprecation(cx, self.def_id), - non_exhaustive: false, def_id: self.def_id, attrs: inline::load_attrs(cx, self.def_id), source: cx.tcx.def_span(self.def_id).clean(cx), @@ -3203,7 +3200,6 @@ impl Clean for hir::StructField { visibility: self.vis.clean(cx), stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)), deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)), - non_exhaustive: false, def_id: cx.tcx.hir.local_def_id(self.id), inner: StructFieldItem(self.ty.clean(cx)), } @@ -3219,7 +3215,6 @@ impl<'tcx> Clean for ty::FieldDef { visibility: self.vis.clean(cx), stability: get_stability(cx, self.did), deprecation: get_deprecation(cx, self.did), - non_exhaustive: false, def_id: self.did, inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)), } @@ -3284,7 +3279,6 @@ impl Clean> for doctree::Struct { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: self.non_exhaustive, inner: StructItem(Struct { struct_type: self.struct_type, generics: self.generics.clean(cx), @@ -3310,7 +3304,6 @@ impl Clean> for doctree::Union { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, inner: UnionItem(Union { struct_type: self.struct_type, generics: self.generics.clean(cx), @@ -3363,7 +3356,6 @@ impl Clean> for doctree::Enum { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: self.non_exhaustive, inner: EnumItem(Enum { variants: self.variants.clean(cx), generics: self.generics.clean(cx), @@ -3389,7 +3381,6 @@ impl Clean for doctree::Variant { visibility: None, stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, def_id: cx.tcx.hir.local_def_id(self.def.id()), inner: VariantItem(Variant { kind: self.def.clean(cx), @@ -3420,7 +3411,6 @@ impl<'tcx> Clean for ty::VariantDef { def_id: field.did, stability: get_stability(cx, field.did), deprecation: get_deprecation(cx, field.did), - non_exhaustive: false, inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx)) } }).collect() @@ -3436,7 +3426,6 @@ impl<'tcx> Clean for ty::VariantDef { inner: VariantItem(Variant { kind: kind }), stability: get_stability(cx, self.did), deprecation: get_deprecation(cx, self.did), - non_exhaustive: false, } } } @@ -3688,7 +3677,6 @@ impl Clean for doctree::Typedef { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, inner: TypedefItem(Typedef { type_: self.ty.clean(cx), generics: self.gen.clean(cx), @@ -3740,7 +3728,6 @@ impl Clean for doctree::Static { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, inner: StaticItem(Static { type_: self.type_.clean(cx), mutability: self.mutability.clean(cx), @@ -3766,7 +3753,6 @@ impl Clean for doctree::Constant { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, inner: ConstantItem(Constant { type_: self.type_.clean(cx), expr: print_const_expr(cx, self.expr), @@ -3855,7 +3841,6 @@ impl Clean> for doctree::Impl { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, inner: ImplItem(Impl { unsafety: self.unsafety, generics: self.generics.clean(cx), @@ -3942,7 +3927,6 @@ impl Clean for doctree::ExternCrate { visibility: self.vis.clean(cx), stability: None, deprecation: None, - non_exhaustive: false, inner: ExternCrateItem(self.name.clean(cx), self.path.clone()) } } @@ -3989,7 +3973,6 @@ impl Clean> for doctree::Import { visibility: self.vis.clean(cx), stability: None, deprecation: None, - non_exhaustive: false, inner: ImportItem(inner) }] } @@ -4058,7 +4041,6 @@ impl Clean for hir::ForeignItem { visibility: self.vis.clean(cx), stability: get_stability(cx, cx.tcx.hir.local_def_id(self.id)), deprecation: get_deprecation(cx, cx.tcx.hir.local_def_id(self.id)), - non_exhaustive: false, inner, } } @@ -4233,7 +4215,6 @@ impl Clean for doctree::Macro { visibility: Some(Public), stability: self.stab.clean(cx), deprecation: self.depr.clean(cx), - non_exhaustive: false, def_id: self.def_id, inner: MacroItem(Macro { source: format!("macro_rules! {} {{\n{}}}", diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index f0eb1ffd5ab69..0807db2997626 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -97,7 +97,6 @@ pub struct Struct { pub vis: hir::Visibility, pub stab: Option, pub depr: Option, - pub non_exhaustive: bool, pub id: NodeId, pub struct_type: StructType, pub name: Name, @@ -124,7 +123,6 @@ pub struct Enum { pub vis: hir::Visibility, pub stab: Option, pub depr: Option, - pub non_exhaustive: bool, pub variants: hir::HirVec, pub generics: hir::Generics, pub attrs: hir::HirVec, diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 8d191357cbe1f..899714a8873e3 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -99,7 +99,6 @@ pub trait DocFolder : Sized { inner, stability, deprecation, - non_exhaustive } = item; let inner = match inner { @@ -108,7 +107,7 @@ pub trait DocFolder : Sized { }; Some(Item { attrs, name, source, inner, visibility, - stability, deprecation, non_exhaustive, def_id }) + stability, deprecation, def_id }) } fn fold_mod(&mut self, m: Module) -> Module { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a79dad0f8204a..a13055c25e93a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2264,7 +2264,7 @@ fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) } fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { - if item.non_exhaustive { + if item.is_non_exhaustive() { write!(w, "
")?; write!(w, "
🔬")?; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 2dbcb945b49fb..6bf1931e468de 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -89,12 +89,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { .and_then(|def_id| self.cx.tcx.lookup_deprecation(def_id)) } - fn non_exhaustive(&self, id: ast::NodeId) -> bool { - self.cx.tcx.hir.opt_local_def_id(id) - .map(|def_id| self.cx.tcx.has_attr(def_id, "non_exhaustive")) - .unwrap_or(false) - } - pub fn visit(&mut self, krate: &hir::Crate) { self.attrs = krate.attrs.clone(); @@ -125,7 +119,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { vis: item.vis.clone(), stab: self.stability(item.id), depr: self.deprecation(item.id), - non_exhaustive: self.non_exhaustive(item.id), attrs: item.attrs.clone(), generics: generics.clone(), fields: sd.fields().iter().cloned().collect(), @@ -169,7 +162,6 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { vis: it.vis.clone(), stab: self.stability(it.id), depr: self.deprecation(it.id), - non_exhaustive: self.non_exhaustive(it.id), generics: params.clone(), attrs: it.attrs.clone(), id: it.id, From 9527d6ade742ac6d06cc110afc10d66a9ae1c101 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 12 Jul 2018 20:14:13 +0100 Subject: [PATCH 5/8] Moved non_exhaustive message to fields/variants section and onto type. --- src/librustdoc/html/render.rs | 31 ++++++++++----------- src/librustdoc/html/static/themes/dark.css | 3 +- src/librustdoc/html/static/themes/light.css | 3 +- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a13055c25e93a..c344302cabf59 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2194,7 +2194,6 @@ fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Re info!("Documenting {}", name); } document_stability(w, cx, item)?; - document_non_exhaustive(w, item)?; let prefix = render_assoc_const_value(item); document_full(w, item, cx, &prefix)?; Ok(()) @@ -2263,20 +2262,13 @@ 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, "
")?; - write!(w, "
🔬")?; - - if item.is_struct() { - write!(w, "This struct is marked as non exhaustive.")?; - } else if item.is_enum() { - write!(w, "This enum is marked as non exhaustive.")?; - } else { - write!(w, "This type is marked as non exhaustive.")?; - } - - write!(w, "

")?; + write!(w, "

")?; if item.is_struct() { write!(w, "This struct is marked as non-exhaustive as additional fields may be \ @@ -2293,7 +2285,7 @@ fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::R constructors.")?; } - write!(w, "

")?; + write!(w, "

")?; } Ok(()) @@ -3159,7 +3151,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, @@ -3291,7 +3285,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, @@ -3392,7 +3388,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/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index bb33cd0302554..f97ff45b22f7a 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -148,6 +148,8 @@ pre { .content .fnname{ color: #2BAB63; } .content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; } +.non-exhaustive { color: #DDD; margin-bottom: 1em; } + pre.rust .comment { color: #8d8d8b; } pre.rust .doccomment { color: #8ca375; } @@ -188,7 +190,6 @@ a.test-arrow { border-color: #008dfd; } -.stab.non-exhaustive { background: #2a2a2a; border-color: #707070; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #404040; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; color: #404040; } .stab.portability { background: #C4ECFF; border-color: #7BA5DB; color: #404040; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 3c3372aedd48c..da8b24f3b171f 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -148,6 +148,8 @@ pre { .content .fnname { color: #9a6e31; } .content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; } +.non-exhaustive { color: #222; margin-bottom: 1em; } + pre.rust .comment { color: #8E908C; } pre.rust .doccomment { color: #4D4D4C; } @@ -188,7 +190,6 @@ a.test-arrow { border-color: #66afe9; } -.stab.non-exhaustive { background: #F5F5F5; border-color: #D3D3D3; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } .stab.portability { background: #C4ECFF; border-color: #7BA5DB; } From d0d33a03351433b7c27ae03e17bf18ad627379fe Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 13 Jul 2018 08:36:01 +0100 Subject: [PATCH 6/8] Switch to any from count when checking for non_exhaustive attribute. --- src/librustdoc/clean/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a47213a62a54b..87f52d2cfa20e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -497,8 +497,7 @@ impl Item { pub fn is_non_exhaustive(&self) -> bool { self.attrs.other_attrs.iter() - .filter(|a| a.name().as_str() == "non_exhaustive") - .count() > 0 + .any(|a| a.name().as_str() == "non_exhaustive") } /// Returns a documentation-level item type from the item. From 959a13d53e27ca92b59798e6c6737f8249d59a2e Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 18 Jul 2018 20:27:25 +0100 Subject: [PATCH 7/8] Updated wording and placement of non-exhaustive notice so it is collapsed by default and easier to understand. --- src/librustdoc/html/render.rs | 22 +++++++++++--------- src/librustdoc/html/static/main.js | 23 ++++++++++++++++++--- src/librustdoc/html/static/rustdoc.css | 6 +++++- src/librustdoc/html/static/themes/dark.css | 2 -- src/librustdoc/html/static/themes/light.css | 2 -- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c344302cabf59..78cf745718705 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2268,24 +2268,26 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str { fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if item.is_non_exhaustive() { - write!(w, "

")?; + write!(w, "

", { + if item.is_struct() { "struct" } else if item.is_enum() { "enum" } else { "type" } + })?; if item.is_struct() { - write!(w, "This struct is marked as non-exhaustive as additional fields may be \ - added in the future. This means that this struct cannot be constructed in \ - external crates using the traditional Struct {{ .. }} syntax; - cannot be matched against without a wildcard ..; and \ - functional-record-updates do not work on this 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 \ + functional-record-updates do not work.")?; } else if item.is_enum() { - write!(w, "This enum is marked as non-exhaustive, and additional variants may be \ - added in the future. When matching over values of this type, an extra \ - _ arm must be added to account for future extensions.")?; + 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, "

")?; + write!(w, "
")?; } Ok(()) 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 f97ff45b22f7a..3aea30c767f61 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -148,8 +148,6 @@ pre { .content .fnname{ color: #2BAB63; } .content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; } -.non-exhaustive { color: #DDD; margin-bottom: 1em; } - pre.rust .comment { color: #8d8d8b; } pre.rust .doccomment { color: #8ca375; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index da8b24f3b171f..e84e3cb56636e 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -148,8 +148,6 @@ pre { .content .fnname { color: #9a6e31; } .content span.keyword, .content a.keyword, .block a.current.keyword { color: #de5249; } -.non-exhaustive { color: #222; margin-bottom: 1em; } - pre.rust .comment { color: #8E908C; } pre.rust .doccomment { color: #4D4D4C; } From b671bdc381c8d4b870e408ae83b281ec3ede855f Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 19 Jul 2018 17:03:17 +0100 Subject: [PATCH 8/8] Updated FRU terminology. --- src/librustdoc/html/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 78cf745718705..9ae92d06dbd76 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2277,7 +2277,7 @@ fn document_non_exhaustive(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::R Therefore, non-exhaustive structs cannot be constructed in external crates \ using the traditional Struct {{ .. }} syntax; cannot be \ matched against without a wildcard ..; and \ - functional-record-updates do not work.")?; + 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 \