Auto merge of #52585 - GuillaumeGomez:generic-impls, r=QuietMisdreavus
[rustdoc] Generic impls Fixes #33772. r? @QuietMisdreavus
This commit is contained in:
commit
dab71516f1
@ -8,10 +8,15 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::traits::auto_trait as auto;
|
||||
use rustc::ty::TypeFoldable;
|
||||
use rustc::hir;
|
||||
use rustc::traits::{self, auto_trait as auto};
|
||||
use rustc::ty::{self, ToPredicate, TypeFoldable};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::infer::InferOk;
|
||||
use std::fmt::Debug;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
use core::DocAccessLevels;
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -75,6 +80,141 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
|
||||
self.get_auto_trait_impls(did, &def_ctor, Some(name))
|
||||
}
|
||||
|
||||
fn get_real_ty<F>(&self,
|
||||
def_id: DefId,
|
||||
def_ctor: &F,
|
||||
real_name: &Option<Ident>,
|
||||
generics: &ty::Generics,
|
||||
) -> hir::Ty
|
||||
where F: Fn(DefId) -> Def {
|
||||
let path = get_path_for_type(self.cx.tcx, def_id, def_ctor);
|
||||
let mut segments = path.segments.into_vec();
|
||||
let last = segments.pop().unwrap();
|
||||
|
||||
segments.push(hir::PathSegment::new(
|
||||
real_name.unwrap_or(last.ident),
|
||||
self.generics_to_path_params(generics.clone()),
|
||||
false,
|
||||
));
|
||||
|
||||
let new_path = hir::Path {
|
||||
span: path.span,
|
||||
def: path.def,
|
||||
segments: HirVec::from_vec(segments),
|
||||
};
|
||||
|
||||
hir::Ty {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
|
||||
span: DUMMY_SP,
|
||||
hir_id: hir::DUMMY_HIR_ID,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_blanket_impls<F>(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
def_ctor: &F,
|
||||
name: Option<String>,
|
||||
generics: &ty::Generics,
|
||||
) -> Vec<Item>
|
||||
where F: Fn(DefId) -> Def {
|
||||
let ty = self.cx.tcx.type_of(def_id);
|
||||
let mut traits = Vec::new();
|
||||
if self.cx.access_levels.borrow().is_doc_reachable(def_id) {
|
||||
let real_name = name.clone().map(|name| Ident::from_str(&name));
|
||||
let param_env = self.cx.tcx.param_env(def_id);
|
||||
for &trait_def_id in self.cx.all_traits.iter() {
|
||||
if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
|
||||
self.cx.generated_synthetics
|
||||
.borrow_mut()
|
||||
.get(&(def_id, trait_def_id))
|
||||
.is_some() {
|
||||
continue
|
||||
}
|
||||
self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| {
|
||||
self.cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
let t_generics = infcx.tcx.generics_of(impl_def_id);
|
||||
let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
|
||||
match infcx.tcx.type_of(impl_def_id).sty {
|
||||
::rustc::ty::TypeVariants::TyParam(_) => {},
|
||||
_ => return,
|
||||
}
|
||||
|
||||
let substs = infcx.fresh_substs_for_item(DUMMY_SP, def_id);
|
||||
let ty = ty.subst(infcx.tcx, substs);
|
||||
let param_env = param_env.subst(infcx.tcx, substs);
|
||||
|
||||
let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
|
||||
let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
|
||||
|
||||
// Require the type the impl is implemented on to match
|
||||
// our type, and ignore the impl if there was a mismatch.
|
||||
let cause = traits::ObligationCause::dummy();
|
||||
let eq_result = infcx.at(&cause, param_env)
|
||||
.eq(trait_ref.self_ty(), ty);
|
||||
if let Ok(InferOk { value: (), obligations }) = eq_result {
|
||||
// FIXME(eddyb) ignoring `obligations` might cause false positives.
|
||||
drop(obligations);
|
||||
|
||||
let may_apply = infcx.predicate_may_hold(&traits::Obligation::new(
|
||||
cause.clone(),
|
||||
param_env,
|
||||
trait_ref.to_predicate(),
|
||||
));
|
||||
if !may_apply {
|
||||
return
|
||||
}
|
||||
self.cx.generated_synthetics.borrow_mut()
|
||||
.insert((def_id, trait_def_id));
|
||||
let trait_ = hir::TraitRef {
|
||||
path: get_path_for_type(infcx.tcx,
|
||||
trait_def_id,
|
||||
hir::def::Def::Trait),
|
||||
ref_id: ast::DUMMY_NODE_ID,
|
||||
};
|
||||
let provided_trait_methods =
|
||||
infcx.tcx.provided_trait_methods(trait_def_id)
|
||||
.into_iter()
|
||||
.map(|meth| meth.ident.to_string())
|
||||
.collect();
|
||||
|
||||
let ty = self.get_real_ty(def_id, def_ctor, &real_name, generics);
|
||||
let predicates = infcx.tcx.predicates_of(impl_def_id);
|
||||
|
||||
traits.push(Item {
|
||||
source: infcx.tcx.def_span(impl_def_id).clean(self.cx),
|
||||
name: None,
|
||||
attrs: Default::default(),
|
||||
visibility: None,
|
||||
def_id: self.next_def_id(impl_def_id.krate),
|
||||
stability: None,
|
||||
deprecation: None,
|
||||
inner: ImplItem(Impl {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
generics: (t_generics, &predicates).clean(self.cx),
|
||||
provided_trait_methods,
|
||||
trait_: Some(trait_.clean(self.cx)),
|
||||
for_: ty.clean(self.cx),
|
||||
items: infcx.tcx.associated_items(impl_def_id)
|
||||
.collect::<Vec<_>>()
|
||||
.clean(self.cx),
|
||||
polarity: None,
|
||||
synthetic: false,
|
||||
blanket_impl: Some(infcx.tcx.type_of(impl_def_id)
|
||||
.clean(self.cx)),
|
||||
}),
|
||||
});
|
||||
debug!("{:?} => {}", trait_ref, may_apply);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
traits
|
||||
}
|
||||
|
||||
pub fn get_auto_trait_impls<F>(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
@ -122,6 +262,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
|
||||
def_ctor,
|
||||
tcx.require_lang_item(lang_items::SyncTraitLangItem),
|
||||
).into_iter())
|
||||
.chain(self.get_blanket_impls(def_id, def_ctor, name, &generics).into_iter())
|
||||
.collect();
|
||||
|
||||
debug!(
|
||||
@ -196,31 +337,8 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let path = get_path_for_type(self.cx.tcx, def_id, def_ctor);
|
||||
let mut segments = path.segments.into_vec();
|
||||
let last = segments.pop().unwrap();
|
||||
|
||||
let real_name = name.map(|name| Ident::from_str(&name));
|
||||
|
||||
segments.push(hir::PathSegment::new(
|
||||
real_name.unwrap_or(last.ident),
|
||||
self.generics_to_path_params(generics.clone()),
|
||||
false,
|
||||
));
|
||||
|
||||
let new_path = hir::Path {
|
||||
span: path.span,
|
||||
def: path.def,
|
||||
segments: HirVec::from_vec(segments),
|
||||
};
|
||||
|
||||
let ty = hir::Ty {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: hir::TyKind::Path(hir::QPath::Resolved(None, P(new_path))),
|
||||
span: DUMMY_SP,
|
||||
hir_id: hir::DUMMY_HIR_ID,
|
||||
};
|
||||
let ty = self.get_real_ty(def_id, def_ctor, &real_name, &generics);
|
||||
|
||||
return Some(Item {
|
||||
source: Span::empty(),
|
||||
@ -239,6 +357,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
|
||||
items: Vec::new(),
|
||||
polarity,
|
||||
synthetic: true,
|
||||
blanket_impl: None,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
@ -275,7 +275,6 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
|
||||
if auto_traits {
|
||||
let auto_impls = get_auto_traits_with_def_id(cx, did);
|
||||
let mut renderinfo = cx.renderinfo.borrow_mut();
|
||||
|
||||
let new_impls: Vec<clean::Item> = auto_impls.into_iter()
|
||||
.filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
|
||||
|
||||
@ -415,6 +414,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
|
||||
items: trait_items,
|
||||
polarity: Some(polarity.clean(cx)),
|
||||
synthetic: false,
|
||||
blanket_impl: None,
|
||||
}),
|
||||
source: tcx.def_span(did).clean(cx),
|
||||
name: None,
|
||||
|
@ -1549,7 +1549,6 @@ impl GenericBound {
|
||||
}
|
||||
|
||||
fn get_trait_type(&self) -> Option<Type> {
|
||||
|
||||
if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
|
||||
return Some(trait_.clone());
|
||||
}
|
||||
@ -3880,6 +3879,7 @@ pub struct Impl {
|
||||
pub items: Vec<Item>,
|
||||
pub polarity: Option<ImplPolarity>,
|
||||
pub synthetic: bool,
|
||||
pub blanket_impl: Option<Type>,
|
||||
}
|
||||
|
||||
pub fn get_auto_traits_with_node_id(cx: &DocContext, id: ast::NodeId, name: String) -> Vec<Item> {
|
||||
@ -3947,6 +3947,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
|
||||
items,
|
||||
polarity: Some(self.polarity.clean(cx)),
|
||||
synthetic: false,
|
||||
blanket_impl: None,
|
||||
})
|
||||
});
|
||||
ret
|
||||
|
@ -11,7 +11,7 @@
|
||||
use rustc_lint;
|
||||
use rustc_driver::{self, driver, target_features, abort_on_err};
|
||||
use rustc::session::{self, config};
|
||||
use rustc::hir::def_id::{DefId, CrateNum};
|
||||
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc::middle::privacy::AccessLevels;
|
||||
@ -84,6 +84,7 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
|
||||
/// Maps (type_id, trait_id) -> auto trait impl
|
||||
pub generated_synthetics: RefCell<FxHashSet<(DefId, DefId)>>,
|
||||
pub current_item_name: RefCell<Option<Name>>,
|
||||
pub all_traits: Vec<DefId>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
|
||||
@ -386,6 +387,7 @@ pub fn run_core(search_paths: SearchPaths,
|
||||
all_fake_def_ids: RefCell::new(FxHashSet()),
|
||||
generated_synthetics: RefCell::new(FxHashSet()),
|
||||
current_item_name: RefCell::new(None),
|
||||
all_traits: tcx.all_traits(LOCAL_CRATE).to_vec(),
|
||||
};
|
||||
debug!("crate: {:?}", tcx.hir.krate());
|
||||
|
||||
|
@ -769,7 +769,11 @@ fn fmt_impl(i: &clean::Impl,
|
||||
write!(f, " for ")?;
|
||||
}
|
||||
|
||||
fmt_type(&i.for_, f, use_absolute)?;
|
||||
if let Some(ref ty) = i.blanket_impl {
|
||||
fmt_type(ty, f, use_absolute)?;
|
||||
} else {
|
||||
fmt_type(&i.for_, f, use_absolute)?;
|
||||
}
|
||||
|
||||
fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
|
||||
Ok(())
|
||||
|
@ -177,7 +177,7 @@ pub enum ExternalLocation {
|
||||
}
|
||||
|
||||
/// Metadata about implementations for a type or trait.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Impl {
|
||||
pub impl_item: clean::Item,
|
||||
}
|
||||
@ -2900,18 +2900,18 @@ fn item_trait(
|
||||
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?;
|
||||
|
||||
let cache = cache();
|
||||
let impl_header = "
|
||||
<h2 id='implementors' class='small-section-header'>
|
||||
Implementors<a href='#implementors' class='anchor'></a>
|
||||
</h2>
|
||||
<ul class='item-list' id='implementors-list'>
|
||||
let impl_header = "\
|
||||
<h2 id='implementors' class='small-section-header'>\
|
||||
Implementors<a href='#implementors' class='anchor'></a>\
|
||||
</h2>\
|
||||
<ul class='item-list' id='implementors-list'>\
|
||||
";
|
||||
|
||||
let synthetic_impl_header = "
|
||||
<h2 id='synthetic-implementors' class='small-section-header'>
|
||||
Auto implementors<a href='#synthetic-implementors' class='anchor'></a>
|
||||
</h2>
|
||||
<ul class='item-list' id='synthetic-implementors-list'>
|
||||
let synthetic_impl_header = "\
|
||||
<h2 id='synthetic-implementors' class='small-section-header'>\
|
||||
Auto implementors<a href='#synthetic-implementors' class='anchor'></a>\
|
||||
</h2>\
|
||||
<ul class='item-list' id='synthetic-implementors-list'>\
|
||||
";
|
||||
|
||||
let mut synthetic_types = Vec::new();
|
||||
@ -2942,9 +2942,9 @@ fn item_trait(
|
||||
.map_or(true, |d| cache.paths.contains_key(&d)));
|
||||
|
||||
|
||||
let (synthetic, concrete) = local.iter()
|
||||
.partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
|
||||
|
||||
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter()
|
||||
.filter(|i| i.inner_impl().blanket_impl.is_none())
|
||||
.partition(|i| i.inner_impl().synthetic);
|
||||
|
||||
if !foreign.is_empty() {
|
||||
write!(w, "
|
||||
@ -3590,18 +3590,19 @@ fn render_assoc_items(w: &mut fmt::Formatter,
|
||||
if !non_trait.is_empty() {
|
||||
let render_mode = match what {
|
||||
AssocItemRender::All => {
|
||||
write!(w, "
|
||||
<h2 id='methods' class='small-section-header'>
|
||||
Methods<a href='#methods' class='anchor'></a>
|
||||
</h2>
|
||||
write!(w, "\
|
||||
<h2 id='methods' class='small-section-header'>\
|
||||
Methods<a href='#methods' class='anchor'></a>\
|
||||
</h2>\
|
||||
")?;
|
||||
RenderMode::Normal
|
||||
}
|
||||
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
|
||||
write!(w, "
|
||||
<h2 id='deref-methods' class='small-section-header'>
|
||||
Methods from {}<Target = {}><a href='#deref-methods' class='anchor'></a>
|
||||
</h2>
|
||||
write!(w, "\
|
||||
<h2 id='deref-methods' class='small-section-header'>\
|
||||
Methods from {}<Target = {}>\
|
||||
<a href='#deref-methods' class='anchor'></a>\
|
||||
</h2>\
|
||||
", trait_, type_)?;
|
||||
RenderMode::ForDeref { mut_: deref_mut_ }
|
||||
}
|
||||
@ -3625,9 +3626,12 @@ fn render_assoc_items(w: &mut fmt::Formatter,
|
||||
render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?;
|
||||
}
|
||||
|
||||
let (synthetic, concrete) = traits
|
||||
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = traits
|
||||
.iter()
|
||||
.partition::<Vec<_>, _>(|t| t.inner_impl().synthetic);
|
||||
.partition(|t| t.inner_impl().synthetic);
|
||||
let (blanket_impl, concrete) = concrete
|
||||
.into_iter()
|
||||
.partition(|t| t.inner_impl().blanket_impl.is_some());
|
||||
|
||||
struct RendererStruct<'a, 'b, 'c>(&'a Context, Vec<&'b &'b Impl>, &'c clean::Item);
|
||||
|
||||
@ -3639,23 +3643,36 @@ fn render_assoc_items(w: &mut fmt::Formatter,
|
||||
|
||||
let impls = format!("{}", RendererStruct(cx, concrete, containing_item));
|
||||
if !impls.is_empty() {
|
||||
write!(w, "
|
||||
<h2 id='implementations' class='small-section-header'>
|
||||
Trait Implementations<a href='#implementations' class='anchor'></a>
|
||||
</h2>
|
||||
write!(w, "\
|
||||
<h2 id='implementations' class='small-section-header'>\
|
||||
Trait Implementations<a href='#implementations' class='anchor'></a>\
|
||||
</h2>\
|
||||
<div id='implementations-list'>{}</div>", impls)?;
|
||||
}
|
||||
|
||||
if !synthetic.is_empty() {
|
||||
write!(w, "
|
||||
<h2 id='synthetic-implementations' class='small-section-header'>
|
||||
Auto Trait Implementations<a href='#synthetic-implementations' class='anchor'></a>
|
||||
</h2>
|
||||
<div id='synthetic-implementations-list'>
|
||||
write!(w, "\
|
||||
<h2 id='synthetic-implementations' class='small-section-header'>\
|
||||
Auto Trait Implementations\
|
||||
<a href='#synthetic-implementations' class='anchor'></a>\
|
||||
</h2>\
|
||||
<div id='synthetic-implementations-list'>\
|
||||
")?;
|
||||
render_impls(cx, w, &synthetic, containing_item)?;
|
||||
write!(w, "</div>")?;
|
||||
}
|
||||
|
||||
if !blanket_impl.is_empty() {
|
||||
write!(w, "\
|
||||
<h2 id='blanket-implementations' class='small-section-header'>\
|
||||
Blanket Implementations\
|
||||
<a href='#blanket-implementations' class='anchor'></a>\
|
||||
</h2>\
|
||||
<div id='blanket-implementations-list'>\
|
||||
")?;
|
||||
render_impls(cx, w, &blanket_impl, containing_item)?;
|
||||
write!(w, "</div>")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -4201,12 +4218,16 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
|
||||
.collect::<String>()
|
||||
};
|
||||
|
||||
let (synthetic, concrete) = v
|
||||
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = v
|
||||
.iter()
|
||||
.partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
|
||||
let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
|
||||
.into_iter()
|
||||
.partition::<Vec<_>, _>(|i| i.inner_impl().blanket_impl.is_some());
|
||||
|
||||
let concrete_format = format_impls(concrete);
|
||||
let synthetic_format = format_impls(synthetic);
|
||||
let blanket_format = format_impls(blanket_impl);
|
||||
|
||||
if !concrete_format.is_empty() {
|
||||
out.push_str("<a class=\"sidebar-title\" href=\"#implementations\">\
|
||||
@ -4219,6 +4240,12 @@ fn sidebar_assoc_items(it: &clean::Item) -> String {
|
||||
Auto Trait Implementations</a>");
|
||||
out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", synthetic_format));
|
||||
}
|
||||
|
||||
if !blanket_format.is_empty() {
|
||||
out.push_str("<a class=\"sidebar-title\" href=\"#blanket-implementations\">\
|
||||
Blanket Implementations</a>");
|
||||
out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", blanket_format));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
25
src/test/rustdoc/generic-impl.rs
Normal file
25
src/test/rustdoc/generic-impl.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_name = "foo"]
|
||||
|
||||
use std::fmt;
|
||||
|
||||
// @!has foo/struct.Bar.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
|
||||
pub struct Bar;
|
||||
|
||||
// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
|
||||
pub struct Foo;
|
||||
|
||||
impl fmt::Display for Foo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Foo")
|
||||
}
|
||||
}
|
@ -56,7 +56,6 @@ impl T for S1 {
|
||||
// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
|
||||
// @!has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
|
||||
// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
|
||||
// @!has - '//*[@class="docblock"]' 'Read more'
|
||||
pub struct S2(usize);
|
||||
|
||||
/// Docs associated with the S2 trait implementation.
|
||||
|
@ -31,11 +31,11 @@ pub trait Foo {
|
||||
// @has - '//*[@class="sidebar-title"][@href="#fields"]' 'Fields'
|
||||
// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f"]' 'f'
|
||||
// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.u"]' 'u'
|
||||
// @!has - '//*[@class="sidebar-links"]/a' 'w'
|
||||
// @!has - '//*[@class="sidebar-links"]/a' 'waza'
|
||||
pub struct Bar {
|
||||
pub f: u32,
|
||||
pub u: u32,
|
||||
w: u32,
|
||||
waza: u32,
|
||||
}
|
||||
|
||||
// @has foo/enum.En.html
|
||||
@ -51,9 +51,9 @@ pub enum En {
|
||||
// @has - '//*[@class="sidebar-title"][@href="#fields"]' 'Fields'
|
||||
// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f1"]' 'f1'
|
||||
// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f2"]' 'f2'
|
||||
// @!has - '//*[@class="sidebar-links"]/a' 'w'
|
||||
// @!has - '//*[@class="sidebar-links"]/a' 'waza'
|
||||
pub union MyUnion {
|
||||
pub f1: u32,
|
||||
pub f2: f32,
|
||||
w: u32,
|
||||
waza: u32,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user