Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC 2008 non-exhaustive enums/structs: Rustdoc #51854

Merged
merged 8 commits into from
Jul 19, 2018
1 change: 1 addition & 0 deletions src/librustdoc/clean/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -412,6 +413,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
visibility: Some(clean::Inherited),
stability: tcx.lookup_stability(did).clean(cx),
deprecation: tcx.lookup_deprecation(did).clean(cx),
non_exhaustive: false,
def_id: did,
});
}
Expand Down
25 changes: 25 additions & 0 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ impl<'a, 'tcx, 'rcx> Clean<Crate> 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),
}
Expand All @@ -204,6 +205,7 @@ impl<'a, 'tcx, 'rcx> Clean<Crate> 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),
}
Expand Down Expand Up @@ -366,6 +368,7 @@ pub struct Item {
pub def_id: DefId,
pub stability: Option<Stability>,
pub deprecation: Option<Deprecation>,
pub non_exhaustive: bool,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think i'd prefer seeing the non_exhaustive marker just on the kinds where it's relevant, so just Struct/Enum/etc, instead of on Item here where literally everything has to care about it.

On the other hand, if i remember right we do keep all the ast::Attributes around in the Attributes struct, so we could just query them as needed, rather than passing this flag around all the way from clean_ast to html/render.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be resolved now.

}

impl fmt::Debug for Item {
Expand Down Expand Up @@ -625,6 +628,7 @@ impl Clean<Item> 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,
Expand Down Expand Up @@ -2117,6 +2121,7 @@ impl Clean<Item> 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,
Expand Down Expand Up @@ -2298,6 +2303,7 @@ impl Clean<Item> 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,
Expand Down Expand Up @@ -2367,6 +2373,7 @@ impl Clean<Item> 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,
}
}
Expand Down Expand Up @@ -2395,6 +2402,7 @@ impl Clean<Item> 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,
}
}
Expand Down Expand Up @@ -2541,6 +2549,7 @@ impl<'tcx> Clean<Item> 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),
Expand Down Expand Up @@ -3194,6 +3203,7 @@ impl Clean<Item> 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)),
}
Expand All @@ -3209,6 +3219,7 @@ impl<'tcx> Clean<Item> 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)),
}
Expand Down Expand Up @@ -3273,6 +3284,7 @@ impl Clean<Vec<Item>> 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),
Expand All @@ -3298,6 +3310,7 @@ impl Clean<Vec<Item>> 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),
Expand Down Expand Up @@ -3350,6 +3363,7 @@ impl Clean<Vec<Item>> 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),
Expand All @@ -3375,6 +3389,7 @@ impl Clean<Item> 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),
Expand Down Expand Up @@ -3405,6 +3420,7 @@ impl<'tcx> Clean<Item> 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()
Expand All @@ -3420,6 +3436,7 @@ impl<'tcx> Clean<Item> for ty::VariantDef {
inner: VariantItem(Variant { kind: kind }),
stability: get_stability(cx, self.did),
deprecation: get_deprecation(cx, self.did),
non_exhaustive: false,
}
}
}
Expand Down Expand Up @@ -3671,6 +3688,7 @@ impl Clean<Item> 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),
Expand Down Expand Up @@ -3722,6 +3740,7 @@ impl Clean<Item> 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),
Expand All @@ -3747,6 +3766,7 @@ impl Clean<Item> 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),
Expand Down Expand Up @@ -3835,6 +3855,7 @@ impl Clean<Vec<Item>> 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),
Expand Down Expand Up @@ -3921,6 +3942,7 @@ impl Clean<Item> for doctree::ExternCrate {
visibility: self.vis.clean(cx),
stability: None,
deprecation: None,
non_exhaustive: false,
inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
}
}
Expand Down Expand Up @@ -3967,6 +3989,7 @@ impl Clean<Vec<Item>> for doctree::Import {
visibility: self.vis.clean(cx),
stability: None,
deprecation: None,
non_exhaustive: false,
inner: ImportItem(inner)
}]
}
Expand Down Expand Up @@ -4035,6 +4058,7 @@ impl Clean<Item> 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,
}
}
Expand Down Expand Up @@ -4209,6 +4233,7 @@ impl Clean<Item> 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{}}}",
Expand Down
2 changes: 2 additions & 0 deletions src/librustdoc/doctree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pub struct Struct {
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub depr: Option<attr::Deprecation>,
pub non_exhaustive: bool,
pub id: NodeId,
pub struct_type: StructType,
pub name: Name,
Expand All @@ -123,6 +124,7 @@ pub struct Enum {
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub depr: Option<attr::Deprecation>,
pub non_exhaustive: bool,
pub variants: hir::HirVec<Variant>,
pub generics: hir::Generics,
pub attrs: hir::HirVec<ast::Attribute>,
Expand Down
14 changes: 12 additions & 2 deletions src/librustdoc/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,25 @@ pub trait DocFolder : Sized {

/// don't override!
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
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)),
_ => self.fold_inner_recur(inner),
};

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 {
Expand Down
37 changes: 37 additions & 0 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...though now i see why you did it this way. I commented in #51860 (comment) that this marker could go into the "Fields" or "Variants" sections of the struct/enum pages, rather than at the top of the full docs.

let prefix = render_assoc_const_value(item);
document_full(w, item, cx, &prefix)?;
Ok(())
Expand Down Expand Up @@ -2262,6 +2263,42 @@ 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, "<div class='non-exhaustive'><div class='stab non-exhaustive'>")?;
write!(w, "<details><summary><span class=microscope>🔬</span>")?;

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, "</summary><p>")?;

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 <code>Struct {{ .. }}</code> syntax;
cannot be matched against without a wildcard <code>..</code>; 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 \
<code>_</code> 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, "</p></details></div></div>")?;
}

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);
Expand Down
3 changes: 2 additions & 1 deletion src/librustdoc/html/static/themes/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -406,4 +407,4 @@ kbd {
}
.search-results td span.grey {
color: #ccc;
}
}
3 changes: 2 additions & 1 deletion src/librustdoc/html/static/themes/light.css
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -400,4 +401,4 @@ kbd {
}
.search-results td span.grey {
color: #999;
}
}
8 changes: 8 additions & 0 deletions src/librustdoc/visit_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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,
Expand Down