rollup merge of #19969: aturon/inherit-trait-stab

There is currently no way to specify the stability level for a trait
impl produced by `deriving`. This patch is a stopgap solution that:

* Turns of stability inheritance for trait impls, and
* Uses the stability level of the *trait* if no level is directly
  specified.

That is, manual trait impls may still provide a directly stability
level, but `deriving` will use the level of the trait. While not a
perfect solution, it should be good enough for 1.0 API stabilization, as
we will like *remove* any unwanted impls outright.

r? @alexcrichton
This commit is contained in:
Alex Crichton 2014-12-21 00:04:02 -08:00
commit ee1bb3f25b

View File

@ -43,7 +43,8 @@ struct Annotator {
impl Annotator {
// Determine the stability for a node based on its attributes and inherited
// stability. The stability is recorded in the index and used as the parent.
fn annotate<F>(&mut self, id: NodeId, attrs: &Vec<Attribute>, f: F) where
fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
attrs: &Vec<Attribute>, f: F) where
F: FnOnce(&mut Annotator),
{
match attr::find_stability(attrs.as_slice()) {
@ -60,7 +61,9 @@ impl Annotator {
}
}
None => {
self.parent.clone().map(|stab| self.index.local.insert(id, stab));
if use_parent {
self.parent.clone().map(|stab| self.index.local.insert(id, stab));
}
f(self);
}
}
@ -69,11 +72,24 @@ impl Annotator {
impl<'v> Visitor<'v> for Annotator {
fn visit_item(&mut self, i: &Item) {
self.annotate(i.id, &i.attrs, |v| visit::walk_item(v, i));
// FIXME (#18969): the following is a hack around the fact
// that we cannot currently annotate the stability of
// `deriving`. Basically, we do *not* allow stability
// inheritance on trait implementations, so that derived
// implementations appear to be unannotated. This then allows
// derived implementations to be automatically tagged with the
// stability of the trait. This is WRONG, but expedient to get
// libstd stabilized for the 1.0 release.
let use_parent = match i.node {
ast::ItemImpl(_, _, Some(_), _, _) => false,
_ => true,
};
self.annotate(i.id, use_parent, &i.attrs, |v| visit::walk_item(v, i));
if let ast::ItemStruct(ref sd, _) = i.node {
sd.ctor_id.map(|id| {
self.annotate(id, &i.attrs, |_| {})
self.annotate(id, true, &i.attrs, |_| {})
});
}
}
@ -82,7 +98,7 @@ impl<'v> Visitor<'v> for Annotator {
_: &'v Block, _: Span, _: NodeId) {
if let FkMethod(_, _, meth) = fk {
// Methods are not already annotated, so we annotate it
self.annotate(meth.id, &meth.attrs, |_| {});
self.annotate(meth.id, true, &meth.attrs, |_| {});
}
// Items defined in a function body have no reason to have
// a stability attribute, so we don't recurse.
@ -101,15 +117,17 @@ impl<'v> Visitor<'v> for Annotator {
TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs),
};
self.annotate(id, attrs, |v| visit::walk_trait_item(v, t));
self.annotate(id, true, attrs, |v| visit::walk_trait_item(v, t));
}
fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
self.annotate(var.node.id, &var.node.attrs, |v| visit::walk_variant(v, var, g))
self.annotate(var.node.id, true, &var.node.attrs,
|v| visit::walk_variant(v, var, g))
}
fn visit_struct_field(&mut self, s: &StructField) {
self.annotate(s.node.id, &s.node.attrs, |v| visit::walk_struct_field(v, s));
self.annotate(s.node.id, true, &s.node.attrs,
|v| visit::walk_struct_field(v, s));
}
}
@ -123,7 +141,8 @@ impl Index {
},
parent: None
};
annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, |v| visit::walk_crate(v, krate));
annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs,
|v| visit::walk_crate(v, krate));
annotator.index
}
}
@ -135,16 +154,29 @@ pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
match ty::trait_item_of_item(tcx, id) {
Some(ty::MethodTraitItemId(trait_method_id))
if trait_method_id != id => {
lookup(tcx, trait_method_id)
}
_ if is_local(id) => {
tcx.stability.borrow().local.get(&id.node).cloned()
}
_ => {
let stab = csearch::get_stability(&tcx.sess.cstore, id);
let mut index = tcx.stability.borrow_mut();
(*index).extern_cache.insert(id, stab.clone());
stab
return lookup(tcx, trait_method_id)
}
_ => {}
}
let item_stab = if is_local(id) {
tcx.stability.borrow().local.get(&id.node).cloned()
} else {
let stab = csearch::get_stability(&tcx.sess.cstore, id);
let mut index = tcx.stability.borrow_mut();
(*index).extern_cache.insert(id, stab.clone());
stab
};
item_stab.or_else(|| {
if let Some(trait_id) = ty::trait_id_of_impl(tcx, id) {
// FIXME (#18969): for the time being, simply use the
// stability of the trait to determine the stability of any
// unmarked impls for it. See FIXME above for more details.
lookup(tcx, trait_id)
} else {
None
}
})
}