Skip to content

Commit

Permalink
rustc: unify and simplify managing associated items.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Nov 10, 2016
1 parent 9292e1c commit 1fd9bb7
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 147 deletions.
51 changes: 23 additions & 28 deletions clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
did: DefId) -> clean::Trait {
let def = tcx.lookup_trait_def(did);
let trait_items = tcx.trait_items(did).clean(cx);
let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect();
let predicates = tcx.lookup_predicates(did);
let generics = (def.generics, &predicates).clean(cx);
let generics = filter_non_trait_generics(did, generics);
Expand Down Expand Up @@ -307,7 +307,6 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext,

for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
if !def_id.is_local() {
tcx.populate_implementations_for_primitive_if_necessary(def_id);
build_impl(cx, tcx, def_id, &mut impls);
}
}
Expand Down Expand Up @@ -367,43 +366,40 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
}

let predicates = tcx.lookup_predicates(did);
let trait_items = tcx.sess.cstore.impl_or_trait_items(did)
.iter()
.filter_map(|&did| {
match tcx.impl_or_trait_item(did) {
ty::ConstTraitItem(ref assoc_const) => {
let did = assoc_const.def_id;
let type_scheme = tcx.lookup_item_type(did);
let default = if assoc_const.has_value {
let trait_items = tcx.associated_items(did).filter_map(|item| {
match item.kind {
ty::AssociatedKind::Const => {
let type_scheme = tcx.lookup_item_type(item.def_id);
let default = if item.has_value {
Some(pprust::expr_to_string(
lookup_const_by_id(tcx, did, None).unwrap().0))
lookup_const_by_id(tcx, item.def_id, None).unwrap().0))
} else {
None
};
Some(clean::Item {
name: Some(assoc_const.name.clean(cx)),
name: Some(item.name.clean(cx)),
inner: clean::AssociatedConstItem(
type_scheme.ty.clean(cx),
default,
),
source: clean::Span::empty(),
attrs: vec![],
visibility: None,
stability: tcx.lookup_stability(did).clean(cx),
deprecation: tcx.lookup_deprecation(did).clean(cx),
def_id: did
stability: tcx.lookup_stability(item.def_id).clean(cx),
deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
def_id: item.def_id
})
}
ty::MethodTraitItem(method) => {
if method.vis != ty::Visibility::Public && associated_trait.is_none() {
ty::AssociatedKind::Method => {
if item.vis != ty::Visibility::Public && associated_trait.is_none() {
return None
}
let mut item = method.clean(cx);
item.inner = match item.inner.clone() {
let mut cleaned = item.clean(cx);
cleaned.inner = match cleaned.inner.clone() {
clean::TyMethodItem(clean::TyMethod {
unsafety, decl, generics, abi
}) => {
let constness = if tcx.sess.cstore.is_const_fn(did) {
let constness = if tcx.sess.cstore.is_const_fn(item.def_id) {
hir::Constness::Const
} else {
hir::Constness::NotConst
Expand All @@ -419,27 +415,26 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
}
_ => panic!("not a tymethod"),
};
Some(item)
Some(cleaned)
}
ty::TypeTraitItem(ref assoc_ty) => {
let did = assoc_ty.def_id;
ty::AssociatedKind::Type => {
let typedef = clean::Typedef {
type_: assoc_ty.ty.unwrap().clean(cx),
type_: tcx.lookup_item_type(item.def_id).ty.clean(cx),
generics: clean::Generics {
lifetimes: vec![],
type_params: vec![],
where_predicates: vec![]
}
};
Some(clean::Item {
name: Some(assoc_ty.name.clean(cx)),
name: Some(item.name.clean(cx)),
inner: clean::TypedefItem(typedef, true),
source: clean::Span::empty(),
attrs: vec![],
visibility: None,
stability: tcx.lookup_stability(did).clean(cx),
deprecation: tcx.lookup_deprecation(did).clean(cx),
def_id: did
stability: tcx.lookup_stability(item.def_id).clean(cx),
deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
def_id: item.def_id
})
}
}
Expand Down
224 changes: 105 additions & 119 deletions clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1338,48 +1338,117 @@ impl Clean<Item> for hir::ImplItem {
}
}

impl<'tcx> Clean<Item> for ty::Method<'tcx> {
impl<'tcx> Clean<Item> for ty::AssociatedItem {
fn clean(&self, cx: &DocContext) -> Item {
let generics = (self.generics, &self.predicates).clean(cx);
let mut decl = (self.def_id, &self.fty.sig).clean(cx);
match self.explicit_self {
ty::ExplicitSelfCategory::ByValue => {
decl.inputs.values[0].type_ = Infer;
let inner = match self.kind {
ty::AssociatedKind::Const => {
let ty = cx.tcx().lookup_item_type(self.def_id).ty;
AssociatedConstItem(ty.clean(cx), None)
}
ty::ExplicitSelfCategory::ByReference(..) => {
match decl.inputs.values[0].type_ {
BorrowedRef{ref mut type_, ..} => **type_ = Infer,
_ => unreachable!(),
ty::AssociatedKind::Method => {
let generics = (cx.tcx().lookup_generics(self.def_id),
&cx.tcx().lookup_predicates(self.def_id)).clean(cx);
let fty = match cx.tcx().lookup_item_type(self.def_id).ty.sty {
ty::TyFnDef(_, _, f) => f,
_ => unreachable!()
};
let mut decl = (self.def_id, &fty.sig).clean(cx);

if self.method_has_self_argument {
let self_ty = match self.container {
ty::ImplContainer(def_id) => {
cx.tcx().lookup_item_type(def_id).ty
}
ty::TraitContainer(_) => cx.tcx().mk_self_type()
};
let self_arg_ty = *fty.sig.input(0).skip_binder();
if self_arg_ty == self_ty {
decl.inputs.values[0].type_ = Infer;
} else if let ty::TyRef(_, mt) = self_arg_ty.sty {
if mt.ty == self_ty {
match decl.inputs.values[0].type_ {
BorrowedRef{ref mut type_, ..} => **type_ = Infer,
_ => unreachable!(),
}
}
}
}
let provided = match self.container {
ty::ImplContainer(_) => false,
ty::TraitContainer(_) => self.has_value
};
if provided {
MethodItem(Method {
unsafety: fty.unsafety,
generics: generics,
decl: decl,
abi: fty.abi,

// trait methods canot (currently, at least) be const
constness: hir::Constness::NotConst,
})
} else {
TyMethodItem(TyMethod {
unsafety: fty.unsafety,
generics: generics,
decl: decl,
abi: fty.abi,
})
}
}
_ => {}
}
let provided = match self.container {
ty::ImplContainer(..) => false,
ty::TraitContainer(did) => {
cx.tcx().provided_trait_methods(did).iter().any(|m| {
m.def_id == self.def_id
})
ty::AssociatedKind::Type => {
let my_name = self.name.clean(cx);

let mut bounds = if let ty::TraitContainer(did) = self.container {
// When loading a cross-crate associated type, the bounds for this type
// are actually located on the trait/impl itself, so we need to load
// all of the generics from there and then look for bounds that are
// applied to this associated type in question.
let def = cx.tcx().lookup_trait_def(did);
let predicates = cx.tcx().lookup_predicates(did);
let generics = (def.generics, &predicates).clean(cx);
generics.where_predicates.iter().filter_map(|pred| {
let (name, self_type, trait_, bounds) = match *pred {
WherePredicate::BoundPredicate {
ty: QPath { ref name, ref self_type, ref trait_ },
ref bounds
} => (name, self_type, trait_, bounds),
_ => return None,
};
if *name != my_name { return None }
match **trait_ {
ResolvedPath { did, .. } if did == self.container.id() => {}
_ => return None,
}
match **self_type {
Generic(ref s) if *s == "Self" => {}
_ => return None,
}
Some(bounds)
}).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
} else {
vec![]
};

// Our Sized/?Sized bound didn't get handled when creating the generics
// because we didn't actually get our whole set of bounds until just now
// (some of them may have come from the trait). If we do have a sized
// bound, we remove it, and if we don't then we add the `?Sized` bound
// at the end.
match bounds.iter().position(|b| b.is_sized_bound(cx)) {
Some(i) => { bounds.remove(i); }
None => bounds.push(TyParamBound::maybe_sized(cx)),
}

let ty = if self.has_value {
Some(cx.tcx().lookup_item_type(self.def_id).ty)
} else {
None
};

AssociatedTypeItem(bounds, ty.clean(cx))
}
};
let inner = if provided {
MethodItem(Method {
unsafety: self.fty.unsafety,
generics: generics,
decl: decl,
abi: self.fty.abi,

// trait methods canot (currently, at least) be const
constness: hir::Constness::NotConst,
})
} else {
TyMethodItem(TyMethod {
unsafety: self.fty.unsafety,
generics: generics,
decl: decl,
abi: self.fty.abi,
})
};

Item {
name: Some(self.name.clean(cx)),
Expand All @@ -1394,16 +1463,6 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
}
}

impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
match *self {
ty::ConstTraitItem(ref cti) => cti.clean(cx),
ty::MethodTraitItem(ref mti) => mti.clean(cx),
ty::TypeTraitItem(ref tti) => tti.clean(cx),
}
}
}

/// A trait reference, which may have higher ranked lifetimes.
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub struct PolyTrait {
Expand Down Expand Up @@ -2884,79 +2943,6 @@ impl Clean<Deprecation> for attr::Deprecation {
}
}

impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
Item {
source: DUMMY_SP.clean(cx),
name: Some(self.name.clean(cx)),
attrs: Vec::new(),
inner: AssociatedConstItem(self.ty.clean(cx), None),
visibility: None,
def_id: self.def_id,
stability: None,
deprecation: None,
}
}
}

impl<'tcx> Clean<Item> for ty::AssociatedType<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
let my_name = self.name.clean(cx);

let mut bounds = if let ty::TraitContainer(did) = self.container {
// When loading a cross-crate associated type, the bounds for this type
// are actually located on the trait/impl itself, so we need to load
// all of the generics from there and then look for bounds that are
// applied to this associated type in question.
let def = cx.tcx().lookup_trait_def(did);
let predicates = cx.tcx().lookup_predicates(did);
let generics = (def.generics, &predicates).clean(cx);
generics.where_predicates.iter().filter_map(|pred| {
let (name, self_type, trait_, bounds) = match *pred {
WherePredicate::BoundPredicate {
ty: QPath { ref name, ref self_type, ref trait_ },
ref bounds
} => (name, self_type, trait_, bounds),
_ => return None,
};
if *name != my_name { return None }
match **trait_ {
ResolvedPath { did, .. } if did == self.container.id() => {}
_ => return None,
}
match **self_type {
Generic(ref s) if *s == "Self" => {}
_ => return None,
}
Some(bounds)
}).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
} else {
vec![]
};

// Our Sized/?Sized bound didn't get handled when creating the generics
// because we didn't actually get our whole set of bounds until just now
// (some of them may have come from the trait). If we do have a sized
// bound, we remove it, and if we don't then we add the `?Sized` bound
// at the end.
match bounds.iter().position(|b| b.is_sized_bound(cx)) {
Some(i) => { bounds.remove(i); }
None => bounds.push(TyParamBound::maybe_sized(cx)),
}

Item {
source: DUMMY_SP.clean(cx),
name: Some(self.name.clean(cx)),
attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
inner: AssociatedTypeItem(bounds, self.ty.clean(cx)),
visibility: self.vis.clean(cx),
def_id: self.def_id,
stability: cx.tcx().lookup_stability(self.def_id).clean(cx),
deprecation: cx.tcx().lookup_deprecation(self.def_id).clean(cx),
}
}
}

fn lang_struct(cx: &DocContext, did: Option<DefId>,
t: ty::Ty, name: &str,
fallback: fn(Box<Type>) -> Type) -> Type {
Expand Down

0 comments on commit 1fd9bb7

Please sign in to comment.