auto merge of #16286 : pcwalton/rust/associated-items-groundwork, r=nikomatsakis

methods.

This paves the way to associated items by introducing an extra level of
abstraction ("impl-or-trait item") between traits/implementations and
methods. This new abstraction is encoded in the metadata and used
throughout the compiler where appropriate.

There are no functional changes; this is purely a refactoring.

r? @nick29581
This commit is contained in:
bors 2014-08-14 19:11:18 +00:00
commit a8c8e3f80f
49 changed files with 1909 additions and 1103 deletions

View File

@ -109,10 +109,14 @@ fn fold_foreign_mod(cx: &mut Context, nm: &ast::ForeignMod) -> ast::ForeignMod {
fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ {
let item = match *item {
ast::ItemImpl(ref a, ref b, c, ref methods) => {
let methods = methods.iter().filter(|m| method_in_cfg(cx, &***m))
.map(|x| *x).collect();
ast::ItemImpl((*a).clone(), (*b).clone(), c, methods)
ast::ItemImpl(ref a, ref b, c, ref impl_items) => {
let impl_items = impl_items.iter()
.filter(|ii| {
impl_item_in_cfg(cx, &**ii)
})
.map(|x| *x)
.collect();
ast::ItemImpl((*a).clone(), (*b).clone(), c, impl_items)
}
ast::ItemTrait(ref a, ref b, ref c, ref methods) => {
let methods = methods.iter()
@ -230,14 +234,16 @@ fn view_item_in_cfg(cx: &mut Context, item: &ast::ViewItem) -> bool {
return (cx.in_cfg)(item.attrs.as_slice());
}
fn method_in_cfg(cx: &mut Context, meth: &ast::Method) -> bool {
return (cx.in_cfg)(meth.attrs.as_slice());
fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitItem) -> bool {
match *meth {
ast::RequiredMethod(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
ast::ProvidedMethod(meth) => (cx.in_cfg)(meth.attrs.as_slice())
}
}
fn trait_method_in_cfg(cx: &mut Context, meth: &ast::TraitMethod) -> bool {
match *meth {
ast::Required(ref meth) => (cx.in_cfg)(meth.attrs.as_slice()),
ast::Provided(meth) => (cx.in_cfg)(meth.attrs.as_slice())
fn impl_item_in_cfg(cx: &mut Context, impl_item: &ast::ImplItem) -> bool {
match *impl_item {
ast::MethodImplItem(meth) => (cx.in_cfg)(meth.attrs.as_slice()),
}
}

View File

@ -801,15 +801,19 @@ fn method_context(cx: &Context, m: &ast::Method) -> MethodContext {
node: m.id
};
match cx.tcx.methods.borrow().find_copy(&did) {
match cx.tcx.impl_or_trait_items.borrow().find_copy(&did) {
None => cx.sess().span_bug(m.span, "missing method descriptor?!"),
Some(md) => {
match md.container {
ty::TraitContainer(..) => TraitDefaultImpl,
ty::ImplContainer(cid) => {
match ty::impl_trait_ref(cx.tcx, cid) {
Some(..) => TraitImpl,
None => PlainImpl
match md {
ty::MethodTraitItem(md) => {
match md.container {
ty::TraitContainer(..) => TraitDefaultImpl,
ty::ImplContainer(cid) => {
match ty::impl_trait_ref(cx.tcx, cid) {
Some(..) => TraitImpl,
None => PlainImpl
}
}
}
}
}
@ -1470,7 +1474,15 @@ impl LintPass for Stability {
trait_id: trait_id,
method_num: index,
..
}) => ty::trait_method(cx.tcx, trait_id, index).def_id
}) => {
match ty::trait_item(cx.tcx,
trait_id,
index) {
ty::MethodTraitItem(method) => {
method.def_id
}
}
}
}
}
None => return

View File

@ -563,9 +563,9 @@ impl<'a> Visitor<()> for Context<'a> {
visit::walk_generics(self, g, ());
}
fn visit_trait_method(&mut self, m: &ast::TraitMethod, _: ()) {
fn visit_trait_item(&mut self, m: &ast::TraitItem, _: ()) {
run_lints!(self, check_trait_method, m);
visit::walk_trait_method(self, m, ());
visit::walk_trait_item(self, m, ());
}
fn visit_opt_lifetime_ref(&mut self, sp: Span, lt: &Option<ast::Lifetime>, _: ()) {

View File

@ -141,7 +141,7 @@ pub trait LintPass {
fn check_fn(&mut self, _: &Context,
_: &FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
fn check_ty_method(&mut self, _: &Context, _: &ast::TypeMethod) { }
fn check_trait_method(&mut self, _: &Context, _: &ast::TraitMethod) { }
fn check_trait_method(&mut self, _: &Context, _: &ast::TraitItem) { }
fn check_struct_def(&mut self, _: &Context,
_: &ast::StructDef, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
fn check_struct_def_post(&mut self, _: &Context,

View File

@ -77,7 +77,7 @@ pub static tag_crate_dep_hash: uint = 0x1e;
pub static tag_mod_impl: uint = 0x1f;
pub static tag_item_trait_method: uint = 0x20;
pub static tag_item_trait_item: uint = 0x20;
pub static tag_item_trait_ref: uint = 0x21;
pub static tag_item_super_trait_ref: uint = 0x22;
@ -95,14 +95,14 @@ pub static tag_item_field_origin: uint = 0x29;
pub static tag_item_variances: uint = 0x2a;
/*
trait items contain tag_item_trait_method elements,
impl items contain tag_item_impl_method elements, and classes
trait items contain tag_item_trait_item elements,
impl items contain tag_item_impl_item elements, and classes
have both. That's because some code treats classes like traits,
and other code treats them like impls. Because classes can contain
both, tag_item_trait_method and tag_item_impl_method have to be two
both, tag_item_trait_item and tag_item_impl_item have to be two
different tags.
*/
pub static tag_item_impl_method: uint = 0x30;
pub static tag_item_impl_item: uint = 0x30;
pub static tag_item_trait_method_explicit_self: uint = 0x31;
@ -154,9 +154,11 @@ impl astencode_tag {
}
}
pub static tag_item_trait_method_sort: uint = 0x60;
pub static tag_item_trait_item_sort: uint = 0x60;
pub static tag_item_impl_type_basename: uint = 0x61;
pub static tag_item_trait_parent_sort: uint = 0x61;
pub static tag_item_impl_type_basename: uint = 0x62;
pub static tag_crate_triple: uint = 0x66;

View File

@ -16,6 +16,7 @@ use metadata::common::*;
use metadata::cstore;
use metadata::decoder;
use middle::lang_items;
use middle::resolve;
use middle::ty;
use middle::typeck;
use middle::subst::VecPerParamSpace;
@ -121,30 +122,33 @@ pub fn get_enum_variants(tcx: &ty::ctxt, def: ast::DefId)
}
/// Returns information about the given implementation.
pub fn get_impl_methods(cstore: &cstore::CStore, impl_def_id: ast::DefId)
-> Vec<ast::DefId> {
pub fn get_impl_items(cstore: &cstore::CStore, impl_def_id: ast::DefId)
-> Vec<ty::ImplOrTraitItemId> {
let cdata = cstore.get_crate_data(impl_def_id.krate);
decoder::get_impl_methods(&*cdata, impl_def_id.node)
decoder::get_impl_items(&*cdata, impl_def_id.node)
}
pub fn get_method(tcx: &ty::ctxt, def: ast::DefId) -> ty::Method {
pub fn get_impl_or_trait_item(tcx: &ty::ctxt, def: ast::DefId)
-> ty::ImplOrTraitItem {
let cdata = tcx.sess.cstore.get_crate_data(def.krate);
decoder::get_method(tcx.sess.cstore.intr.clone(), &*cdata, def.node, tcx)
decoder::get_impl_or_trait_item(tcx.sess.cstore.intr.clone(),
&*cdata,
def.node,
tcx)
}
pub fn get_method_name_and_explicit_self(cstore: &cstore::CStore,
def: ast::DefId)
-> (ast::Ident,
ty::ExplicitSelfCategory)
{
pub fn get_trait_item_name_and_kind(cstore: &cstore::CStore, def: ast::DefId)
-> (ast::Ident, resolve::TraitItemKind) {
let cdata = cstore.get_crate_data(def.krate);
decoder::get_method_name_and_explicit_self(cstore.intr.clone(), &*cdata, def.node)
decoder::get_trait_item_name_and_kind(cstore.intr.clone(),
&*cdata,
def.node)
}
pub fn get_trait_method_def_ids(cstore: &cstore::CStore,
def: ast::DefId) -> Vec<ast::DefId> {
pub fn get_trait_item_def_ids(cstore: &cstore::CStore, def: ast::DefId)
-> Vec<ty::ImplOrTraitItemId> {
let cdata = cstore.get_crate_data(def.krate);
decoder::get_trait_method_def_ids(&*cdata, def.node)
decoder::get_trait_item_def_ids(&*cdata, def.node)
}
pub fn get_item_variances(cstore: &cstore::CStore,
@ -286,15 +290,15 @@ pub fn each_implementation_for_trait(cstore: &cstore::CStore,
decoder::each_implementation_for_trait(&*cdata, def_id.node, callback)
}
/// If the given def ID describes a method belonging to a trait (either a
/// If the given def ID describes an item belonging to a trait (either a
/// default method or an implementation of a trait method), returns the ID of
/// the trait that the method belongs to. Otherwise, returns `None`.
pub fn get_trait_of_method(cstore: &cstore::CStore,
def_id: ast::DefId,
tcx: &ty::ctxt)
-> Option<ast::DefId> {
pub fn get_trait_of_item(cstore: &cstore::CStore,
def_id: ast::DefId,
tcx: &ty::ctxt)
-> Option<ast::DefId> {
let cdata = cstore.get_crate_data(def_id.krate);
decoder::get_trait_of_method(&*cdata, def_id.node, tcx)
decoder::get_trait_of_item(&*cdata, def_id.node, tcx)
}
pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore,

View File

@ -18,11 +18,12 @@ use metadata::common::*;
use metadata::csearch::StaticMethodInfo;
use metadata::csearch;
use metadata::cstore;
use metadata::tydecode::{parse_ty_data, parse_def_id,
parse_type_param_def_data,
parse_bare_fn_ty_data, parse_trait_ref_data};
use middle::lang_items;
use metadata::tydecode::{parse_ty_data, parse_def_id};
use metadata::tydecode::{parse_type_param_def_data, parse_bare_fn_ty_data};
use metadata::tydecode::{parse_trait_ref_data};
use middle::def;
use middle::lang_items;
use middle::resolve::TraitItemKind;
use middle::subst;
use middle::ty::{ImplContainer, TraitContainer};
use middle::ty;
@ -165,9 +166,9 @@ fn item_visibility(item: rbml::Doc) -> ast::Visibility {
}
}
fn item_method_sort(item: rbml::Doc) -> char {
fn item_sort(item: rbml::Doc) -> char {
let mut ret = 'r';
reader::tagged_docs(item, tag_item_trait_method_sort, |doc| {
reader::tagged_docs(item, tag_item_trait_item_sort, |doc| {
ret = doc.as_str_slice().as_bytes()[0] as char;
false
});
@ -338,15 +339,18 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
UnsafeFn => DlDef(def::DefFn(did, ast::UnsafeFn)),
Fn => DlDef(def::DefFn(did, ast::NormalFn)),
StaticMethod | UnsafeStaticMethod => {
let fn_style = if fam == UnsafeStaticMethod { ast::UnsafeFn } else
{ ast::NormalFn };
let fn_style = if fam == UnsafeStaticMethod {
ast::UnsafeFn
} else {
ast::NormalFn
};
// def_static_method carries an optional field of its enclosing
// trait or enclosing impl (if this is an inherent static method).
// So we need to detect whether this is in a trait or not, which
// we do through the mildly hacky way of checking whether there is
// a trait_method_sort.
// a trait_parent_sort.
let provenance = if reader::maybe_get_doc(
item, tag_item_trait_method_sort).is_some() {
item, tag_item_trait_parent_sort).is_some() {
def::FromTrait(item_reqd_and_translated_parent_item(cnum,
item))
} else {
@ -536,14 +540,11 @@ fn each_child_of_item_or_crate(intr: Rc<IdentInterner>,
None => {}
Some(inherent_impl_doc) => {
let _ = reader::tagged_docs(inherent_impl_doc,
tag_item_impl_method,
|impl_method_def_id_doc| {
let impl_method_def_id =
reader::with_doc_data(impl_method_def_id_doc,
parse_def_id);
let impl_method_def_id =
translate_def_id(cdata, impl_method_def_id);
match maybe_find_item(impl_method_def_id.node, items) {
tag_item_impl_item,
|impl_item_def_id_doc| {
let impl_item_def_id = item_def_id(impl_item_def_id_doc,
cdata);
match maybe_find_item(impl_item_def_id.node, items) {
None => {}
Some(impl_method_doc) => {
match item_family(impl_method_doc) {
@ -554,7 +555,7 @@ fn each_child_of_item_or_crate(intr: Rc<IdentInterner>,
item_name(&*intr, impl_method_doc);
let static_method_def_like =
item_to_def_like(impl_method_doc,
impl_method_def_id,
impl_item_def_id,
cdata.cnum);
callback(static_method_def_like,
static_method_name,
@ -752,33 +753,46 @@ fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory {
}
}
/// Returns information about the given implementation.
pub fn get_impl_methods(cdata: Cmd, impl_id: ast::NodeId) -> Vec<ast::DefId> {
let mut methods = Vec::new();
/// Returns the def IDs of all the items in the given implementation.
pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
-> Vec<ty::ImplOrTraitItemId> {
let mut impl_items = Vec::new();
reader::tagged_docs(lookup_item(impl_id, cdata.data()),
tag_item_impl_method, |doc| {
let m_did = reader::with_doc_data(doc, parse_def_id);
methods.push(translate_def_id(cdata, m_did));
tag_item_impl_item, |doc| {
let def_id = item_def_id(doc, cdata);
match item_sort(doc) {
'r' | 'p' => impl_items.push(ty::MethodTraitItemId(def_id)),
_ => fail!("unknown impl item sort"),
}
true
});
methods
impl_items
}
pub fn get_method_name_and_explicit_self(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId)
-> (ast::Ident,
ty::ExplicitSelfCategory) {
let method_doc = lookup_item(id, cdata.data());
let name = item_name(&*intr, method_doc);
let explicit_self = get_explicit_self(method_doc);
(name, explicit_self)
pub fn get_trait_item_name_and_kind(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId)
-> (ast::Ident, TraitItemKind) {
let doc = lookup_item(id, cdata.data());
let name = item_name(&*intr, doc);
match item_sort(doc) {
'r' | 'p' => {
let explicit_self = get_explicit_self(doc);
(name, TraitItemKind::from_explicit_self_category(explicit_self))
}
c => {
fail!("get_trait_item_name_and_kind(): unknown trait item kind \
in metadata: `{}`", c)
}
}
}
pub fn get_method(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
tcx: &ty::ctxt) -> ty::Method
{
pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId,
tcx: &ty::ctxt)
-> ty::ImplOrTraitItem {
let method_doc = lookup_item(id, cdata.data());
let def_id = item_def_id(method_doc, cdata);
@ -791,36 +805,45 @@ pub fn get_method(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
};
let name = item_name(&*intr, method_doc);
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
let rp_defs = item_region_param_defs(method_doc, cdata);
let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc);
let explicit_self = get_explicit_self(method_doc);
let provided_source = get_provided_source(method_doc, cdata);
ty::Method::new(
name,
ty::Generics {
types: type_param_defs,
regions: rp_defs,
},
fty,
explicit_self,
vis,
def_id,
container,
provided_source
)
match item_sort(method_doc) {
'r' | 'p' => {
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
let rp_defs = item_region_param_defs(method_doc, cdata);
let fty = doc_method_fty(method_doc, tcx, cdata);
let vis = item_visibility(method_doc);
let explicit_self = get_explicit_self(method_doc);
let provided_source = get_provided_source(method_doc, cdata);
let generics = ty::Generics {
types: type_param_defs,
regions: rp_defs,
};
ty::MethodTraitItem(Rc::new(ty::Method::new(name,
generics,
fty,
explicit_self,
vis,
def_id,
container,
provided_source)))
}
_ => fail!("unknown impl/trait item sort"),
}
}
pub fn get_trait_method_def_ids(cdata: Cmd,
id: ast::NodeId) -> Vec<ast::DefId> {
pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
-> Vec<ty::ImplOrTraitItemId> {
let data = cdata.data();
let item = lookup_item(id, data);
let mut result = Vec::new();
reader::tagged_docs(item, tag_item_trait_method, |mth| {
result.push(item_def_id(mth, cdata));
reader::tagged_docs(item, tag_item_trait_item, |mth| {
let def_id = item_def_id(mth, cdata);
match item_sort(mth) {
'r' | 'p' => result.push(ty::MethodTraitItemId(def_id)),
_ => fail!("unknown trait item sort"),
}
true
});
result
@ -834,19 +857,29 @@ pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
Decodable::decode(&mut decoder).unwrap()
}
pub fn get_provided_trait_methods(intr: Rc<IdentInterner>, cdata: Cmd,
id: ast::NodeId, tcx: &ty::ctxt)
pub fn get_provided_trait_methods(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId,
tcx: &ty::ctxt)
-> Vec<Rc<ty::Method>> {
let data = cdata.data();
let item = lookup_item(id, data);
let mut result = Vec::new();
reader::tagged_docs(item, tag_item_trait_method, |mth_id| {
reader::tagged_docs(item, tag_item_trait_item, |mth_id| {
let did = item_def_id(mth_id, cdata);
let mth = lookup_item(did.node, data);
if item_method_sort(mth) == 'p' {
result.push(Rc::new(get_method(intr.clone(), cdata, did.node, tcx)));
if item_sort(mth) == 'p' {
let trait_item = get_impl_or_trait_item(intr.clone(),
cdata,
did.node,
tcx);
match trait_item {
ty::MethodTraitItem(ref method) => {
result.push((*method).clone())
}
}
}
true
});
@ -905,8 +938,8 @@ pub fn get_static_methods_if_impl(intr: Rc<IdentInterner>,
if !ret { return None }
let mut impl_method_ids = Vec::new();
reader::tagged_docs(item, tag_item_impl_method, |impl_method_doc| {
impl_method_ids.push(reader::with_doc_data(impl_method_doc, parse_def_id));
reader::tagged_docs(item, tag_item_impl_item, |impl_method_doc| {
impl_method_ids.push(item_def_id(impl_method_doc, cdata));
true
});
@ -1230,8 +1263,8 @@ pub fn each_implementation_for_trait(cdata: Cmd,
});
}
pub fn get_trait_of_method(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
-> Option<ast::DefId> {
pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
-> Option<ast::DefId> {
let item_doc = lookup_item(id, cdata.data());
let parent_item_id = match item_parent_item(item_doc) {
None => return None,

View File

@ -54,13 +54,19 @@ use syntax;
use rbml::writer;
use rbml::io::SeekableMemWriter;
/// A borrowed version of ast::InlinedItem.
/// A borrowed version of `ast::InlinedItem`.
pub enum InlinedItemRef<'a> {
IIItemRef(&'a ast::Item),
IIMethodRef(ast::DefId, bool, &'a ast::Method),
IITraitItemRef(ast::DefId, InlinedTraitItemRef<'a>),
IIForeignRef(&'a ast::ForeignItem)
}
/// A borrowed version of `ast::InlinedTraitItem`.
pub enum InlinedTraitItemRef<'a> {
ProvidedInlinedTraitItemRef(&'a Method),
RequiredInlinedTraitItemRef(&'a Method),
}
pub type Encoder<'a> = writer::Encoder<'a, SeekableMemWriter>;
pub type EncodeInlinedItem<'a> = |ecx: &EncodeContext,
@ -403,14 +409,24 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
rbml_w: &mut Encoder,
exp: &middle::resolve::Export2)
-> bool {
let impl_methods = ecx.tcx.impl_methods.borrow();
let impl_items = ecx.tcx.impl_items.borrow();
match ecx.tcx.inherent_impls.borrow().find(&exp.def_id) {
Some(implementations) => {
for base_impl_did in implementations.borrow().iter() {
for &method_did in impl_methods.get(base_impl_did).iter() {
let m = ty::method(ecx.tcx, method_did);
if m.explicit_self == ty::StaticExplicitSelfCategory {
encode_reexported_static_method(rbml_w, exp, m.def_id, m.ident);
for &method_did in impl_items.get(base_impl_did).iter() {
let impl_item = ty::impl_or_trait_item(
ecx.tcx,
method_did.def_id());
match impl_item {
ty::MethodTraitItem(ref m) => {
if m.explicit_self ==
ty::StaticExplicitSelfCategory {
encode_reexported_static_method(rbml_w,
exp,
m.def_id,
m.ident);
}
}
}
}
}
@ -425,11 +441,18 @@ fn encode_reexported_static_trait_methods(ecx: &EncodeContext,
rbml_w: &mut Encoder,
exp: &middle::resolve::Export2)
-> bool {
match ecx.tcx.trait_methods_cache.borrow().find(&exp.def_id) {
Some(methods) => {
for m in methods.iter() {
if m.explicit_self == ty::StaticExplicitSelfCategory {
encode_reexported_static_method(rbml_w, exp, m.def_id, m.ident);
match ecx.tcx.trait_items_cache.borrow().find(&exp.def_id) {
Some(trait_items) => {
for trait_item in trait_items.iter() {
match *trait_item {
ty::MethodTraitItem(ref m) if m.explicit_self ==
ty::StaticExplicitSelfCategory => {
encode_reexported_static_method(rbml_w,
exp,
m.def_id,
m.ident);
}
_ => {}
}
}
@ -675,8 +698,14 @@ fn encode_explicit_self(rbml_w: &mut Encoder,
}
}
fn encode_method_sort(rbml_w: &mut Encoder, sort: char) {
rbml_w.start_tag(tag_item_trait_method_sort);
fn encode_item_sort(rbml_w: &mut Encoder, sort: char) {
rbml_w.start_tag(tag_item_trait_item_sort);
rbml_w.writer.write(&[ sort as u8 ]);
rbml_w.end_tag();
}
fn encode_parent_sort(rbml_w: &mut Encoder, sort: char) {
rbml_w.start_tag(tag_item_trait_parent_sort);
rbml_w.writer.write(&[ sort as u8 ]);
rbml_w.end_tag();
}
@ -799,6 +828,7 @@ fn encode_info_for_method(ecx: &EncodeContext,
encode_method_ty_fields(ecx, rbml_w, m);
encode_parent_item(rbml_w, local_def(parent_id));
encode_item_sort(rbml_w, 'r');
let stab = stability::lookup(ecx.tcx, m.def_id);
encode_stability(rbml_w, stab);
@ -819,9 +849,11 @@ fn encode_info_for_method(ecx: &EncodeContext,
for &ast_method in ast_method_opt.iter() {
let any_types = !pty.generics.types.is_empty();
if any_types || is_default_impl || should_inline(ast_method.attrs.as_slice()) {
encode_inlined_item(ecx, rbml_w,
IIMethodRef(local_def(parent_id), false,
&*ast_method));
encode_inlined_item(ecx,
rbml_w,
IITraitItemRef(local_def(parent_id),
RequiredInlinedTraitItemRef(
&*ast_method)));
} else {
encode_symbol(ecx, rbml_w, m.def_id.node);
}
@ -1106,11 +1138,11 @@ fn encode_info_for_item(ecx: &EncodeContext,
None => {}
}
}
ItemImpl(_, ref opt_trait, ty, ref ast_methods) => {
ItemImpl(_, ref opt_trait, ty, ref ast_items) => {
// We need to encode information about the default methods we
// have inherited, so we drive this based on the impl structure.
let impl_methods = tcx.impl_methods.borrow();
let methods = impl_methods.get(&def_id);
let impl_items = tcx.impl_items.borrow();
let items = impl_items.get(&def_id);
add_to_index(item, rbml_w, index);
rbml_w.start_tag(tag_items_data_item);
@ -1128,10 +1160,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
}
_ => {}
}
for &method_def_id in methods.iter() {
rbml_w.start_tag(tag_item_impl_method);
let s = def_to_string(method_def_id);
rbml_w.writer.write(s.as_bytes());
for &item_def_id in items.iter() {
rbml_w.start_tag(tag_item_impl_item);
match item_def_id {
ty::MethodTraitItemId(item_def_id) => {
encode_def_id(rbml_w, item_def_id);
encode_item_sort(rbml_w, 'r');
}
}
rbml_w.end_tag();
}
for ast_trait_ref in opt_trait.iter() {
@ -1145,27 +1181,46 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_stability(rbml_w, stab);
rbml_w.end_tag();
// Iterate down the methods, emitting them. We rely on the
// assumption that all of the actually implemented methods
// Iterate down the trait items, emitting them. We rely on the
// assumption that all of the actually implemented trait items
// appear first in the impl structure, in the same order they do
// in the ast. This is a little sketchy.
let num_implemented_methods = ast_methods.len();
for (i, &method_def_id) in methods.iter().enumerate() {
let ast_method = if i < num_implemented_methods {
Some(*ast_methods.get(i))
} else { None };
let num_implemented_methods = ast_items.len();
for (i, &trait_item_def_id) in items.iter().enumerate() {
let ast_item = if i < num_implemented_methods {
Some(*ast_items.get(i))
} else {
None
};
index.push(entry {
val: method_def_id.node as i64,
val: trait_item_def_id.def_id().node as i64,
pos: rbml_w.writer.tell().unwrap(),
});
encode_info_for_method(ecx,
rbml_w,
&*ty::method(tcx, method_def_id),
path.clone(),
false,
item.id,
ast_method)
let trait_item_type =
ty::impl_or_trait_item(tcx, trait_item_def_id.def_id());
match (trait_item_type, ast_item) {
(ty::MethodTraitItem(method_type),
Some(ast::MethodImplItem(ast_method))) => {
encode_info_for_method(ecx,
rbml_w,
&*method_type,
path.clone(),
false,
item.id,
Some(ast_method))
}
(ty::MethodTraitItem(method_type), None) => {
encode_info_for_method(ecx,
rbml_w,
&*method_type,
path.clone(),
false,
item.id,
None)
}
}
}
}
ItemTrait(_, _, ref super_traits, ref ms) => {
@ -1184,13 +1239,18 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_attributes(rbml_w, item.attrs.as_slice());
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() {
rbml_w.start_tag(tag_item_trait_method);
encode_def_id(rbml_w, method_def_id);
for &method_def_id in ty::trait_item_def_ids(tcx, def_id).iter() {
rbml_w.start_tag(tag_item_trait_item);
match method_def_id {
ty::MethodTraitItemId(method_def_id) => {
encode_def_id(rbml_w, method_def_id);
encode_item_sort(rbml_w, 'r');
}
}
rbml_w.end_tag();
rbml_w.start_tag(tag_mod_child);
rbml_w.wr_str(def_to_string(method_def_id).as_slice());
rbml_w.wr_str(def_to_string(method_def_id.def_id()).as_slice());
rbml_w.end_tag();
}
encode_path(rbml_w, path.clone());
@ -1207,66 +1267,83 @@ fn encode_info_for_item(ecx: &EncodeContext,
rbml_w.end_tag();
// Now output the method info for each method.
let r = ty::trait_method_def_ids(tcx, def_id);
for (i, &method_def_id) in r.iter().enumerate() {
assert_eq!(method_def_id.krate, ast::LOCAL_CRATE);
let method_ty = ty::method(tcx, method_def_id);
// Now output the trait item info for each trait item.
let r = ty::trait_item_def_ids(tcx, def_id);
for (i, &item_def_id) in r.iter().enumerate() {
assert_eq!(item_def_id.def_id().krate, ast::LOCAL_CRATE);
index.push(entry {
val: method_def_id.node as i64,
val: item_def_id.def_id().node as i64,
pos: rbml_w.writer.tell().unwrap(),
});
rbml_w.start_tag(tag_items_data_item);
encode_method_ty_fields(ecx, rbml_w, &*method_ty);
encode_parent_item(rbml_w, def_id);
let trait_item_type =
ty::impl_or_trait_item(tcx, item_def_id.def_id());
match trait_item_type {
ty::MethodTraitItem(method_ty) => {
let method_def_id = item_def_id.def_id();
let stab = stability::lookup(tcx, method_def_id);
encode_stability(rbml_w, stab);
encode_method_ty_fields(ecx, rbml_w, &*method_ty);
encode_parent_item(rbml_w, def_id);
let elem = ast_map::PathName(method_ty.ident.name);
encode_path(rbml_w, path.clone().chain(Some(elem).move_iter()));
let stab = stability::lookup(tcx, method_def_id);
encode_stability(rbml_w, stab);
match method_ty.explicit_self {
ty::StaticExplicitSelfCategory => {
encode_family(rbml_w,
fn_style_static_method_family(
method_ty.fty.fn_style));
let elem = ast_map::PathName(method_ty.ident.name);
encode_path(rbml_w,
path.clone().chain(Some(elem).move_iter()));
let pty = ty::lookup_item_type(tcx, method_def_id);
encode_bounds_and_type(rbml_w, ecx, &pty);
}
match method_ty.explicit_self {
ty::StaticExplicitSelfCategory => {
encode_family(rbml_w,
fn_style_static_method_family(
method_ty.fty.fn_style));
_ => {
encode_family(rbml_w,
style_fn_family(
method_ty.fty.fn_style));
}
}
let pty = ty::lookup_item_type(tcx,
method_def_id);
encode_bounds_and_type(rbml_w, ecx, &pty);
}
match ms.get(i) {
&Required(ref tm) => {
encode_attributes(rbml_w, tm.attrs.as_slice());
encode_method_sort(rbml_w, 'r');
encode_method_argument_names(rbml_w, &*tm.decl);
}
&Provided(m) => {
encode_attributes(rbml_w, m.attrs.as_slice());
// If this is a static method, we've already encoded
// this.
if method_ty.explicit_self != ty::StaticExplicitSelfCategory {
// FIXME: I feel like there is something funny going on.
let pty = ty::lookup_item_type(tcx, method_def_id);
encode_bounds_and_type(rbml_w, ecx, &pty);
_ => {
encode_family(rbml_w,
style_fn_family(
method_ty.fty.fn_style));
}
}
match ms.get(i) {
&RequiredMethod(ref tm) => {
encode_attributes(rbml_w, tm.attrs.as_slice());
encode_item_sort(rbml_w, 'r');
encode_parent_sort(rbml_w, 't');
encode_method_argument_names(rbml_w, &*tm.decl);
}
&ProvidedMethod(m) => {
encode_attributes(rbml_w, m.attrs.as_slice());
// If this is a static method, we've already
// encoded this.
if method_ty.explicit_self !=
ty::StaticExplicitSelfCategory {
// FIXME: I feel like there is something funny
// going on.
let pty = ty::lookup_item_type(tcx, method_def_id);
encode_bounds_and_type(rbml_w, ecx, &pty);
}
encode_item_sort(rbml_w, 'p');
encode_parent_sort(rbml_w, 't');
encode_inlined_item(
ecx,
rbml_w,
IITraitItemRef(
def_id,
ProvidedInlinedTraitItemRef(&*m)));
encode_method_argument_names(rbml_w,
&*m.pe_fn_decl());
}
}
encode_method_sort(rbml_w, 'p');
encode_inlined_item(ecx, rbml_w,
IIMethodRef(def_id, true, &*m));
encode_method_argument_names(rbml_w, &*m.pe_fn_decl());
}
}

View File

@ -84,7 +84,8 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
let id = match ii {
e::IIItemRef(i) => i.id,
e::IIForeignRef(i) => i.id,
e::IIMethodRef(_, _, m) => m.id,
e::IITraitItemRef(_, e::ProvidedInlinedTraitItemRef(m)) => m.id,
e::IITraitItemRef(_, e::RequiredInlinedTraitItemRef(m)) => m.id,
};
debug!("> Encoding inlined item: {} ({})",
ecx.tcx.map.path_to_string(id),
@ -137,7 +138,12 @@ pub fn decode_inlined_item(cdata: &cstore::crate_metadata,
let ident = match ii {
ast::IIItem(i) => i.ident,
ast::IIForeign(i) => i.ident,
ast::IIMethod(_, _, m) => m.pe_ident(),
ast::IITraitItem(_, iti) => {
match iti {
ast::ProvidedInlinedTraitItem(m) => m.pe_ident(),
ast::RequiredInlinedTraitItem(m) => m.pe_ident(),
}
}
};
debug!("Fn named: {}", token::get_ident(ident));
debug!("< Decoded inlined fn: {}::{}",
@ -344,12 +350,29 @@ fn simplify_ast(ii: e::InlinedItemRef) -> ast::InlinedItem {
match ii {
// HACK we're not dropping items.
e::IIItemRef(i) => ast::IIItem(fold::noop_fold_item(i, &mut fld)
.expect_one("expected one item")),
e::IIMethodRef(d, p, m) => ast::IIMethod(d, p, fold::noop_fold_method(m, &mut fld)
.expect_one(
"noop_fold_method must produce exactly one method")),
e::IIForeignRef(i) => ast::IIForeign(fold::noop_fold_foreign_item(i, &mut fld))
e::IIItemRef(i) => {
ast::IIItem(fold::noop_fold_item(i, &mut fld)
.expect_one("expected one item"))
}
e::IITraitItemRef(d, iti) => {
ast::IITraitItem(d, match iti {
e::ProvidedInlinedTraitItemRef(m) => {
ast::ProvidedInlinedTraitItem(
fold::noop_fold_method(m, &mut fld)
.expect_one("noop_fold_method must produce \
exactly one method"))
}
e::RequiredInlinedTraitItemRef(m) => {
ast::RequiredInlinedTraitItem(
fold::noop_fold_method(m, &mut fld)
.expect_one("noop_fold_method must produce \
exactly one method"))
}
})
}
e::IIForeignRef(i) => {
ast::IIForeign(fold::noop_fold_foreign_item(i, &mut fld))
}
}
}
@ -389,9 +412,23 @@ fn renumber_and_map_ast(xcx: &ExtendedDecodeContext,
ast::IIItem(i) => {
ast::IIItem(fld.fold_item(i).expect_one("expected one item"))
}
ast::IIMethod(d, is_provided, m) => {
ast::IIMethod(xcx.tr_def_id(d), is_provided, fld.fold_method(m)
.expect_one("expected one method"))
ast::IITraitItem(d, iti) => {
match iti {
ast::ProvidedInlinedTraitItem(m) => {
ast::IITraitItem(
xcx.tr_def_id(d),
ast::ProvidedInlinedTraitItem(
fld.fold_method(m)
.expect_one("expected one method")))
}
ast::RequiredInlinedTraitItem(m) => {
ast::IITraitItem(
xcx.tr_def_id(d),
ast::RequiredInlinedTraitItem(
fld.fold_method(m)
.expect_one("expected one method")))
}
}
}
ast::IIForeign(i) => ast::IIForeign(fld.fold_foreign_item(i))
}

View File

@ -40,9 +40,9 @@ fn should_explore(tcx: &ty::ctxt, def_id: ast::DefId) -> bool {
match tcx.map.find(def_id.node) {
Some(ast_map::NodeItem(..))
| Some(ast_map::NodeMethod(..))
| Some(ast_map::NodeImplItem(..))
| Some(ast_map::NodeForeignItem(..))
| Some(ast_map::NodeTraitMethod(..)) => true,
| Some(ast_map::NodeTraitItem(..)) => true,
_ => false
}
}
@ -114,9 +114,14 @@ impl<'a> MarkSymbolVisitor<'a> {
method_num: index,
..
}) => {
let def_id = ty::trait_method(self.tcx,
trait_id, index).def_id;
self.check_def_id(def_id);
let trait_item = ty::trait_item(self.tcx,
trait_id,
index);
match trait_item {
ty::MethodTraitItem(method) => {
self.check_def_id(method.def_id);
}
}
}
}
}
@ -208,11 +213,15 @@ impl<'a> MarkSymbolVisitor<'a> {
_ => ()
}
}
ast_map::NodeTraitMethod(trait_method) => {
visit::walk_trait_method(self, &*trait_method, ctxt);
ast_map::NodeTraitItem(trait_method) => {
visit::walk_trait_item(self, &*trait_method, ctxt);
}
ast_map::NodeMethod(method) => {
visit::walk_block(self, &*method.pe_body(), ctxt);
ast_map::NodeImplItem(impl_item) => {
match *impl_item {
ast::MethodImplItem(method) => {
visit::walk_block(self, &*method.pe_body(), ctxt);
}
}
}
ast_map::NodeForeignItem(foreign_item) => {
visit::walk_foreign_item(self, &*foreign_item, ctxt);
@ -316,9 +325,13 @@ impl Visitor<()> for LifeSeeder {
self.worklist.push(item.id);
}
match item.node {
ast::ItemImpl(_, Some(ref _trait_ref), _, ref methods) => {
for method in methods.iter() {
self.worklist.push(method.id);
ast::ItemImpl(_, Some(ref _trait_ref), _, ref impl_items) => {
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(method) => {
self.worklist.push(method.id);
}
}
}
}
_ => ()
@ -443,13 +456,14 @@ impl<'a> DeadVisitor<'a> {
// This is done to handle the case where, for example, the static
// method of a private type is used, but the type itself is never
// called directly.
let impl_methods = self.tcx.impl_methods.borrow();
let impl_items = self.tcx.impl_items.borrow();
match self.tcx.inherent_impls.borrow().find(&local_def(id)) {
None => (),
Some(impl_list) => {
for impl_did in impl_list.borrow().iter() {
for method_did in impl_methods.get(impl_did).iter() {
if self.live_symbols.contains(&method_did.node) {
for item_did in impl_items.get(impl_did).iter() {
if self.live_symbols.contains(&item_did.def_id()
.node) {
return true;
}
}
@ -516,12 +530,12 @@ impl<'a> Visitor<()> for DeadVisitor<'a> {
}
// Overwrite so that we don't warn the trait method itself.
fn visit_trait_method(&mut self, trait_method: &ast::TraitMethod, _: ()) {
fn visit_trait_item(&mut self, trait_method: &ast::TraitItem, _: ()) {
match *trait_method {
ast::Provided(ref method) => {
ast::ProvidedMethod(ref method) => {
visit::walk_block(self, &*method.pe_body(), ())
}
ast::Required(_) => ()
ast::RequiredMethod(_) => ()
}
}
}

View File

@ -131,12 +131,14 @@ impl OverloadedCallType {
fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
-> OverloadedCallType {
let method_descriptor =
match tcx.methods.borrow_mut().find(&method_id) {
match tcx.impl_or_trait_items.borrow_mut().find(&method_id) {
Some(&ty::MethodTraitItem(ref method_descriptor)) => {
(*method_descriptor).clone()
}
None => {
tcx.sess.bug("overloaded call method wasn't in method \
map")
}
Some(ref method_descriptor) => (*method_descriptor).clone(),
};
let impl_id = match method_descriptor.container {
ty::TraitContainer(_) => {

View File

@ -83,8 +83,8 @@ impl Visitor<()> for ParentVisitor {
ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => {
for m in methods.iter() {
match *m {
ast::Provided(ref m) => self.parents.insert(m.id, item.id),
ast::Required(ref m) => self.parents.insert(m.id, item.id),
ast::ProvidedMethod(ref m) => self.parents.insert(m.id, item.id),
ast::RequiredMethod(ref m) => self.parents.insert(m.id, item.id),
};
}
}
@ -240,7 +240,7 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {
// undefined symbols at linkage time if this case is not handled.
//
// * Private trait impls for private types can be completely ignored
ast::ItemImpl(_, _, ref ty, ref methods) => {
ast::ItemImpl(_, _, ref ty, ref impl_items) => {
let public_ty = match ty.node {
ast::TyPath(_, _, id) => {
match self.tcx.def_map.borrow().get_copy(&id) {
@ -261,13 +261,18 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {
});
if public_ty || public_trait {
for method in methods.iter() {
let meth_public = match method.pe_explicit_self().node {
ast::SelfStatic => public_ty,
_ => true,
} && method.pe_vis() == ast::Public;
if meth_public || tr.is_some() {
self.exported_items.insert(method.id);
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(method) => {
let meth_public =
match method.pe_explicit_self().node {
ast::SelfStatic => public_ty,
_ => true,
} && method.pe_vis() == ast::Public;
if meth_public || tr.is_some() {
self.exported_items.insert(method.id);
}
}
}
}
}
@ -278,11 +283,11 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {
ast::ItemTrait(_, _, _, ref methods) if public_first => {
for method in methods.iter() {
match *method {
ast::Provided(ref m) => {
ast::ProvidedMethod(ref m) => {
debug!("provided {}", m.id);
self.exported_items.insert(m.id);
}
ast::Required(ref m) => {
ast::RequiredMethod(ref m) => {
debug!("required {}", m.id);
self.exported_items.insert(m.id);
}
@ -387,9 +392,10 @@ impl<'a> PrivacyVisitor<'a> {
}
debug!("privacy - is {:?} a public method", did);
return match self.tcx.methods.borrow().find(&did) {
Some(meth) => {
debug!("privacy - well at least it's a method: {:?}", meth);
return match self.tcx.impl_or_trait_items.borrow().find(&did) {
Some(&ty::MethodTraitItem(ref meth)) => {
debug!("privacy - well at least it's a method: {:?}",
*meth);
match meth.container {
ty::TraitContainer(id) => {
debug!("privacy - recursing on trait {:?}", id);
@ -451,15 +457,23 @@ impl<'a> PrivacyVisitor<'a> {
// invocation.
// FIXME(#10573) is this the right behavior? Why not consider
// where the method was defined?
Some(ast_map::NodeMethod(ref m)) => {
let imp = self.tcx.map.get_parent_did(closest_private_id);
match ty::impl_trait_ref(self.tcx, imp) {
Some(..) => return Allowable,
_ if m.pe_vis() == ast::Public => return Allowable,
_ => m.pe_vis()
Some(ast_map::NodeImplItem(ref ii)) => {
match **ii {
ast::MethodImplItem(m) => {
let imp = self.tcx
.map
.get_parent_did(closest_private_id);
match ty::impl_trait_ref(self.tcx, imp) {
Some(..) => return Allowable,
_ if m.pe_vis() == ast::Public => {
return Allowable
}
_ => m.pe_vis()
}
}
}
}
Some(ast_map::NodeTraitMethod(_)) => {
Some(ast_map::NodeTraitItem(_)) => {
return Allowable;
}
@ -648,12 +662,17 @@ impl<'a> PrivacyVisitor<'a> {
}
// Given the ID of a method, checks to ensure it's in scope.
fn check_static_method(&mut self, span: Span, method_id: ast::DefId,
fn check_static_method(&mut self,
span: Span,
method_id: ast::DefId,
name: ast::Ident) {
// If the method is a default method, we need to use the def_id of
// the default implementation.
let method_id = ty::method(self.tcx, method_id).provided_source
.unwrap_or(method_id);
let method_id = match ty::impl_or_trait_item(self.tcx, method_id) {
ty::MethodTraitItem(method_type) => {
method_type.provided_source.unwrap_or(method_id)
}
};
let string = token::get_ident(name);
self.report_error(self.ensure_public(span,
@ -1075,12 +1094,16 @@ impl<'a> SanePrivacyVisitor<'a> {
match item.node {
// implementations of traits don't need visibility qualifiers because
// that's controlled by having the trait in scope.
ast::ItemImpl(_, Some(..), _, ref methods) => {
ast::ItemImpl(_, Some(..), _, ref impl_items) => {
check_inherited(item.span, item.vis,
"visibility qualifiers have no effect on trait \
impls");
for m in methods.iter() {
check_inherited(m.span, m.pe_vis(), "");
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(m) => {
check_inherited(m.span, m.pe_vis(), "");
}
}
}
}
@ -1111,11 +1134,11 @@ impl<'a> SanePrivacyVisitor<'a> {
ast::ItemTrait(_, _, _, ref methods) => {
for m in methods.iter() {
match *m {
ast::Provided(ref m) => {
ast::ProvidedMethod(ref m) => {
check_inherited(m.span, m.pe_vis(),
"unnecessary visibility");
}
ast::Required(ref m) => {
ast::RequiredMethod(ref m) => {
check_inherited(m.span, m.vis,
"unnecessary visibility");
}
@ -1148,9 +1171,13 @@ impl<'a> SanePrivacyVisitor<'a> {
};
check_inherited(tcx, item.span, item.vis);
match item.node {
ast::ItemImpl(_, _, _, ref methods) => {
for m in methods.iter() {
check_inherited(tcx, m.span, m.pe_vis());
ast::ItemImpl(_, _, _, ref impl_items) => {
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(m) => {
check_inherited(tcx, m.span, m.pe_vis());
}
}
}
}
ast::ItemForeignMod(ref fm) => {
@ -1174,8 +1201,8 @@ impl<'a> SanePrivacyVisitor<'a> {
ast::ItemTrait(_, _, _, ref methods) => {
for m in methods.iter() {
match *m {
ast::Required(..) => {}
ast::Provided(ref m) => check_inherited(tcx, m.span,
ast::RequiredMethod(..) => {}
ast::ProvidedMethod(ref m) => check_inherited(tcx, m.span,
m.pe_vis()),
}
}
@ -1270,7 +1297,7 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> {
// (i.e. we could just return here to not check them at
// all, or some worse estimation of whether an impl is
// publicly visible.
ast::ItemImpl(ref g, ref trait_ref, self_, ref methods) => {
ast::ItemImpl(ref g, ref trait_ref, self_, ref impl_items) => {
// `impl [... for] Private` is never visible.
let self_contains_private;
// impl [... for] Public<...>, but not `impl [... for]
@ -1311,7 +1338,14 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> {
// are private (because `T` won't be visible externally).
let trait_or_some_public_method =
trait_ref.is_some() ||
methods.iter().any(|m| self.exported_items.contains(&m.id));
impl_items.iter()
.any(|impl_item| {
match *impl_item {
ast::MethodImplItem(m) => {
self.exported_items.contains(&m.id)
}
}
});
if !self_contains_private &&
not_private_trait &&
@ -1321,8 +1355,14 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> {
match *trait_ref {
None => {
for method in methods.iter() {
visit::walk_method_helper(self, &**method, ())
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(method) => {
visit::walk_method_helper(self,
&*method,
())
}
}
}
}
Some(ref tr) => {
@ -1345,11 +1385,19 @@ impl<'a> Visitor<()> for VisiblePrivateTypesVisitor<'a> {
// impl Public<Private> { ... }. Any public static
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for method in methods.iter() {
if method.pe_explicit_self().node == ast::SelfStatic &&
self.exported_items.contains(&method.id) {
found_pub_static = true;
visit::walk_method_helper(self, &**method, ());
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(method) => {
if method.pe_explicit_self().node ==
ast::SelfStatic &&
self.exported_items
.contains(&method.id) {
found_pub_static = true;
visit::walk_method_helper(self,
&*method,
());
}
}
}
}
if found_pub_static {

View File

@ -193,26 +193,37 @@ impl<'a> ReachableContext<'a> {
_ => false,
}
}
Some(ast_map::NodeTraitMethod(trait_method)) => {
Some(ast_map::NodeTraitItem(trait_method)) => {
match *trait_method {
ast::Required(_) => false,
ast::Provided(_) => true,
ast::RequiredMethod(_) => false,
ast::ProvidedMethod(_) => true,
}
}
Some(ast_map::NodeMethod(method)) => {
if generics_require_inlining(method.pe_generics()) ||
attributes_specify_inlining(method.attrs.as_slice()) {
true
} else {
let impl_did = self.tcx.map.get_parent_did(node_id);
// Check the impl. If the generics on the self type of the
// impl require inlining, this method does too.
assert!(impl_did.krate == ast::LOCAL_CRATE);
match self.tcx.map.expect_item(impl_did.node).node {
ast::ItemImpl(ref generics, _, _, _) => {
generics_require_inlining(generics)
Some(ast_map::NodeImplItem(impl_item)) => {
match *impl_item {
ast::MethodImplItem(method) => {
if generics_require_inlining(method.pe_generics()) ||
attributes_specify_inlining(
method.attrs.as_slice()) {
true
} else {
let impl_did = self.tcx
.map
.get_parent_did(node_id);
// Check the impl. If the generics on the self
// type of the impl require inlining, this method
// does too.
assert!(impl_did.krate == ast::LOCAL_CRATE);
match self.tcx
.map
.expect_item(impl_did.node)
.node {
ast::ItemImpl(ref generics, _, _, _) => {
generics_require_inlining(generics)
}
_ => false
}
}
_ => false
}
}
}
@ -310,20 +321,24 @@ impl<'a> ReachableContext<'a> {
}
}
}
ast_map::NodeTraitMethod(trait_method) => {
ast_map::NodeTraitItem(trait_method) => {
match *trait_method {
ast::Required(..) => {
ast::RequiredMethod(..) => {
// Keep going, nothing to get exported
}
ast::Provided(ref method) => {
ast::ProvidedMethod(ref method) => {
visit::walk_block(self, &*method.pe_body(), ())
}
}
}
ast_map::NodeMethod(method) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, &*method, did) {
visit::walk_block(self, &*method.pe_body(), ())
ast_map::NodeImplItem(impl_item) => {
match *impl_item {
ast::MethodImplItem(method) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, &*method, did) {
visit::walk_block(self, &*method.pe_body(), ())
}
}
}
}
// Nothing to recurse on for these

View File

@ -24,7 +24,7 @@ use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
use syntax::ast::*;
use syntax::ast;
use syntax::ast_util::{local_def, PostExpansionMethod};
use syntax::ast_util::{walk_pat, trait_method_to_ty_method};
use syntax::ast_util::{walk_pat, trait_item_to_ty_method};
use syntax::ext::mtwt;
use syntax::parse::token::special_names;
use syntax::parse::token::special_idents;
@ -36,7 +36,7 @@ use syntax::visit::Visitor;
use std::collections::{HashMap, HashSet};
use std::cell::{Cell, RefCell};
use std::gc::{Gc, GC};
use std::gc::GC;
use std::mem::replace;
use std::rc::{Rc, Weak};
use std::uint;
@ -225,7 +225,7 @@ enum FallbackSuggestion {
NoSuggestion,
Field,
Method,
TraitMethod,
TraitItem,
StaticMethod(String),
StaticTraitMethod(String),
}
@ -272,10 +272,10 @@ enum RibKind {
ConstantItemRibKind
}
// Methods can be required or provided. Required methods only occur in traits.
// Methods can be required or provided. RequiredMethod methods only occur in traits.
enum MethodSort {
Required,
Provided(NodeId)
RequiredMethod,
ProvidedMethod(NodeId)
}
enum UseLexicalScopeFlag {
@ -289,19 +289,19 @@ enum ModulePrefixResult {
}
#[deriving(Clone, Eq, PartialEq)]
enum MethodIsStaticFlag {
MethodIsNotStatic,
MethodIsStatic,
pub enum TraitItemKind {
NonstaticMethodTraitItemKind,
StaticMethodTraitItemKind,
}
impl MethodIsStaticFlag {
fn from_explicit_self_category(explicit_self_category:
ExplicitSelfCategory)
-> MethodIsStaticFlag {
impl TraitItemKind {
pub fn from_explicit_self_category(explicit_self_category:
ExplicitSelfCategory)
-> TraitItemKind {
if explicit_self_category == StaticExplicitSelfCategory {
MethodIsStatic
StaticMethodTraitItemKind
} else {
MethodIsNotStatic
NonstaticMethodTraitItemKind
}
}
}
@ -824,7 +824,7 @@ struct Resolver<'a> {
graph_root: NameBindings,
method_map: RefCell<FnvHashMap<(Name, DefId), MethodIsStaticFlag>>,
trait_item_map: RefCell<FnvHashMap<(Name, DefId), TraitItemKind>>,
structs: FnvHashMap<DefId, Vec<Name>>,
@ -934,7 +934,7 @@ impl<'a> Resolver<'a> {
graph_root: graph_root,
method_map: RefCell::new(FnvHashMap::new()),
trait_item_map: RefCell::new(FnvHashMap::new()),
structs: FnvHashMap::new(),
unresolved_imports: 0,
@ -1263,7 +1263,7 @@ impl<'a> Resolver<'a> {
parent
}
ItemImpl(_, None, ty, ref methods) => {
ItemImpl(_, None, ty, ref impl_items) => {
// If this implements an anonymous trait, then add all the
// methods within to a new module, if the type was defined
// within this module.
@ -1315,35 +1315,43 @@ impl<'a> Resolver<'a> {
}
};
// For each method...
for method in methods.iter() {
// Add the method to the module.
let ident = method.pe_ident();
let method_name_bindings =
self.add_child(ident,
new_parent.clone(),
ForbidDuplicateValues,
method.span);
let def = match method.pe_explicit_self().node {
SelfStatic => {
// Static methods become
// `def_static_method`s.
DefStaticMethod(local_def(method.id),
FromImpl(local_def(
item.id)),
method.pe_fn_style())
}
_ => {
// Non-static methods become
// `def_method`s.
DefMethod(local_def(method.id), None)
}
};
// For each implementation item...
for impl_item in impl_items.iter() {
match *impl_item {
MethodImplItem(method) => {
// Add the method to the module.
let ident = method.pe_ident();
let method_name_bindings =
self.add_child(ident,
new_parent.clone(),
ForbidDuplicateValues,
method.span);
let def = match method.pe_explicit_self()
.node {
SelfStatic => {
// Static methods become
// `def_static_method`s.
DefStaticMethod(
local_def(method.id),
FromImpl(local_def(item.id)),
method.pe_fn_style())
}
_ => {
// Non-static methods become
// `def_method`s.
DefMethod(local_def(method.id),
None)
}
};
let is_public = method.pe_vis() == ast::Public;
method_name_bindings.define_value(def,
method.span,
is_public);
let is_public =
method.pe_vis() == ast::Public;
method_name_bindings.define_value(
def,
method.span,
is_public);
}
}
}
}
_ => {}
@ -1376,7 +1384,7 @@ impl<'a> Resolver<'a> {
// Add the names of all the methods to the trait info.
for method in methods.iter() {
let ty_m = trait_method_to_ty_method(method);
let ty_m = trait_item_to_ty_method(method);
let ident = ty_m.ident;
@ -1387,13 +1395,13 @@ impl<'a> Resolver<'a> {
(DefStaticMethod(local_def(ty_m.id),
FromTrait(local_def(item.id)),
ty_m.fn_style),
MethodIsStatic)
StaticMethodTraitItemKind)
}
_ => {
// Non-static methods become `def_method`s.
(DefMethod(local_def(ty_m.id),
Some(local_def(item.id))),
MethodIsNotStatic)
NonstaticMethodTraitItemKind)
}
};
@ -1404,7 +1412,7 @@ impl<'a> Resolver<'a> {
ty_m.span);
method_name_bindings.define_value(def, ty_m.span, true);
self.method_map
self.trait_item_map
.borrow_mut()
.insert((ident.name, def_id), static_flag);
}
@ -1714,29 +1722,29 @@ impl<'a> Resolver<'a> {
debug!("(building reduced graph for external \
crate) building type {}", final_ident);
// If this is a trait, add all the method names
// to the trait info.
// If this is a trait, add all the trait item names to the trait
// info.
let method_def_ids =
csearch::get_trait_method_def_ids(&self.session.cstore, def_id);
for &method_def_id in method_def_ids.iter() {
let (method_name, explicit_self) =
csearch::get_method_name_and_explicit_self(&self.session.cstore,
method_def_id);
let trait_item_def_ids =
csearch::get_trait_item_def_ids(&self.session.cstore, def_id);
for trait_item_def_id in trait_item_def_ids.iter() {
let (trait_item_name, trait_item_kind) =
csearch::get_trait_item_name_and_kind(
&self.session.cstore,
trait_item_def_id.def_id());
debug!("(building reduced graph for \
external crate) ... adding \
trait method '{}'",
token::get_ident(method_name));
debug!("(building reduced graph for external crate) ... \
adding trait item '{}'",
token::get_ident(trait_item_name));
self.method_map
self.trait_item_map
.borrow_mut()
.insert((method_name.name, def_id),
MethodIsStaticFlag::from_explicit_self_category(
explicit_self));
.insert((trait_item_name.name, def_id),
trait_item_kind);
if is_exported {
self.external_exports.insert(method_def_id);
self.external_exports
.insert(trait_item_def_id.def_id());
}
}
@ -3680,12 +3688,12 @@ impl<'a> Resolver<'a> {
ItemImpl(ref generics,
ref implemented_traits,
ref self_type,
ref methods) => {
ref impl_items) => {
self.resolve_implementation(item.id,
generics,
implemented_traits,
&**self_type,
methods.as_slice());
impl_items.as_slice());
}
ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
@ -3724,12 +3732,12 @@ impl<'a> Resolver<'a> {
// FIXME #4951: Do we need a node ID here?
match *method {
ast::Required(ref ty_m) => {
ast::RequiredMethod(ref ty_m) => {
this.with_type_parameter_rib
(HasTypeParameters(&ty_m.generics,
FnSpace,
item.id,
MethodRibKind(item.id, Required)),
MethodRibKind(item.id, RequiredMethod)),
|this| {
// Resolve the method-specific type
@ -3751,9 +3759,9 @@ impl<'a> Resolver<'a> {
this.resolve_type(&*ty_m.decl.output);
});
}
ast::Provided(ref m) => {
ast::ProvidedMethod(ref m) => {
this.resolve_method(MethodRibKind(item.id,
Provided(m.id)),
ProvidedMethod(m.id)),
&**m)
}
}
@ -4129,7 +4137,7 @@ impl<'a> Resolver<'a> {
generics: &Generics,
opt_trait_reference: &Option<TraitRef>,
self_type: &Ty,
methods: &[Gc<Method>]) {
impl_items: &[ImplItem]) {
// If applicable, create a rib for the type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
@ -4145,27 +4153,36 @@ impl<'a> Resolver<'a> {
this.resolve_type(self_type);
this.with_current_self_type(self_type, |this| {
for method in methods.iter() {
// If this is a trait impl, ensure the method exists in trait
this.check_trait_method(&**method);
for impl_item in impl_items.iter() {
match *impl_item {
MethodImplItem(method) => {
// If this is a trait impl, ensure the method
// exists in trait
this.check_trait_item(method.pe_ident(),
method.span);
// We also need a new scope for the method-specific type parameters.
this.resolve_method(MethodRibKind(id, Provided(method.id)),
&**method);
// We also need a new scope for the method-
// specific type parameters.
this.resolve_method(
MethodRibKind(id,
ProvidedMethod(method.id)),
&*method);
}
}
}
});
});
});
}
fn check_trait_method(&self, method: &Method) {
fn check_trait_item(&self, ident: Ident, span: Span) {
// If there is a TraitRef in scope for an impl, then the method must be in the trait.
for &(did, ref trait_ref) in self.current_trait_ref.iter() {
let method_name = method.pe_ident().name;
let method_name = ident.name;
if self.method_map.borrow().find(&(method_name, did)).is_none() {
if self.trait_item_map.borrow().find(&(method_name, did)).is_none() {
let path_str = self.path_idents_to_string(&trait_ref.path);
self.resolve_error(method.span,
self.resolve_error(span,
format!("method `{}` is not a member of trait `{}`",
token::get_name(method_name),
path_str).as_slice());
@ -4845,8 +4862,8 @@ impl<'a> Resolver<'a> {
TraitModuleKind | ImplModuleKind => {
match containing_module.def_id.get() {
Some(def_id) => {
match self.method_map.borrow().find(&(ident.name, def_id)) {
Some(&MethodIsStatic) => (),
match self.trait_item_map.borrow().find(&(ident.name, def_id)) {
Some(&StaticMethodTraitItemKind) => (),
None => (),
_ => {
debug!("containing module was a trait or impl \
@ -5102,7 +5119,7 @@ impl<'a> Resolver<'a> {
}
}
Some(DefMethod(_, None)) if allowed == Everything => return Method,
Some(DefMethod(_, Some(_))) => return TraitMethod,
Some(DefMethod(_, Some(_))) => return TraitItem,
_ => ()
}
}
@ -5112,14 +5129,14 @@ impl<'a> Resolver<'a> {
}
// Look for a method in the current trait.
let method_map = self.method_map.borrow();
let trait_item_map = self.trait_item_map.borrow();
match self.current_trait_ref {
Some((did, ref trait_ref)) => {
let path_str = self.path_idents_to_string(&trait_ref.path);
match method_map.find(&(name, did)) {
Some(&MethodIsStatic) => return StaticTraitMethod(path_str),
Some(_) => return TraitMethod,
match trait_item_map.find(&(name, did)) {
Some(&StaticMethodTraitItemKind) => return StaticTraitMethod(path_str),
Some(_) => return TraitItem,
None => {}
}
}
@ -5262,7 +5279,7 @@ impl<'a> Resolver<'a> {
Field =>
format!("`self.{}`", wrong_name),
Method
| TraitMethod =>
| TraitItem =>
format!("to call `self.{}`", wrong_name),
StaticTraitMethod(path_str)
| StaticMethod(path_str) =>
@ -5437,9 +5454,9 @@ impl<'a> Resolver<'a> {
// Look for the current trait.
match self.current_trait_ref {
Some((trait_def_id, _)) => {
let method_map = self.method_map.borrow();
let trait_item_map = self.trait_item_map.borrow();
if method_map.contains_key(&(name, trait_def_id)) {
if trait_item_map.contains_key(&(name, trait_def_id)) {
add_trait_info(&mut found_traits, trait_def_id, name);
}
}
@ -5450,7 +5467,7 @@ impl<'a> Resolver<'a> {
self.populate_module_if_necessary(&search_module);
{
let method_map = self.method_map.borrow();
let trait_item_map = self.trait_item_map.borrow();
for (_, child_names) in search_module.children.borrow().iter() {
let def = match child_names.def_for_namespace(TypeNS) {
Some(def) => def,
@ -5460,7 +5477,7 @@ impl<'a> Resolver<'a> {
DefTrait(trait_def_id) => trait_def_id,
_ => continue,
};
if method_map.contains_key(&(name, trait_def_id)) {
if trait_item_map.contains_key(&(name, trait_def_id)) {
add_trait_info(&mut found_traits, trait_def_id, name);
}
}
@ -5476,7 +5493,7 @@ impl<'a> Resolver<'a> {
Some(DefTrait(trait_def_id)) => trait_def_id,
Some(..) | None => continue,
};
if self.method_map.borrow().contains_key(&(name, did)) {
if self.trait_item_map.borrow().contains_key(&(name, did)) {
add_trait_info(&mut found_traits, did, name);
self.used_imports.insert((import.type_id, TypeNS));
}

View File

@ -283,8 +283,8 @@ impl <'l> DxrVisitor<'l> {
let mut result = String::from_str("<");
result.push_str(ty_to_string(&*ty).as_slice());
match ty::trait_of_method(&self.analysis.ty_cx,
ast_util::local_def(method.id)) {
match ty::trait_of_item(&self.analysis.ty_cx,
ast_util::local_def(method.id)) {
Some(def_id) => {
result.push_str(" as ");
result.push_str(
@ -310,8 +310,8 @@ impl <'l> DxrVisitor<'l> {
).as_slice());
},
},
None => match ty::trait_of_method(&self.analysis.ty_cx,
ast_util::local_def(method.id)) {
None => match ty::trait_of_item(&self.analysis.ty_cx,
ast_util::local_def(method.id)) {
Some(def_id) => {
scope_id = def_id.node;
match self.analysis.ty_cx.map.get(def_id.node) {
@ -338,9 +338,19 @@ impl <'l> DxrVisitor<'l> {
let qualname = qualname.as_slice();
// record the decl for this def (if it has one)
let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx,
ast_util::local_def(method.id))
.filtered(|def_id| method.id != 0 && def_id.node == 0);
let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx,
ast_util::local_def(method.id))
.filtered(|def_id| {
match *def_id {
ty::MethodTraitItemId(def_id) => {
method.id != 0 && def_id.node == 0
}
}
});
let decl_id = match decl_id {
None => None,
Some(ty::MethodTraitItemId(def_id)) => Some(def_id),
};
let sub_span = self.span.sub_span_after_keyword(method.span, keywords::Fn);
self.fmt.method_str(method.span,
@ -601,7 +611,7 @@ impl <'l> DxrVisitor<'l> {
type_parameters: &ast::Generics,
trait_ref: &Option<ast::TraitRef>,
typ: ast::P<ast::Ty>,
methods: &Vec<Gc<ast::Method>>) {
impl_items: &Vec<ast::ImplItem>) {
match typ.node {
ast::TyPath(ref path, _, id) => {
match self.lookup_type_ref(id) {
@ -630,8 +640,12 @@ impl <'l> DxrVisitor<'l> {
}
self.process_generic_params(type_parameters, item.span, "", item.id, e);
for method in methods.iter() {
visit::walk_method_helper(self, &**method, e)
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(method) => {
visit::walk_method_helper(self, &*method, e)
}
}
}
}
@ -640,7 +654,7 @@ impl <'l> DxrVisitor<'l> {
e: DxrVisitorEnv,
generics: &ast::Generics,
trait_refs: &Vec<ast::TraitRef>,
methods: &Vec<ast::TraitMethod>) {
methods: &Vec<ast::TraitItem>) {
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
@ -672,7 +686,7 @@ impl <'l> DxrVisitor<'l> {
// walk generics and methods
self.process_generic_params(generics, item.span, qualname.as_slice(), item.id, e);
for method in methods.iter() {
self.visit_trait_method(method, e)
self.visit_trait_item(method, e)
}
}
@ -735,18 +749,44 @@ impl <'l> DxrVisitor<'l> {
def::DefStaticMethod(declid, provenence, _) => {
let sub_span = self.span.sub_span_for_meth_name(ex.span);
let defid = if declid.krate == ast::LOCAL_CRATE {
let m = ty::method(&self.analysis.ty_cx, declid);
let ti = ty::impl_or_trait_item(&self.analysis.ty_cx,
declid);
match provenence {
def::FromTrait(def_id) =>
Some(ty::trait_methods(&self.analysis.ty_cx, def_id)
.iter().find(|mr| mr.ident.name == m.ident.name).unwrap().def_id),
def::FromTrait(def_id) => {
Some(ty::trait_items(&self.analysis.ty_cx,
def_id)
.iter()
.find(|mr| {
match **mr {
ty::MethodTraitItem(ref mr) => {
mr.ident.name == ti.ident()
.name
}
}
})
.unwrap()
.def_id())
}
def::FromImpl(def_id) => {
let impl_methods = self.analysis.ty_cx.impl_methods.borrow();
Some(*impl_methods.get(&def_id)
.iter().find(|mr|
ty::method(
&self.analysis.ty_cx, **mr).ident.name == m.ident.name)
.unwrap())
let impl_items = self.analysis
.ty_cx
.impl_items
.borrow();
Some(impl_items.get(&def_id)
.iter()
.find(|mr| {
match **mr {
ty::MethodTraitItemId(mr) => {
ty::impl_or_trait_item(
&self.analysis
.ty_cx,
mr).ident()
.name ==
ti.ident().name
}
}
}).unwrap()
.def_id())
}
}
} else {
@ -845,27 +885,45 @@ impl <'l> DxrVisitor<'l> {
typeck::MethodStatic(def_id) |
typeck::MethodStaticUnboxedClosure(def_id) => {
// method invoked on an object with a concrete type (not a static method)
let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id);
let decl_id =
match ty::trait_item_of_item(&self.analysis.ty_cx,
def_id) {
None => None,
Some(ty::MethodTraitItemId(decl_id)) => Some(decl_id),
};
// This incantation is required if the method referenced is a trait's
// default implementation.
let def_id = ty::method(&self.analysis.ty_cx, def_id).provided_source
.unwrap_or(def_id);
// This incantation is required if the method referenced is a
// trait's default implementation.
let def_id = match ty::impl_or_trait_item(&self.analysis
.ty_cx,
def_id) {
ty::MethodTraitItem(method) => {
method.provided_source.unwrap_or(def_id)
}
};
(Some(def_id), decl_id)
}
typeck::MethodParam(mp) => {
// method invoked on a type parameter
let method = ty::trait_method(&self.analysis.ty_cx,
mp.trait_id,
mp.method_num);
(None, Some(method.def_id))
let trait_item = ty::trait_item(&self.analysis.ty_cx,
mp.trait_id,
mp.method_num);
match trait_item {
ty::MethodTraitItem(method) => {
(None, Some(method.def_id))
}
}
},
typeck::MethodObject(mo) => {
// method invoked on a trait instance
let method = ty::trait_method(&self.analysis.ty_cx,
mo.trait_id,
mo.method_num);
(None, Some(method.def_id))
let trait_item = ty::trait_item(&self.analysis.ty_cx,
mo.trait_id,
mo.method_num);
match trait_item {
ty::MethodTraitItem(method) => {
(None, Some(method.def_id))
}
}
},
};
let sub_span = self.span.sub_span_for_meth_name(ex.span);
@ -968,8 +1026,17 @@ impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
self.process_static(item, e, typ, mt, &*expr),
ast::ItemStruct(def, ref ty_params) => self.process_struct(item, e, &*def, ty_params),
ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, e, def, ty_params),
ast::ItemImpl(ref ty_params, ref trait_ref, typ, ref methods) =>
self.process_impl(item, e, ty_params, trait_ref, typ, methods),
ast::ItemImpl(ref ty_params,
ref trait_ref,
typ,
ref impl_items) => {
self.process_impl(item,
e,
ty_params,
trait_ref,
typ,
impl_items)
}
ast::ItemTrait(ref generics, _, ref trait_refs, ref methods) =>
self.process_trait(item, e, generics, trait_refs, methods),
ast::ItemMod(ref m) => self.process_mod(item, e, m),
@ -1027,16 +1094,16 @@ impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
}
}
fn visit_trait_method(&mut self, tm: &ast::TraitMethod, e: DxrVisitorEnv) {
fn visit_trait_item(&mut self, tm: &ast::TraitItem, e: DxrVisitorEnv) {
match *tm {
ast::Required(ref method_type) => {
ast::RequiredMethod(ref method_type) => {
if generated_code(method_type.span) {
return;
}
let mut scope_id ;
let mut qualname = match ty::trait_of_method(&self.analysis.ty_cx,
ast_util::local_def(method_type.id)) {
let mut scope_id;
let mut qualname = match ty::trait_of_item(&self.analysis.ty_cx,
ast_util::local_def(method_type.id)) {
Some(def_id) => {
scope_id = def_id.node;
ty::item_path_str(&self.analysis.ty_cx, def_id).append("::")
@ -1070,7 +1137,7 @@ impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
method_type.id,
e);
}
ast::Provided(method) => self.process_method(&*method, e),
ast::ProvidedMethod(method) => self.process_method(&*method, e),
}
}

View File

@ -16,7 +16,7 @@ use syntax::codemap::Span;
use syntax::{attr, visit};
use syntax::ast;
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
use syntax::ast::{Item, Required, Provided, TraitMethod, TypeMethod, Method};
use syntax::ast::{Item, RequiredMethod, ProvidedMethod, TraitItem, TypeMethod, Method};
use syntax::ast::{Generics, StructDef, StructField, Ident};
use syntax::ast_util::is_local;
use syntax::attr::Stability;
@ -68,18 +68,18 @@ impl Visitor<Option<Stability>> for Annotator {
visit::walk_fn(self, fk, fd, b, s, stab)
}
fn visit_trait_method(&mut self, t: &TraitMethod, parent: Option<Stability>) {
fn visit_trait_item(&mut self, t: &TraitItem, parent: Option<Stability>) {
let stab = match *t {
Required(TypeMethod {attrs: ref attrs, id: id, ..}) =>
RequiredMethod(TypeMethod {attrs: ref attrs, id: id, ..}) =>
self.annotate(id, attrs.as_slice(), parent),
// work around lack of pattern matching for @ types
Provided(method) => match *method {
ProvidedMethod(method) => match *method {
Method {attrs: ref attrs, id: id, ..} =>
self.annotate(id, attrs.as_slice(), parent)
}
};
visit::walk_trait_method(self, t, stab)
visit::walk_trait_item(self, t, stab)
}
fn visit_variant(&mut self, v: &Variant, g: &Generics, parent: Option<Stability>) {
@ -116,10 +116,11 @@ impl Index {
/// Lookup the stability for a node, loading external crate
/// metadata as necessary.
pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
// is this definition the implementation of a trait method?
match ty::trait_method_of_method(tcx, id) {
Some(trait_method_id) if trait_method_id != id => {
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) => {

View File

@ -1299,9 +1299,9 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
_ => tcx.sess.bug("unexpected item variant in has_nested_returns")
}
}
Some(ast_map::NodeTraitMethod(trait_method)) => {
Some(ast_map::NodeTraitItem(trait_method)) => {
match *trait_method {
ast::Provided(m) => {
ast::ProvidedMethod(m) => {
match m.node {
ast::MethDecl(_, _, _, _, _, _, blk, _) => {
let mut explicit = CheckForNestedReturnsVisitor { found: false };
@ -1313,20 +1313,34 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
}
}
ast::Required(_) => tcx.sess.bug("unexpected variant: required trait method in \
has_nested_returns")
ast::RequiredMethod(_) => {
tcx.sess.bug("unexpected variant: required trait method \
in has_nested_returns")
}
}
}
Some(ast_map::NodeMethod(m)) => {
match m.node {
ast::MethDecl(_, _, _, _, _, _, blk, _) => {
let mut explicit = CheckForNestedReturnsVisitor { found: false };
let mut implicit = CheckForNestedReturnsVisitor { found: false };
visit::walk_method_helper(&mut explicit, &*m, false);
visit::walk_expr_opt(&mut implicit, blk.expr, true);
explicit.found || implicit.found
Some(ast_map::NodeImplItem(ref ii)) => {
match **ii {
ast::MethodImplItem(ref m) => {
match m.node {
ast::MethDecl(_, _, _, _, _, _, blk, _) => {
let mut explicit = CheckForNestedReturnsVisitor {
found: false,
};
let mut implicit = CheckForNestedReturnsVisitor {
found: false,
};
visit::walk_method_helper(&mut explicit,
&**m,
false);
visit::walk_expr_opt(&mut implicit,
blk.expr,
true);
explicit.found || implicit.found
}
ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
}
}
ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
}
}
Some(ast_map::NodeExpr(e)) => {
@ -2107,8 +2121,12 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
let mut v = TransItemVisitor{ ccx: ccx };
v.visit_block(&**body, ());
}
ast::ItemImpl(ref generics, _, _, ref ms) => {
meth::trans_impl(ccx, item.ident, ms.as_slice(), generics, item.id);
ast::ItemImpl(ref generics, _, _, ref impl_items) => {
meth::trans_impl(ccx,
item.ident,
impl_items.as_slice(),
generics,
item.id);
}
ast::ItemMod(ref m) => {
trans_mod(ccx, m);
@ -2615,21 +2633,23 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
v
}
ast_map::NodeTraitMethod(trait_method) => {
debug!("get_item_val(): processing a NodeTraitMethod");
ast_map::NodeTraitItem(trait_method) => {
debug!("get_item_val(): processing a NodeTraitItem");
match *trait_method {
ast::Required(_) => {
ast::RequiredMethod(_) => {
ccx.sess().bug("unexpected variant: required trait method in \
get_item_val()");
}
ast::Provided(m) => {
ast::ProvidedMethod(m) => {
register_method(ccx, id, &*m)
}
}
}
ast_map::NodeMethod(m) => {
register_method(ccx, id, &*m)
ast_map::NodeImplItem(ii) => {
match *ii {
ast::MethodImplItem(m) => register_method(ccx, id, &*m),
}
}
ast_map::NodeForeignItem(ni) => {

View File

@ -77,7 +77,7 @@ pub enum CalleeData {
Intrinsic(ast::NodeId, subst::Substs),
TraitMethod(MethodData)
TraitItem(MethodData)
}
pub struct Callee<'a> {
@ -449,7 +449,7 @@ pub fn trans_fn_ref_with_vtables(
assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
// Load the info for the appropriate trait if necessary.
match ty::trait_of_method(tcx, def_id) {
match ty::trait_of_item(tcx, def_id) {
None => {}
Some(trait_id) => {
ty::populate_implementations_for_trait_if_necessary(tcx, trait_id)
@ -476,35 +476,43 @@ pub fn trans_fn_ref_with_vtables(
// So, what we need to do is find this substitution and
// compose it with the one we already have.
let impl_id = ty::method(tcx, def_id).container_id();
let method = ty::method(tcx, source_id);
let trait_ref = ty::impl_trait_ref(tcx, impl_id)
.expect("could not find trait_ref for impl with \
default methods");
let impl_id = ty::impl_or_trait_item(tcx, def_id).container()
.id();
let impl_or_trait_item = ty::impl_or_trait_item(tcx, source_id);
match impl_or_trait_item {
ty::MethodTraitItem(method) => {
let trait_ref = ty::impl_trait_ref(tcx, impl_id)
.expect("could not find trait_ref for impl with \
default methods");
// Compute the first substitution
let first_subst = make_substs_for_receiver_types(
tcx, &*trait_ref, &*method);
// Compute the first substitution
let first_subst = make_substs_for_receiver_types(
tcx, &*trait_ref, &*method);
// And compose them
let new_substs = first_subst.subst(tcx, &substs);
// And compose them
let new_substs = first_subst.subst(tcx, &substs);
debug!("trans_fn_with_vtables - default method: \
substs = {}, trait_subst = {}, \
first_subst = {}, new_subst = {}, \
vtables = {}",
substs.repr(tcx), trait_ref.substs.repr(tcx),
first_subst.repr(tcx), new_substs.repr(tcx),
vtables.repr(tcx));
debug!("trans_fn_with_vtables - default method: \
substs = {}, trait_subst = {}, \
first_subst = {}, new_subst = {}, \
vtables = {}",
substs.repr(tcx), trait_ref.substs.repr(tcx),
first_subst.repr(tcx), new_substs.repr(tcx),
vtables.repr(tcx));
let param_vtables =
resolve_default_method_vtables(bcx, impl_id, &substs, vtables);
let param_vtables =
resolve_default_method_vtables(bcx,
impl_id,
&substs,
vtables);
debug!("trans_fn_with_vtables - default method: \
param_vtables = {}",
param_vtables.repr(tcx));
debug!("trans_fn_with_vtables - default method: \
param_vtables = {}",
param_vtables.repr(tcx));
(true, source_id, new_substs, param_vtables)
(true, source_id, new_substs, param_vtables)
}
}
}
};
@ -742,7 +750,7 @@ pub fn trans_call_inner<'a>(
Fn(llfn) => {
(llfn, None, None)
}
TraitMethod(d) => {
TraitItem(d) => {
(d.llfn, None, Some(d.llself))
}
Closure(d) => {

View File

@ -1140,13 +1140,17 @@ pub fn create_function_debug_context(cx: &CrateContext,
}
}
}
ast_map::NodeMethod(ref method) => {
(method.pe_ident(),
method.pe_fn_decl(),
method.pe_generics(),
method.pe_body(),
method.span,
true)
ast_map::NodeImplItem(ref item) => {
match **item {
ast::MethodImplItem(ref method) => {
(method.pe_ident(),
method.pe_fn_decl(),
method.pe_generics(),
method.pe_body(),
method.span,
true)
}
}
}
ast_map::NodeExpr(ref expr) => {
match expr.node {
@ -1168,9 +1172,9 @@ pub fn create_function_debug_context(cx: &CrateContext,
"create_function_debug_context: expected an expr_fn_block here")
}
}
ast_map::NodeTraitMethod(ref trait_method) => {
ast_map::NodeTraitItem(ref trait_method) => {
match **trait_method {
ast::Provided(ref method) => {
ast::ProvidedMethod(ref method) => {
(method.pe_ident(),
method.pe_fn_decl(),
method.pe_generics(),

View File

@ -115,27 +115,42 @@ pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
ccx.sess().bug("maybe_get_item_ast returned a found_parent \
with a non-item parent");
}
csearch::found(ast::IIMethod(impl_did, is_provided, mth)) => {
ccx.external.borrow_mut().insert(fn_id, Some(mth.id));
ccx.external_srcs.borrow_mut().insert(mth.id, fn_id);
csearch::found(ast::IITraitItem(impl_did, impl_item)) => {
match impl_item {
ast::ProvidedInlinedTraitItem(mth) |
ast::RequiredInlinedTraitItem(mth) => {
ccx.external.borrow_mut().insert(fn_id, Some(mth.id));
ccx.external_srcs.borrow_mut().insert(mth.id, fn_id);
ccx.stats.n_inlines.set(ccx.stats.n_inlines.get() + 1);
ccx.stats.n_inlines.set(ccx.stats.n_inlines.get() + 1);
}
}
// If this is a default method, we can't look up the
// impl type. But we aren't going to translate anyways, so don't.
if is_provided { return local_def(mth.id); }
match impl_item {
ast::ProvidedInlinedTraitItem(mth) => {
// If this is a default method, we can't look up the
// impl type. But we aren't going to translate anyways, so
// don't.
local_def(mth.id)
}
ast::RequiredInlinedTraitItem(mth) => {
let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did);
let unparameterized = impl_tpt.generics.types.is_empty() &&
mth.pe_generics().ty_params.is_empty();
let impl_tpt = ty::lookup_item_type(ccx.tcx(), impl_did);
let unparameterized =
impl_tpt.generics.types.is_empty() &&
mth.pe_generics().ty_params.is_empty();
if unparameterized {
let llfn = get_item_val(ccx, mth.id);
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), llfn,
&param_substs::empty(), mth.id, []);
}
local_def(mth.id)
if unparameterized {
let llfn = get_item_val(ccx, mth.id);
trans_fn(ccx,
&*mth.pe_fn_decl(),
&*mth.pe_body(),
llfn,
&param_substs::empty(),
mth.id,
[]);
}
local_def(mth.id)
}
}
}
};
}

View File

@ -35,7 +35,6 @@ use util::common::indenter;
use util::ppaux::Repr;
use std::c_str::ToCStr;
use std::gc::Gc;
use syntax::abi::{Rust, RustCall};
use syntax::parse::token;
use syntax::{ast, ast_map, visit};
@ -49,7 +48,7 @@ see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
*/
pub fn trans_impl(ccx: &CrateContext,
name: ast::Ident,
methods: &[Gc<ast::Method>],
impl_items: &[ast::ImplItem],
generics: &ast::Generics,
id: ast::NodeId) {
let _icx = push_ctxt("meth::trans_impl");
@ -61,24 +60,34 @@ pub fn trans_impl(ccx: &CrateContext,
// items that we need to translate.
if !generics.ty_params.is_empty() {
let mut v = TransItemVisitor{ ccx: ccx };
for method in methods.iter() {
visit::walk_method_helper(&mut v, &**method, ());
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(method) => {
visit::walk_method_helper(&mut v, &*method, ());
}
}
}
return;
}
for method in methods.iter() {
if method.pe_generics().ty_params.len() == 0u {
let llfn = get_item_val(ccx, method.id);
trans_fn(ccx,
&*method.pe_fn_decl(),
&*method.pe_body(),
llfn,
&param_substs::empty(),
method.id,
[]);
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(method) => {
if method.pe_generics().ty_params.len() == 0u {
let llfn = get_item_val(ccx, method.id);
trans_fn(ccx,
&*method.pe_fn_decl(),
&*method.pe_body(),
llfn,
&param_substs::empty(),
method.id,
[]);
}
let mut v = TransItemVisitor {
ccx: ccx,
};
visit::walk_method_helper(&mut v, &*method, ());
}
}
let mut v = TransItemVisitor{ ccx: ccx };
visit::walk_method_helper(&mut v, &**method, ());
}
}
@ -165,10 +174,10 @@ pub fn trans_static_method_callee(bcx: &Block,
let mname = if method_id.krate == ast::LOCAL_CRATE {
match bcx.tcx().map.get(method_id.node) {
ast_map::NodeTraitMethod(method) => {
ast_map::NodeTraitItem(method) => {
let ident = match *method {
ast::Required(ref m) => m.ident,
ast::Provided(ref m) => m.pe_ident()
ast::RequiredMethod(ref m) => m.ident,
ast::ProvidedMethod(ref m) => m.pe_ident()
};
ident.name
}
@ -213,22 +222,33 @@ pub fn trans_static_method_callee(bcx: &Block,
}
}
fn method_with_name(ccx: &CrateContext,
impl_id: ast::DefId,
name: ast::Name) -> ast::DefId {
fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name)
-> ast::DefId {
match ccx.impl_method_cache.borrow().find_copy(&(impl_id, name)) {
Some(m) => return m,
None => {}
}
let methods = ccx.tcx.impl_methods.borrow();
let methods = methods.find(&impl_id)
.expect("could not find impl while translating");
let meth_did = methods.iter().find(|&did| ty::method(&ccx.tcx, *did).ident.name == name)
.expect("could not find method while translating");
let impl_items = ccx.tcx.impl_items.borrow();
let impl_items =
impl_items.find(&impl_id)
.expect("could not find impl while translating");
let meth_did = impl_items.iter()
.find(|&did| {
match *did {
ty::MethodTraitItemId(did) => {
ty::impl_or_trait_item(&ccx.tcx,
did).ident()
.name ==
name
}
}
}).expect("could not find method while \
translating");
ccx.impl_method_cache.borrow_mut().insert((impl_id, name), *meth_did);
*meth_did
ccx.impl_method_cache.borrow_mut().insert((impl_id, name),
meth_did.def_id());
meth_did.def_id()
}
fn trans_monomorphized_callee<'a>(
@ -242,7 +262,9 @@ fn trans_monomorphized_callee<'a>(
match vtbl {
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
let ccx = bcx.ccx();
let mname = ty::trait_method(ccx.tcx(), trait_id, n_method).ident;
let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) {
ty::MethodTraitItem(method) => method.ident,
};
let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name);
// create a concatenated set of substitutions which includes
@ -433,7 +455,7 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>,
return Callee {
bcx: bcx,
data: TraitMethod(MethodData {
data: TraitItem(MethodData {
llfn: mptr,
llself: llself,
})
@ -552,35 +574,42 @@ fn emit_vtable_methods(bcx: &Block,
ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trt_id);
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
trait_method_def_ids.iter().map(|method_def_id| {
let ident = ty::method(tcx, *method_def_id).ident;
let trait_item_def_ids = ty::trait_item_def_ids(tcx, trt_id);
trait_item_def_ids.iter().map(|method_def_id| {
let method_def_id = method_def_id.def_id();
let ident = ty::impl_or_trait_item(tcx, method_def_id).ident();
// The substitutions we have are on the impl, so we grab
// the method type from the impl to substitute into.
let m_id = method_with_name(ccx, impl_id, ident.name);
let m = ty::method(tcx, m_id);
debug!("(making impl vtable) emitting method {} at subst {}",
m.repr(tcx),
substs.repr(tcx));
if m.generics.has_type_params(subst::FnSpace) ||
ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone())) {
debug!("(making impl vtable) method has self or type params: {}",
token::get_ident(ident));
C_null(Type::nil(ccx).ptr_to())
} else {
let mut fn_ref = trans_fn_ref_with_vtables(bcx,
m_id,
ExprId(0),
substs.clone(),
vtables.clone());
if m.explicit_self == ty::ByValueExplicitSelfCategory {
fn_ref = trans_unboxing_shim(bcx,
fn_ref,
&*m,
m_id,
substs.clone());
let ti = ty::impl_or_trait_item(tcx, m_id);
match ti {
ty::MethodTraitItem(m) => {
debug!("(making impl vtable) emitting method {} at subst {}",
m.repr(tcx),
substs.repr(tcx));
if m.generics.has_type_params(subst::FnSpace) ||
ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone())) {
debug!("(making impl vtable) method has self or type \
params: {}",
token::get_ident(ident));
C_null(Type::nil(ccx).ptr_to())
} else {
let mut fn_ref = trans_fn_ref_with_vtables(
bcx,
m_id,
ExprId(0),
substs.clone(),
vtables.clone());
if m.explicit_self == ty::ByValueExplicitSelfCategory {
fn_ref = trans_unboxing_shim(bcx,
fn_ref,
&*m,
m_id,
substs.clone());
}
fn_ref
}
}
fn_ref
}
}).collect()
}

View File

@ -197,15 +197,25 @@ pub fn monomorphic_fn(ccx: &CrateContext,
}
d
}
ast_map::NodeMethod(mth) => {
let d = mk_lldecl(abi::Rust);
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, &psubsts, mth.id, []);
d
ast_map::NodeImplItem(ii) => {
match *ii {
ast::MethodImplItem(mth) => {
let d = mk_lldecl(abi::Rust);
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
trans_fn(ccx,
&*mth.pe_fn_decl(),
&*mth.pe_body(),
d,
&psubsts,
mth.id,
[]);
d
}
}
}
ast_map::NodeTraitMethod(method) => {
ast_map::NodeTraitItem(method) => {
match *method {
ast::Provided(mth) => {
ast::ProvidedMethod(mth) => {
let d = mk_lldecl(abi::Rust);
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d,

View File

@ -25,7 +25,6 @@ use middle::trans::type_of::*;
use middle::ty;
use util::ppaux::ty_to_string;
use std::rc::Rc;
use arena::TypedArena;
use libc::c_uint;
use syntax::ast::DefId;
@ -36,7 +35,7 @@ use syntax::parse::token;
pub struct Reflector<'a, 'b> {
visitor_val: ValueRef,
visitor_methods: &'a [Rc<ty::Method>],
visitor_items: &'a [ty::ImplOrTraitItem],
final_bcx: &'b Block<'b>,
tydesc_ty: Type,
bcx: &'b Block<'b>
@ -87,13 +86,14 @@ impl<'a, 'b> Reflector<'a, 'b> {
pub fn visit(&mut self, ty_name: &str, args: &[ValueRef]) {
let fcx = self.bcx.fcx;
let tcx = self.bcx.tcx();
let mth_idx = ty::method_idx(token::str_to_ident(format!(
let mth_idx = ty::impl_or_trait_item_idx(token::str_to_ident(format!(
"visit_{}", ty_name).as_slice()),
self.visitor_methods.as_slice()).expect(
self.visitor_items.as_slice()).expect(
format!("couldn't find visit method for {}", ty_name).as_slice());
let mth_ty =
ty::mk_bare_fn(tcx,
self.visitor_methods[mth_idx].fty.clone());
let method = match self.visitor_items[mth_idx] {
ty::MethodTraitItem(ref method) => (*method).clone(),
};
let mth_ty = ty::mk_bare_fn(tcx, method.fty.clone());
let v = self.visitor_val;
debug!("passing {} args:", args.len());
let mut bcx = self.bcx;
@ -397,10 +397,10 @@ pub fn emit_calls_to_trait_visit_ty<'a>(
let final = fcx.new_temp_block("final");
let tydesc_ty = ty::get_tydesc_ty(bcx.tcx()).unwrap();
let tydesc_ty = type_of(bcx.ccx(), tydesc_ty);
let visitor_methods = ty::trait_methods(bcx.tcx(), visitor_trait_id);
let visitor_items = ty::trait_items(bcx.tcx(), visitor_trait_id);
let mut r = Reflector {
visitor_val: visitor_val,
visitor_methods: visitor_methods.as_slice(),
visitor_items: visitor_items.as_slice(),
final_bcx: final,
tydesc_ty: tydesc_ty,
bcx: bcx

View File

@ -76,11 +76,64 @@ pub struct field {
}
#[deriving(Clone)]
pub enum MethodContainer {
pub enum ImplOrTraitItemContainer {
TraitContainer(ast::DefId),
ImplContainer(ast::DefId),
}
impl ImplOrTraitItemContainer {
pub fn id(&self) -> ast::DefId {
match *self {
TraitContainer(id) => id,
ImplContainer(id) => id,
}
}
}
#[deriving(Clone)]
pub enum ImplOrTraitItem {
MethodTraitItem(Rc<Method>),
}
impl ImplOrTraitItem {
fn id(&self) -> ImplOrTraitItemId {
match *self {
MethodTraitItem(ref method) => MethodTraitItemId(method.def_id),
}
}
pub fn def_id(&self) -> ast::DefId {
match *self {
MethodTraitItem(ref method) => method.def_id,
}
}
pub fn ident(&self) -> ast::Ident {
match *self {
MethodTraitItem(ref method) => method.ident,
}
}
pub fn container(&self) -> ImplOrTraitItemContainer {
match *self {
MethodTraitItem(ref method) => method.container,
}
}
}
#[deriving(Clone)]
pub enum ImplOrTraitItemId {
MethodTraitItemId(ast::DefId),
}
impl ImplOrTraitItemId {
pub fn def_id(&self) -> ast::DefId {
match *self {
MethodTraitItemId(def_id) => def_id,
}
}
}
#[deriving(Clone)]
pub struct Method {
pub ident: ast::Ident,
@ -89,7 +142,7 @@ pub struct Method {
pub explicit_self: ExplicitSelfCategory,
pub vis: ast::Visibility,
pub def_id: ast::DefId,
pub container: MethodContainer,
pub container: ImplOrTraitItemContainer,
// If this method is provided, we need to know where it came from
pub provided_source: Option<ast::DefId>
@ -102,7 +155,7 @@ impl Method {
explicit_self: ExplicitSelfCategory,
vis: ast::Visibility,
def_id: ast::DefId,
container: MethodContainer,
container: ImplOrTraitItemContainer,
provided_source: Option<ast::DefId>)
-> Method {
Method {
@ -274,14 +327,14 @@ pub struct ctxt {
/// other items.
pub item_substs: RefCell<NodeMap<ItemSubsts>>,
/// Maps from a method to the method "descriptor"
pub methods: RefCell<DefIdMap<Rc<Method>>>,
/// Maps from a trait item to the trait item "descriptor"
pub impl_or_trait_items: RefCell<DefIdMap<ImplOrTraitItem>>,
/// Maps from a trait def-id to a list of the def-ids of its methods
pub trait_method_def_ids: RefCell<DefIdMap<Rc<Vec<DefId>>>>,
/// Maps from a trait def-id to a list of the def-ids of its trait items
pub trait_item_def_ids: RefCell<DefIdMap<Rc<Vec<ImplOrTraitItemId>>>>,
/// A cache for the trait_methods() routine
pub trait_methods_cache: RefCell<DefIdMap<Rc<Vec<Rc<Method>>>>>,
/// A cache for the trait_items() routine
pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ImplOrTraitItem>>>>,
pub impl_trait_cache: RefCell<DefIdMap<Option<Rc<ty::TraitRef>>>>,
@ -332,11 +385,11 @@ pub struct ctxt {
/// Methods in these implementations don't need to be exported.
pub inherent_impls: RefCell<DefIdMap<Rc<RefCell<Vec<ast::DefId>>>>>,
/// Maps a DefId of an impl to a list of its methods.
/// Maps a DefId of an impl to a list of its items.
/// Note that this contains all of the impls that we know about,
/// including ones in other crates. It's not clear that this is the best
/// way to do it.
pub impl_methods: RefCell<DefIdMap<Vec<ast::DefId>>>,
pub impl_items: RefCell<DefIdMap<Vec<ImplOrTraitItemId>>>,
/// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
/// present in this set can be warned about.
@ -1104,9 +1157,9 @@ pub fn mk_ctxt(s: Session,
tc_cache: RefCell::new(HashMap::new()),
ast_ty_to_ty_cache: RefCell::new(NodeMap::new()),
enum_var_cache: RefCell::new(DefIdMap::new()),
methods: RefCell::new(DefIdMap::new()),
trait_method_def_ids: RefCell::new(DefIdMap::new()),
trait_methods_cache: RefCell::new(DefIdMap::new()),
impl_or_trait_items: RefCell::new(DefIdMap::new()),
trait_item_def_ids: RefCell::new(DefIdMap::new()),
trait_items_cache: RefCell::new(DefIdMap::new()),
impl_trait_cache: RefCell::new(DefIdMap::new()),
ty_param_defs: RefCell::new(NodeMap::new()),
adjustments: RefCell::new(NodeMap::new()),
@ -1120,7 +1173,7 @@ pub fn mk_ctxt(s: Session,
destructors: RefCell::new(DefIdSet::new()),
trait_impls: RefCell::new(DefIdMap::new()),
inherent_impls: RefCell::new(DefIdMap::new()),
impl_methods: RefCell::new(DefIdMap::new()),
impl_items: RefCell::new(DefIdMap::new()),
used_unsafe: RefCell::new(NodeSet::new()),
used_mut_nodes: RefCell::new(NodeSet::new()),
impl_vtables: RefCell::new(DefIdMap::new()),
@ -3075,11 +3128,19 @@ pub fn method_call_type_param_defs(tcx: &ctxt, origin: typeck::MethodOrigin)
Err(s) => tcx.sess.fatal(s.as_slice()),
}
}
typeck::MethodParam(typeck::MethodParam{trait_id: trt_id,
method_num: n_mth, ..}) |
typeck::MethodObject(typeck::MethodObject{trait_id: trt_id,
method_num: n_mth, ..}) => {
ty::trait_method(tcx, trt_id, n_mth).generics.types.clone()
typeck::MethodParam(typeck::MethodParam{
trait_id: trt_id,
method_num: n_mth,
..
}) |
typeck::MethodObject(typeck::MethodObject{
trait_id: trt_id,
method_num: n_mth,
..
}) => {
match ty::trait_item(tcx, trt_id, n_mth) {
ty::MethodTraitItem(method) => method.generics.types.clone(),
}
}
}
}
@ -3297,8 +3358,9 @@ pub fn field_idx_strict(tcx: &ctxt, name: ast::Name, fields: &[field])
.collect::<Vec<String>>()).as_slice());
}
pub fn method_idx(id: ast::Ident, meths: &[Rc<Method>]) -> Option<uint> {
meths.iter().position(|m| m.ident == id)
pub fn impl_or_trait_item_idx(id: ast::Ident, trait_items: &[ImplOrTraitItem])
-> Option<uint> {
trait_items.iter().position(|m| m.ident() == id)
}
/// Returns a vector containing the indices of all type parameters that appear
@ -3540,7 +3602,15 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec<Rc<Method>> {
match item.node {
ItemTrait(_, _, _, ref ms) => {
let (_, p) = ast_util::split_trait_methods(ms.as_slice());
p.iter().map(|m| method(cx, ast_util::local_def(m.id))).collect()
p.iter()
.map(|m| {
match impl_or_trait_item(
cx,
ast_util::local_def(m.id)) {
MethodTraitItem(m) => m,
}
})
.collect()
}
_ => {
cx.sess.bug(format!("provided_trait_methods: `{}` is \
@ -3592,7 +3662,7 @@ fn lookup_locally_or_in_crate_store<V:Clone>(
/*!
* Helper for looking things up in the various maps
* that are populated during typeck::collect (e.g.,
* `cx.methods`, `cx.tcache`, etc). All of these share
* `cx.impl_or_trait_items`, `cx.tcache`, etc). All of these share
* the pattern that if the id is local, it should have
* been loaded into the map by the `typeck::collect` phase.
* If the def-id is external, then we have to go consult
@ -3612,40 +3682,47 @@ fn lookup_locally_or_in_crate_store<V:Clone>(
v
}
pub fn trait_method(cx: &ctxt, trait_did: ast::DefId, idx: uint) -> Rc<Method> {
let method_def_id = *ty::trait_method_def_ids(cx, trait_did).get(idx);
ty::method(cx, method_def_id)
pub fn trait_item(cx: &ctxt, trait_did: ast::DefId, idx: uint)
-> ImplOrTraitItem {
let method_def_id = ty::trait_item_def_ids(cx, trait_did).get(idx)
.def_id();
impl_or_trait_item(cx, method_def_id)
}
pub fn trait_methods(cx: &ctxt, trait_did: ast::DefId) -> Rc<Vec<Rc<Method>>> {
let mut trait_methods = cx.trait_methods_cache.borrow_mut();
match trait_methods.find_copy(&trait_did) {
Some(methods) => methods,
pub fn trait_items(cx: &ctxt, trait_did: ast::DefId)
-> Rc<Vec<ImplOrTraitItem>> {
let mut trait_items = cx.trait_items_cache.borrow_mut();
match trait_items.find_copy(&trait_did) {
Some(trait_items) => trait_items,
None => {
let def_ids = ty::trait_method_def_ids(cx, trait_did);
let methods: Rc<Vec<Rc<Method>>> = Rc::new(def_ids.iter().map(|d| {
ty::method(cx, *d)
}).collect());
trait_methods.insert(trait_did, methods.clone());
methods
let def_ids = ty::trait_item_def_ids(cx, trait_did);
let items: Rc<Vec<ImplOrTraitItem>> =
Rc::new(def_ids.iter()
.map(|d| impl_or_trait_item(cx, d.def_id()))
.collect());
trait_items.insert(trait_did, items.clone());
items
}
}
}
pub fn method(cx: &ctxt, id: ast::DefId) -> Rc<Method> {
lookup_locally_or_in_crate_store("methods", id,
&mut *cx.methods.borrow_mut(), || {
Rc::new(csearch::get_method(cx, id))
pub fn impl_or_trait_item(cx: &ctxt, id: ast::DefId) -> ImplOrTraitItem {
lookup_locally_or_in_crate_store("impl_or_trait_items",
id,
&mut *cx.impl_or_trait_items
.borrow_mut(),
|| {
csearch::get_impl_or_trait_item(cx, id)
})
}
pub fn trait_method_def_ids(cx: &ctxt, id: ast::DefId) -> Rc<Vec<DefId>> {
lookup_locally_or_in_crate_store("trait_method_def_ids",
pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId)
-> Rc<Vec<ImplOrTraitItemId>> {
lookup_locally_or_in_crate_store("trait_item_def_ids",
id,
&mut *cx.trait_method_def_ids.borrow_mut(),
&mut *cx.trait_item_def_ids.borrow_mut(),
|| {
Rc::new(csearch::get_trait_method_def_ids(&cx.sess.cstore, id))
Rc::new(csearch::get_trait_item_def_ids(&cx.sess.cstore, id))
})
}
@ -4459,7 +4536,8 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
csearch::each_implementation_for_type(&tcx.sess.cstore, type_id,
|impl_def_id| {
let methods = csearch::get_impl_methods(&tcx.sess.cstore, impl_def_id);
let impl_items = csearch::get_impl_items(&tcx.sess.cstore,
impl_def_id);
// Record the trait->implementation mappings, if applicable.
let associated_traits = csearch::get_impl_trait(tcx, impl_def_id);
@ -4469,14 +4547,21 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
// For any methods that use a default implementation, add them to
// the map. This is a bit unfortunate.
for &method_def_id in methods.iter() {
for &source in ty::method(tcx, method_def_id).provided_source.iter() {
tcx.provided_method_sources.borrow_mut().insert(method_def_id, source);
for impl_item_def_id in impl_items.iter() {
let method_def_id = impl_item_def_id.def_id();
match impl_or_trait_item(tcx, method_def_id) {
MethodTraitItem(method) => {
for &source in method.provided_source.iter() {
tcx.provided_method_sources
.borrow_mut()
.insert(method_def_id, source);
}
}
}
}
// Store the implementation info.
tcx.impl_methods.borrow_mut().insert(impl_def_id, methods);
tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items);
// If this is an inherent implementation, record it.
if associated_traits.is_none() {
@ -4509,21 +4594,28 @@ pub fn populate_implementations_for_trait_if_necessary(
csearch::each_implementation_for_trait(&tcx.sess.cstore, trait_id,
|implementation_def_id| {
let methods = csearch::get_impl_methods(&tcx.sess.cstore, implementation_def_id);
let impl_items = csearch::get_impl_items(&tcx.sess.cstore, implementation_def_id);
// Record the trait->implementation mapping.
record_trait_implementation(tcx, trait_id, implementation_def_id);
// For any methods that use a default implementation, add them to
// the map. This is a bit unfortunate.
for &method_def_id in methods.iter() {
for &source in ty::method(tcx, method_def_id).provided_source.iter() {
tcx.provided_method_sources.borrow_mut().insert(method_def_id, source);
for impl_item_def_id in impl_items.iter() {
let method_def_id = impl_item_def_id.def_id();
match impl_or_trait_item(tcx, method_def_id) {
MethodTraitItem(method) => {
for &source in method.provided_source.iter() {
tcx.provided_method_sources
.borrow_mut()
.insert(method_def_id, source);
}
}
}
}
// Store the implementation info.
tcx.impl_methods.borrow_mut().insert(implementation_def_id, methods);
tcx.impl_items.borrow_mut().insert(implementation_def_id, impl_items);
});
tcx.populated_external_traits.borrow_mut().insert(trait_id);
@ -4555,14 +4647,15 @@ pub fn trait_id_of_impl(tcx: &ctxt,
pub fn impl_of_method(tcx: &ctxt, def_id: ast::DefId)
-> Option<ast::DefId> {
if def_id.krate != LOCAL_CRATE {
return match csearch::get_method(tcx, def_id).container {
return match csearch::get_impl_or_trait_item(tcx,
def_id).container() {
TraitContainer(_) => None,
ImplContainer(def_id) => Some(def_id),
};
}
match tcx.methods.borrow().find_copy(&def_id) {
Some(method) => {
match method.container {
match tcx.impl_or_trait_items.borrow().find_copy(&def_id) {
Some(trait_item) => {
match trait_item.container() {
TraitContainer(_) => None,
ImplContainer(def_id) => Some(def_id),
}
@ -4571,17 +4664,16 @@ pub fn impl_of_method(tcx: &ctxt, def_id: ast::DefId)
}
}
/// If the given def ID describes a method belonging to a trait (either a
/// If the given def ID describes an item belonging to a trait (either a
/// default method or an implementation of a trait method), return the ID of
/// the trait that the method belongs to. Otherwise, return `None`.
pub fn trait_of_method(tcx: &ctxt, def_id: ast::DefId)
-> Option<ast::DefId> {
pub fn trait_of_item(tcx: &ctxt, def_id: ast::DefId) -> Option<ast::DefId> {
if def_id.krate != LOCAL_CRATE {
return csearch::get_trait_of_method(&tcx.sess.cstore, def_id, tcx);
return csearch::get_trait_of_item(&tcx.sess.cstore, def_id, tcx);
}
match tcx.methods.borrow().find_copy(&def_id) {
Some(method) => {
match method.container {
match tcx.impl_or_trait_items.borrow().find_copy(&def_id) {
Some(impl_or_trait_item) => {
match impl_or_trait_item.container() {
TraitContainer(def_id) => Some(def_id),
ImplContainer(def_id) => trait_id_of_impl(tcx, def_id),
}
@ -4590,25 +4682,27 @@ pub fn trait_of_method(tcx: &ctxt, def_id: ast::DefId)
}
}
/// If the given def ID describes a method belonging to a trait, (either a
/// If the given def ID describes an item belonging to a trait, (either a
/// default method or an implementation of a trait method), return the ID of
/// the method inside trait definition (this means that if the given def ID
/// is already that of the original trait method, then the return value is
/// the same).
/// Otherwise, return `None`.
pub fn trait_method_of_method(tcx: &ctxt,
def_id: ast::DefId) -> Option<ast::DefId> {
let method = match tcx.methods.borrow().find(&def_id) {
pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId)
-> Option<ImplOrTraitItemId> {
let impl_item = match tcx.impl_or_trait_items.borrow().find(&def_id) {
Some(m) => m.clone(),
None => return None,
};
let name = method.ident.name;
match trait_of_method(tcx, def_id) {
let name = match impl_item {
MethodTraitItem(method) => method.ident.name,
};
match trait_of_item(tcx, def_id) {
Some(trait_did) => {
let trait_methods = ty::trait_methods(tcx, trait_did);
trait_methods.iter()
.position(|m| m.ident.name == name)
.map(|idx| ty::trait_method(tcx, trait_did, idx).def_id)
let trait_items = ty::trait_items(tcx, trait_did);
trait_items.iter()
.position(|m| m.ident().name == name)
.map(|idx| ty::trait_item(tcx, trait_did, idx).id())
}
None => None
}

View File

@ -220,9 +220,15 @@ fn get_method_index(tcx: &ty::ctxt,
// methods from them.
let mut method_count = 0;
ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| {
if bound_ref.def_id == trait_ref.def_id { false }
else {
method_count += ty::trait_methods(tcx, bound_ref.def_id).len();
if bound_ref.def_id == trait_ref.def_id {
false
} else {
let trait_items = ty::trait_items(tcx, bound_ref.def_id);
for trait_item in trait_items.iter() {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
}
}
true
}
});
@ -488,11 +494,13 @@ impl<'a> LookupContext<'a> {
ty::populate_implementations_for_trait_if_necessary(self.tcx(), trait_did);
// Look for explicit implementations.
let impl_methods = self.tcx().impl_methods.borrow();
let impl_items = self.tcx().impl_items.borrow();
for impl_infos in self.tcx().trait_impls.borrow().find(&trait_did).iter() {
for impl_did in impl_infos.borrow().iter() {
let methods = impl_methods.get(impl_did);
self.push_candidates_from_impl(*impl_did, methods.as_slice(), true);
let items = impl_items.get(impl_did);
self.push_candidates_from_impl(*impl_did,
items.as_slice(),
true);
}
}
}
@ -520,8 +528,11 @@ impl<'a> LookupContext<'a> {
trait_did: DefId,
closure_did: DefId,
closure_function_type: &ClosureTy) {
let method =
ty::trait_methods(self.tcx(), trait_did).get(0).clone();
let trait_item = ty::trait_items(self.tcx(), trait_did).get(0)
.clone();
let method = match trait_item {
ty::MethodTraitItem(method) => method,
};
let vcx = self.fcx.vtable_context();
let region_params =
@ -701,14 +712,24 @@ impl<'a> LookupContext<'a> {
let this_bound_idx = next_bound_idx;
next_bound_idx += 1;
let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id);
match trait_methods.iter().position(|m| {
m.explicit_self != ty::StaticExplicitSelfCategory &&
m.ident.name == self.m_name }) {
let trait_items = ty::trait_items(tcx, bound_trait_ref.def_id);
match trait_items.iter().position(|ti| {
match *ti {
ty::MethodTraitItem(ref m) => {
m.explicit_self != ty::StaticExplicitSelfCategory &&
m.ident.name == self.m_name
}
}
}) {
Some(pos) => {
let method = trait_methods.get(pos).clone();
let method = match *trait_items.get(pos) {
ty::MethodTraitItem(ref method) => (*method).clone(),
};
match mk_cand(bound_trait_ref, method, pos, this_bound_idx) {
match mk_cand(bound_trait_ref,
method,
pos,
this_bound_idx) {
Some(cand) => {
debug!("pushing inherent candidate for param: {}",
cand.repr(self.tcx()));
@ -733,18 +754,20 @@ impl<'a> LookupContext<'a> {
// metadata if necessary.
ty::populate_implementations_for_type_if_necessary(self.tcx(), did);
let impl_methods = self.tcx().impl_methods.borrow();
let impl_items = self.tcx().impl_items.borrow();
for impl_infos in self.tcx().inherent_impls.borrow().find(&did).iter() {
for impl_did in impl_infos.borrow().iter() {
let methods = impl_methods.get(impl_did);
self.push_candidates_from_impl(*impl_did, methods.as_slice(), false);
let items = impl_items.get(impl_did);
self.push_candidates_from_impl(*impl_did,
items.as_slice(),
false);
}
}
}
fn push_candidates_from_impl(&mut self,
impl_did: DefId,
impl_methods: &[DefId],
impl_items: &[ImplOrTraitItemId],
is_extension: bool) {
let did = if self.report_statics == ReportStaticMethods {
// we only want to report each base trait once
@ -762,13 +785,23 @@ impl<'a> LookupContext<'a> {
debug!("push_candidates_from_impl: {} {}",
token::get_name(self.m_name),
impl_methods.iter().map(|&did| ty::method(self.tcx(), did).ident)
.collect::<Vec<ast::Ident>>()
.repr(self.tcx()));
impl_items.iter()
.map(|&did| {
ty::impl_or_trait_item(self.tcx(),
did.def_id()).ident()
})
.collect::<Vec<ast::Ident>>()
.repr(self.tcx()));
let method = match impl_methods.iter().map(|&did| ty::method(self.tcx(), did))
.find(|m| m.ident.name == self.m_name) {
Some(method) => method,
let method = match impl_items.iter()
.map(|&did| {
ty::impl_or_trait_item(self.tcx(),
did.def_id())
})
.find(|m| {
m.ident().name == self.m_name
}) {
Some(ty::MethodTraitItem(method)) => method,
None => { return; } // No method with the right name.
};
@ -1486,9 +1519,16 @@ impl<'a> LookupContext<'a> {
let did = if self.report_statics == ReportStaticMethods {
// If we're reporting statics, we want to report the trait
// definition if possible, rather than an impl
match ty::trait_method_of_method(self.tcx(), impl_did) {
None => {debug!("(report candidate) No trait method found"); impl_did},
Some(trait_did) => {debug!("(report candidate) Found trait ref"); trait_did}
match ty::trait_item_of_item(self.tcx(), impl_did) {
None => {
debug!("(report candidate) No trait method \
found");
impl_did
}
Some(MethodTraitItemId(trait_did)) => {
debug!("(report candidate) Found trait ref");
trait_did
}
}
} else {
// If it is an instantiated default method, use the original

View File

@ -123,7 +123,7 @@ use std::mem::replace;
use std::rc::Rc;
use std::gc::Gc;
use syntax::abi;
use syntax::ast::{Provided, Required};
use syntax::ast::{ProvidedMethod, RequiredMethod};
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{local_def, PostExpansionMethod};
@ -680,23 +680,27 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
check_bare_fn(ccx, &**decl, &**body, it.id, fn_pty.ty, param_env);
}
ast::ItemImpl(_, ref opt_trait_ref, _, ref ms) => {
ast::ItemImpl(_, ref opt_trait_ref, _, ref impl_items) => {
debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
for m in ms.iter() {
check_method_body(ccx, &impl_pty.generics, &**m);
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(m) => {
check_method_body(ccx, &impl_pty.generics, &*m);
}
}
}
match *opt_trait_ref {
Some(ref ast_trait_ref) => {
let impl_trait_ref =
ty::node_id_to_trait_ref(ccx.tcx, ast_trait_ref.ref_id);
check_impl_methods_against_trait(ccx,
it.span,
ast_trait_ref,
&*impl_trait_ref,
ms.as_slice());
check_impl_items_against_trait(ccx,
it.span,
ast_trait_ref,
&*impl_trait_ref,
impl_items.as_slice());
vtable::resolve_impl(ccx.tcx, it, &impl_pty.generics, &*impl_trait_ref);
}
None => { }
@ -707,11 +711,11 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
for trait_method in (*trait_methods).iter() {
match *trait_method {
Required(..) => {
RequiredMethod(..) => {
// Nothing to do, since required methods don't have
// bodies to check.
}
Provided(m) => {
ProvidedMethod(m) => {
check_method_body(ccx, &trait_def.generics, &*m);
}
}
@ -770,7 +774,9 @@ fn check_method_body(ccx: &CrateCtxt,
item_generics.repr(ccx.tcx),
method.id);
let method_def_id = local_def(method.id);
let method_ty = ty::method(ccx.tcx, method_def_id);
let method_ty = match ty::impl_or_trait_item(ccx.tcx, method_def_id) {
ty::MethodTraitItem(ref method_ty) => (*method_ty).clone(),
};
let method_generics = &method_ty.generics;
let param_env = ty::construct_parameter_environment(ccx.tcx,
@ -787,43 +793,58 @@ fn check_method_body(ccx: &CrateCtxt,
param_env);
}
fn check_impl_methods_against_trait(ccx: &CrateCtxt,
impl_span: Span,
ast_trait_ref: &ast::TraitRef,
impl_trait_ref: &ty::TraitRef,
impl_methods: &[Gc<ast::Method>]) {
fn check_impl_items_against_trait(ccx: &CrateCtxt,
impl_span: Span,
ast_trait_ref: &ast::TraitRef,
impl_trait_ref: &ty::TraitRef,
impl_items: &[ast::ImplItem]) {
// Locate trait methods
let tcx = ccx.tcx;
let trait_methods = ty::trait_methods(tcx, impl_trait_ref.def_id);
let trait_items = ty::trait_items(tcx, impl_trait_ref.def_id);
// Check existing impl methods to see if they are both present in trait
// and compatible with trait signature
for impl_method in impl_methods.iter() {
let impl_method_def_id = local_def(impl_method.id);
let impl_method_ty = ty::method(ccx.tcx, impl_method_def_id);
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(impl_method) => {
let impl_method_def_id = local_def(impl_method.id);
let impl_item_ty = ty::impl_or_trait_item(ccx.tcx,
impl_method_def_id);
// If this is an impl of a trait method, find the corresponding
// method definition in the trait.
let opt_trait_method_ty =
trait_methods.iter().
find(|tm| tm.ident.name == impl_method_ty.ident.name);
match opt_trait_method_ty {
Some(trait_method_ty) => {
compare_impl_method(ccx.tcx,
&*impl_method_ty,
impl_method.span,
impl_method.pe_body().id,
&**trait_method_ty,
&impl_trait_ref.substs);
}
None => {
// This is span_bug as it should have already been caught in resolve.
tcx.sess.span_bug(
impl_method.span,
format!(
"method `{}` is not a member of trait `{}`",
token::get_ident(impl_method_ty.ident),
pprust::path_to_string(&ast_trait_ref.path)).as_slice());
// If this is an impl of a trait method, find the
// corresponding method definition in the trait.
let opt_trait_method_ty =
trait_items.iter()
.find(|ti| {
ti.ident().name == impl_item_ty.ident()
.name
});
match opt_trait_method_ty {
Some(trait_method_ty) => {
match (trait_method_ty, &impl_item_ty) {
(&ty::MethodTraitItem(ref trait_method_ty),
&ty::MethodTraitItem(ref impl_method_ty)) => {
compare_impl_method(ccx.tcx,
&**impl_method_ty,
impl_method.span,
impl_method.pe_body().id,
&**trait_method_ty,
&impl_trait_ref.substs);
}
}
}
None => {
// This is span_bug as it should have already been
// caught in resolve.
tcx.sess.span_bug(
impl_method.span,
format!(
"method `{}` is not a member of trait `{}`",
token::get_ident(impl_item_ty.ident()),
pprust::path_to_string(
&ast_trait_ref.path)).as_slice());
}
}
}
}
}
@ -832,16 +853,26 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
let provided_methods = ty::provided_trait_methods(tcx,
impl_trait_ref.def_id);
let mut missing_methods = Vec::new();
for trait_method in trait_methods.iter() {
let is_implemented =
impl_methods.iter().any(
|m| m.pe_ident().name == trait_method.ident.name);
let is_provided =
provided_methods.iter().any(
|m| m.ident.name == trait_method.ident.name);
if !is_implemented && !is_provided {
missing_methods.push(
format!("`{}`", token::get_ident(trait_method.ident)));
for trait_item in trait_items.iter() {
match *trait_item {
ty::MethodTraitItem(ref trait_method) => {
let is_implemented =
impl_items.iter().any(|ii| {
match *ii {
ast::MethodImplItem(m) => {
m.pe_ident().name == trait_method.ident.name
}
}
});
let is_provided =
provided_methods.iter().any(
|m| m.ident.name == trait_method.ident.name);
if !is_implemented && !is_provided {
missing_methods.push(
format!("`{}`",
token::get_ident(trait_method.ident)));
}
}
}
}
@ -853,7 +884,7 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
}
/**
* Checks that a method from an impl/class conforms to the signature of
* Checks that a method from an impl conforms to the signature of
* the same method as declared in the trait.
*
* # Parameters

View File

@ -20,7 +20,8 @@ use metadata::csearch;
use middle::subst;
use middle::subst::{Substs};
use middle::ty::get;
use middle::ty::{ImplContainer, lookup_item_type};
use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
use middle::ty::{lookup_item_type};
use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil};
use middle::ty::{ty_param, Polytype, ty_ptr};
@ -308,7 +309,7 @@ impl<'a> CoherenceChecker<'a> {
}
}
let impl_methods = self.create_impl_from_item(item);
let impl_items = self.create_impl_from_item(item);
for associated_trait in associated_traits.iter() {
let trait_ref = ty::node_id_to_trait_ref(
@ -337,16 +338,17 @@ impl<'a> CoherenceChecker<'a> {
}
}
tcx.impl_methods.borrow_mut().insert(impl_did, impl_methods);
tcx.impl_items.borrow_mut().insert(impl_did, impl_items);
}
// Creates default method IDs and performs type substitutions for an impl
// and trait pair. Then, for each provided method in the trait, inserts a
// `ProvidedMethodInfo` instance into the `provided_method_sources` map.
fn instantiate_default_methods(&self,
impl_id: DefId,
trait_ref: &ty::TraitRef,
all_methods: &mut Vec<DefId>) {
fn instantiate_default_methods(
&self,
impl_id: DefId,
trait_ref: &ty::TraitRef,
all_impl_items: &mut Vec<ImplOrTraitItemId>) {
let tcx = self.crate_context.tcx;
debug!("instantiate_default_methods(impl_id={:?}, trait_ref={})",
impl_id, trait_ref.repr(tcx));
@ -373,7 +375,7 @@ impl<'a> CoherenceChecker<'a> {
Some(trait_method.def_id)));
debug!("new_method_ty={}", new_method_ty.repr(tcx));
all_methods.push(new_did);
all_impl_items.push(MethodTraitItemId(new_did));
// construct the polytype for the method based on the
// method_ty. it will have all the generics from the
@ -385,7 +387,9 @@ impl<'a> CoherenceChecker<'a> {
debug!("new_polytype={}", new_polytype.repr(tcx));
tcx.tcache.borrow_mut().insert(new_did, new_polytype);
tcx.methods.borrow_mut().insert(new_did, new_method_ty);
tcx.impl_or_trait_items
.borrow_mut()
.insert(new_did, ty::MethodTraitItem(new_method_ty));
// Pair the new synthesized ID up with the
// ID of the method.
@ -576,13 +580,20 @@ impl<'a> CoherenceChecker<'a> {
}
}
// Converts an implementation in the AST to a vector of methods.
fn create_impl_from_item(&self, item: &Item) -> Vec<DefId> {
// Converts an implementation in the AST to a vector of items.
fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
match item.node {
ItemImpl(_, ref trait_refs, _, ref ast_methods) => {
let mut methods: Vec<DefId> = ast_methods.iter().map(|ast_method| {
local_def(ast_method.id)
}).collect();
ItemImpl(_, ref trait_refs, _, ref ast_items) => {
let mut items: Vec<ImplOrTraitItemId> =
ast_items.iter()
.map(|ast_item| {
match *ast_item {
ast::MethodImplItem(ast_method) => {
MethodTraitItemId(
local_def(ast_method.id))
}
}
}).collect();
for trait_ref in trait_refs.iter() {
let ty_trait_ref = ty::node_id_to_trait_ref(
@ -591,10 +602,10 @@ impl<'a> CoherenceChecker<'a> {
self.instantiate_default_methods(local_def(item.id),
&*ty_trait_ref,
&mut methods);
&mut items);
}
methods
items
}
_ => {
self.crate_context.tcx.sess.span_bug(item.span,
@ -614,7 +625,8 @@ impl<'a> CoherenceChecker<'a> {
impls_seen: &mut HashSet<DefId>,
impl_def_id: DefId) {
let tcx = self.crate_context.tcx;
let methods = csearch::get_impl_methods(&tcx.sess.cstore, impl_def_id);
let impl_items = csearch::get_impl_items(&tcx.sess.cstore,
impl_def_id);
// Make sure we don't visit the same implementation multiple times.
if !impls_seen.insert(impl_def_id) {
@ -629,20 +641,27 @@ impl<'a> CoherenceChecker<'a> {
// Do a sanity check.
assert!(associated_traits.is_some());
// Record all the trait methods.
// Record all the trait items.
for trait_ref in associated_traits.iter() {
self.add_trait_impl(trait_ref.def_id, impl_def_id);
}
// For any methods that use a default implementation, add them to
// the map. This is a bit unfortunate.
for &method_def_id in methods.iter() {
for &source in ty::method(tcx, method_def_id).provided_source.iter() {
tcx.provided_method_sources.borrow_mut().insert(method_def_id, source);
for item_def_id in impl_items.iter() {
let impl_item = ty::impl_or_trait_item(tcx, item_def_id.def_id());
match impl_item {
ty::MethodTraitItem(ref method) => {
for &source in method.provided_source.iter() {
tcx.provided_method_sources
.borrow_mut()
.insert(item_def_id.def_id(), source);
}
}
}
}
tcx.impl_methods.borrow_mut().insert(impl_def_id, methods);
tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items);
}
// Adds implementations and traits from external crates to the coherence
@ -669,28 +688,31 @@ impl<'a> CoherenceChecker<'a> {
Some(id) => id, None => { return }
};
let impl_methods = tcx.impl_methods.borrow();
let impl_items = tcx.impl_items.borrow();
let trait_impls = match tcx.trait_impls.borrow().find_copy(&drop_trait) {
None => return, // No types with (new-style) dtors present.
Some(found_impls) => found_impls
};
for &impl_did in trait_impls.borrow().iter() {
let methods = impl_methods.get(&impl_did);
if methods.len() < 1 {
let items = impl_items.get(&impl_did);
if items.len() < 1 {
// We'll error out later. For now, just don't ICE.
continue;
}
let method_def_id = *methods.get(0);
let method_def_id = *items.get(0);
let self_type = self.get_self_type_for_implementation(impl_did);
match ty::get(self_type.ty).sty {
ty::ty_enum(type_def_id, _) |
ty::ty_struct(type_def_id, _) |
ty::ty_unboxed_closure(type_def_id, _) => {
tcx.destructor_for_type.borrow_mut().insert(type_def_id,
method_def_id);
tcx.destructors.borrow_mut().insert(method_def_id);
tcx.destructor_for_type
.borrow_mut()
.insert(type_def_id, method_def_id.def_id());
tcx.destructors
.borrow_mut()
.insert(method_def_id.def_id());
}
_ => {
// Destructors only work on nominal types.

View File

@ -37,7 +37,7 @@ use middle::lang_items::SizedTraitLangItem;
use middle::resolve_lifetime;
use middle::subst;
use middle::subst::{Substs};
use middle::ty::{ImplContainer, MethodContainer, TraitContainer};
use middle::ty::{ImplContainer, ImplOrTraitItemContainer, TraitContainer};
use middle::ty::{Polytype};
use middle::ty;
use middle::ty_fold::TypeFolder;
@ -200,64 +200,74 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
match tcx.map.get(trait_id) {
ast_map::NodeItem(item) => {
match item.node {
ast::ItemTrait(_, _, _, ref ms) => {
ast::ItemTrait(_, _, _, ref trait_items) => {
// For each method, construct a suitable ty::Method and
// store it into the `tcx.methods` table:
for m in ms.iter() {
let ty_method = Rc::new(match m {
&ast::Required(ref m) => {
ty_method_of_trait_method(
ccx,
trait_id,
&trait_def.generics,
&m.id,
&m.ident,
&m.explicit_self,
m.abi,
&m.generics,
&m.fn_style,
&*m.decl)
}
// store it into the `tcx.impl_or_trait_items` table:
for trait_item in trait_items.iter() {
match *trait_item {
ast::RequiredMethod(_) |
ast::ProvidedMethod(_) => {
let ty_method = Rc::new(match *trait_item {
ast::RequiredMethod(ref m) => {
ty_method_of_trait_method(
ccx,
trait_id,
&trait_def.generics,
&m.id,
&m.ident,
&m.explicit_self,
m.abi,
&m.generics,
&m.fn_style,
&*m.decl)
}
ast::ProvidedMethod(ref m) => {
ty_method_of_trait_method(
ccx,
trait_id,
&trait_def.generics,
&m.id,
&m.pe_ident(),
m.pe_explicit_self(),
m.pe_abi(),
m.pe_generics(),
&m.pe_fn_style(),
&*m.pe_fn_decl())
}
});
&ast::Provided(ref m) => {
ty_method_of_trait_method(
ccx,
trait_id,
&trait_def.generics,
&m.id,
&m.pe_ident(),
m.pe_explicit_self(),
m.pe_abi(),
m.pe_generics(),
&m.pe_fn_style(),
&*m.pe_fn_decl())
}
});
if ty_method.explicit_self ==
ty::StaticExplicitSelfCategory {
make_static_method_ty(ccx, &*ty_method);
}
if ty_method.explicit_self ==
ty::StaticExplicitSelfCategory {
make_static_method_ty(ccx, &*ty_method);
tcx.impl_or_trait_items
.borrow_mut()
.insert(ty_method.def_id,
ty::MethodTraitItem(ty_method));
}
}
tcx.methods.borrow_mut().insert(ty_method.def_id,
ty_method);
}
// Add an entry mapping
let method_def_ids = Rc::new(ms.iter().map(|m| {
match m {
&ast::Required(ref ty_method) => {
local_def(ty_method.id)
let trait_item_def_ids =
Rc::new(trait_items.iter()
.map(|ti| {
match *ti {
ast::RequiredMethod(ref ty_method) => {
ty::MethodTraitItemId(local_def(
ty_method.id))
}
ast::ProvidedMethod(ref method) => {
ty::MethodTraitItemId(local_def(
method.id))
}
}
&ast::Provided(ref method) => {
local_def(method.id)
}
}
}).collect());
}).collect());
let trait_def_id = local_def(trait_id);
tcx.trait_method_def_ids.borrow_mut()
.insert(trait_def_id, method_def_ids);
tcx.trait_item_def_ids.borrow_mut()
.insert(trait_def_id, trait_item_def_ids);
}
_ => {} // Ignore things that aren't traits.
}
@ -346,12 +356,11 @@ pub fn convert_field(ccx: &CrateCtxt,
}
fn convert_methods(ccx: &CrateCtxt,
container: MethodContainer,
container: ImplOrTraitItemContainer,
ms: &[Gc<ast::Method>],
untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics,
rcvr_visibility: ast::Visibility)
{
rcvr_visibility: ast::Visibility) {
let tcx = ccx.tcx;
let mut seen_methods = HashSet::new();
for m in ms.iter() {
@ -379,11 +388,13 @@ fn convert_methods(ccx: &CrateCtxt,
write_ty_to_tcx(tcx, m.id, fty);
tcx.methods.borrow_mut().insert(mty.def_id, mty);
tcx.impl_or_trait_items
.borrow_mut()
.insert(mty.def_id, ty::MethodTraitItem(mty));
}
fn ty_of_method(ccx: &CrateCtxt,
container: MethodContainer,
container: ImplOrTraitItemContainer,
m: &ast::Method,
untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics,
@ -459,7 +470,10 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
enum_definition.variants.as_slice(),
generics);
},
ast::ItemImpl(ref generics, ref opt_trait_ref, selfty, ref ms) => {
ast::ItemImpl(ref generics,
ref opt_trait_ref,
selfty,
ref impl_items) => {
let ty_generics = ty_generics_for_type(ccx, generics);
let selfty = ccx.to_ty(&ExplicitRscope, &*selfty);
write_ty_to_tcx(tcx, it.id, selfty);
@ -480,16 +494,22 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
it.vis
};
for method in ms.iter() {
check_method_self_type(ccx,
&BindingRscope::new(method.id),
selfty,
method.pe_explicit_self())
let mut methods = Vec::new();
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(ref method) => {
check_method_self_type(ccx,
&BindingRscope::new(method.id),
selfty,
method.pe_explicit_self());
methods.push(*method);
}
}
}
convert_methods(ccx,
ImplContainer(local_def(it.id)),
ms.as_slice(),
methods.as_slice(),
selfty,
&ty_generics,
parent_visibility);
@ -507,14 +527,14 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
0,
local_def(it.id));
match *trait_method {
ast::Required(ref type_method) => {
ast::RequiredMethod(ref type_method) => {
let rscope = BindingRscope::new(type_method.id);
check_method_self_type(ccx,
&rscope,
self_type,
&type_method.explicit_self)
}
ast::Provided(ref method) => {
ast::ProvidedMethod(ref method) => {
check_method_self_type(ccx,
&BindingRscope::new(method.id),
self_type,

View File

@ -305,7 +305,8 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
},
_ => None
},
ast_map::NodeMethod(..) => {
ast_map::NodeImplItem(..) |
ast_map::NodeTraitItem(..) => {
Some(FreeRegionsFromSameFn::new(fr1, fr2, scope_id))
},
_ => None
@ -699,9 +700,17 @@ impl<'a> ErrorReporting for InferCtxt<'a> {
_ => None
}
}
ast_map::NodeMethod(ref m) => {
Some((m.pe_fn_decl(), m.pe_generics(), m.pe_fn_style(),
m.pe_ident(), Some(m.pe_explicit_self().node), m.span))
ast_map::NodeImplItem(ref item) => {
match **item {
ast::MethodImplItem(ref m) => {
Some((m.pe_fn_decl(),
m.pe_generics(),
m.pe_fn_style(),
m.pe_ident(),
Some(m.pe_explicit_self().node),
m.span))
}
}
},
_ => None
},
@ -1454,10 +1463,14 @@ fn lifetimes_in_scope(tcx: &ty::ctxt,
},
_ => None
},
ast_map::NodeMethod(m) => {
taken.push_all(m.pe_generics().lifetimes.as_slice());
Some(m.id)
},
ast_map::NodeImplItem(ii) => {
match *ii {
ast::MethodImplItem(m) => {
taken.push_all(m.pe_generics().lifetimes.as_slice());
Some(m.id)
}
}
}
_ => None
},
None => None

View File

@ -515,10 +515,14 @@ impl<'a> Visitor<()> for ConstraintContext<'a> {
}
ast::ItemTrait(..) => {
let methods = ty::trait_methods(tcx, did);
for method in methods.iter() {
self.add_constraints_from_sig(
&method.fty.sig, self.covariant);
let trait_items = ty::trait_items(tcx, did);
for trait_item in trait_items.iter() {
match *trait_item {
ty::MethodTraitItem(ref method) => {
self.add_constraints_from_sig(&method.fty.sig,
self.covariant);
}
}
}
}
@ -609,8 +613,8 @@ impl<'a> ConstraintContext<'a> {
_ => cannot_happen!(),
}
}
ast_map::NodeTraitMethod(..) => is_inferred = false,
ast_map::NodeMethod(_) => is_inferred = false,
ast_map::NodeTraitItem(..) => is_inferred = false,
ast_map::NodeImplItem(..) => is_inferred = false,
_ => cannot_happen!(),
}

View File

@ -762,8 +762,8 @@ impl Repr for ast::DefId {
match tcx.map.find(self.node) {
Some(ast_map::NodeItem(..)) |
Some(ast_map::NodeForeignItem(..)) |
Some(ast_map::NodeMethod(..)) |
Some(ast_map::NodeTraitMethod(..)) |
Some(ast_map::NodeImplItem(..)) |
Some(ast_map::NodeTraitItem(..)) |
Some(ast_map::NodeVariant(..)) |
Some(ast_map::NodeStructCtor(..)) => {
return format!(

View File

@ -480,8 +480,8 @@ mod svh_visitor {
SawTyMethod.hash(self.st); visit::walk_ty_method(self, t, e)
}
fn visit_trait_method(&mut self, t: &TraitMethod, e: E) {
SawTraitMethod.hash(self.st); visit::walk_trait_method(self, t, e)
fn visit_trait_item(&mut self, t: &TraitItem, e: E) {
SawTraitMethod.hash(self.st); visit::walk_trait_item(self, t, e)
}
fn visit_struct_field(&mut self, s: &StructField, e: E) {

View File

@ -157,13 +157,13 @@ pub fn record_extern_fqn(cx: &core::DocContext,
pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
let def = ty::lookup_trait_def(tcx, did);
let methods = ty::trait_methods(tcx, did).clean();
let trait_items = ty::trait_items(tcx, did).clean();
let provided = ty::provided_trait_methods(tcx, did);
let mut methods = methods.move_iter().map(|meth| {
if provided.iter().any(|a| a.def_id == meth.def_id) {
clean::Provided(meth)
let mut items = trait_items.move_iter().map(|trait_item| {
if provided.iter().any(|a| a.def_id == trait_item.def_id) {
clean::ProvidedMethod(trait_item)
} else {
clean::Required(meth)
clean::RequiredMethod(trait_item)
}
});
let supertraits = ty::trait_supertraits(tcx, did);
@ -176,7 +176,7 @@ pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait {
clean::Trait {
generics: (&def.generics, subst::TypeSpace).clean(),
methods: methods.collect(),
items: items.collect(),
parents: parents.collect()
}
}
@ -303,27 +303,33 @@ fn build_impl(cx: &core::DocContext,
let attrs = load_attrs(tcx, did);
let ty = ty::lookup_item_type(tcx, did);
let methods = csearch::get_impl_methods(&tcx.sess.cstore,
did).iter().filter_map(|did| {
let method = ty::method(tcx, *did);
if method.vis != ast::Public && associated_trait.is_none() {
return None
}
let mut item = ty::method(tcx, *did).clean();
item.inner = match item.inner.clone() {
clean::TyMethodItem(clean::TyMethod {
fn_style, decl, self_, generics
}) => {
clean::MethodItem(clean::Method {
fn_style: fn_style,
decl: decl,
self_: self_,
generics: generics,
})
let trait_items = csearch::get_impl_items(&tcx.sess.cstore, did)
.iter()
.filter_map(|did| {
let did = did.def_id();
let impl_item = ty::impl_or_trait_item(tcx, did);
match impl_item {
ty::MethodTraitItem(method) => {
if method.vis != ast::Public && associated_trait.is_none() {
return None
}
let mut item = method.clean();
item.inner = match item.inner.clone() {
clean::TyMethodItem(clean::TyMethod {
fn_style, decl, self_, generics
}) => {
clean::MethodItem(clean::Method {
fn_style: fn_style,
decl: decl,
self_: self_,
generics: generics,
})
}
_ => fail!("not a tymethod"),
};
Some(item)
}
_ => fail!("not a tymethod"),
};
Some(item)
}
}).collect();
return Some(clean::Item {
inner: clean::ImplItem(clean::Impl {
@ -336,7 +342,7 @@ fn build_impl(cx: &core::DocContext,
}),
for_: ty.ty.clean(),
generics: (&ty.generics, subst::TypeSpace).clean(),
methods: methods,
items: trait_items,
}),
source: clean::Span::empty(),
name: None,

View File

@ -907,7 +907,7 @@ impl Clean<RetStyle> for ast::RetStyle {
#[deriving(Clone, Encodable, Decodable)]
pub struct Trait {
pub methods: Vec<TraitMethod>,
pub items: Vec<TraitItem>,
pub generics: Generics,
pub parents: Vec<Type>,
}
@ -922,7 +922,7 @@ impl Clean<Item> for doctree::Trait {
visibility: self.vis.clean(),
stability: self.stab.clean(),
inner: TraitItem(Trait {
methods: self.methods.clean(),
items: self.items.clean(),
generics: self.generics.clean(),
parents: self.parents.clean(),
}),
@ -937,37 +937,50 @@ impl Clean<Type> for ast::TraitRef {
}
#[deriving(Clone, Encodable, Decodable)]
pub enum TraitMethod {
Required(Item),
Provided(Item),
pub enum TraitItem {
RequiredMethod(Item),
ProvidedMethod(Item),
}
impl TraitMethod {
impl TraitItem {
pub fn is_req(&self) -> bool {
match self {
&Required(..) => true,
&RequiredMethod(..) => true,
_ => false,
}
}
pub fn is_def(&self) -> bool {
match self {
&Provided(..) => true,
&ProvidedMethod(..) => true,
_ => false,
}
}
pub fn item<'a>(&'a self) -> &'a Item {
match *self {
Required(ref item) => item,
Provided(ref item) => item,
RequiredMethod(ref item) => item,
ProvidedMethod(ref item) => item,
}
}
}
impl Clean<TraitMethod> for ast::TraitMethod {
fn clean(&self) -> TraitMethod {
impl Clean<TraitItem> for ast::TraitItem {
fn clean(&self) -> TraitItem {
match self {
&ast::Required(ref t) => Required(t.clean()),
&ast::Provided(ref t) => Provided(t.clean()),
&ast::RequiredMethod(ref t) => RequiredMethod(t.clean()),
&ast::ProvidedMethod(ref t) => ProvidedMethod(t.clean()),
}
}
}
#[deriving(Clone, Encodable, Decodable)]
pub enum ImplItem {
MethodImplItem(Item),
}
impl Clean<ImplItem> for ast::ImplItem {
fn clean(&self) -> ImplItem {
match self {
&ast::MethodImplItem(ref t) => MethodImplItem(t.clean()),
}
}
}
@ -1019,6 +1032,14 @@ impl Clean<Item> for ty::Method {
}
}
impl Clean<Item> for ty::ImplOrTraitItem {
fn clean(&self) -> Item {
match *self {
ty::MethodTraitItem(ref mti) => mti.clean(),
}
}
}
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
/// it does not preserve mutability or boxes.
@ -1714,7 +1735,7 @@ pub struct Impl {
pub generics: Generics,
pub trait_: Option<Type>,
pub for_: Type,
pub methods: Vec<Item>,
pub items: Vec<Item>,
pub derived: bool,
}
@ -1735,7 +1756,11 @@ impl Clean<Item> for doctree::Impl {
generics: self.generics.clean(),
trait_: self.trait_.clean(),
for_: self.for_.clean(),
methods: self.methods.clean(),
items: self.items.clean().move_iter().map(|ti| {
match ti {
MethodImplItem(i) => i,
}
}).collect(),
derived: detect_derived(self.attrs.as_slice()),
}),
}

View File

@ -154,7 +154,7 @@ pub struct Static {
pub struct Trait {
pub name: Ident,
pub methods: Vec<ast::TraitMethod>, //should be TraitMethod
pub items: Vec<ast::TraitItem>, //should be TraitItem
pub generics: ast::Generics,
pub parents: Vec<ast::TraitRef>,
pub attrs: Vec<ast::Attribute>,
@ -168,7 +168,7 @@ pub struct Impl {
pub generics: ast::Generics,
pub trait_: Option<ast::TraitRef>,
pub for_: ast::P<ast::Ty>,
pub methods: Vec<Gc<ast::Method>>,
pub items: Vec<ast::ImplItem>,
pub attrs: Vec<ast::Attribute>,
pub where: Span,
pub vis: ast::Visibility,

View File

@ -40,29 +40,31 @@ pub trait DocFolder {
EnumItem(i)
},
TraitItem(mut i) => {
fn vtrm<T: DocFolder>(this: &mut T, trm: TraitMethod) -> Option<TraitMethod> {
fn vtrm<T: DocFolder>(this: &mut T, trm: TraitItem)
-> Option<TraitItem> {
match trm {
Required(it) => {
RequiredMethod(it) => {
match this.fold_item(it) {
Some(x) => return Some(Required(x)),
Some(x) => return Some(RequiredMethod(x)),
None => return None,
}
},
Provided(it) => {
ProvidedMethod(it) => {
match this.fold_item(it) {
Some(x) => return Some(Provided(x)),
Some(x) => return Some(ProvidedMethod(x)),
None => return None,
}
},
}
}
let mut foo = Vec::new(); swap(&mut foo, &mut i.methods);
i.methods.extend(foo.move_iter().filter_map(|x| vtrm(self, x)));
let mut foo = Vec::new(); swap(&mut foo, &mut i.items);
i.items.extend(foo.move_iter().filter_map(|x| vtrm(self, x)));
TraitItem(i)
},
ImplItem(mut i) => {
let mut foo = Vec::new(); swap(&mut foo, &mut i.methods);
i.methods.extend(foo.move_iter().filter_map(|x| self.fold_item(x)));
let mut foo = Vec::new(); swap(&mut foo, &mut i.items);
i.items.extend(foo.move_iter()
.filter_map(|x| self.fold_item(x)));
ImplItem(i)
},
VariantItem(i) => {

View File

@ -1624,10 +1624,24 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
it.name.get_ref().as_slice(),
t.generics,
parents));
let required = t.methods.iter().filter(|m| m.is_req()).collect::<Vec<&clean::TraitMethod>>();
let provided = t.methods.iter().filter(|m| !m.is_req()).collect::<Vec<&clean::TraitMethod>>();
let required = t.items.iter()
.filter(|m| {
match **m {
clean::RequiredMethod(_) => true,
_ => false,
}
})
.collect::<Vec<&clean::TraitItem>>();
let provided = t.items.iter()
.filter(|m| {
match **m {
clean::ProvidedMethod(_) => true,
_ => false,
}
})
.collect::<Vec<&clean::TraitItem>>();
if t.methods.len() == 0 {
if t.items.len() == 0 {
try!(write!(w, "{{ }}"));
} else {
try!(write!(w, "{{\n"));
@ -1651,7 +1665,8 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
// Trait documentation
try!(document(w, it));
fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result {
fn trait_item(w: &mut fmt::Formatter, m: &clean::TraitItem)
-> fmt::Result {
try!(write!(w, "<h3 id='{}.{}' class='method'>{}<code>",
shortty(m.item()),
*m.item().name.get_ref(),
@ -1669,7 +1684,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
<div class='methods'>
"));
for m in required.iter() {
try!(meth(w, *m));
try!(trait_item(w, *m));
}
try!(write!(w, "</div>"));
}
@ -1679,7 +1694,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
<div class='methods'>
"));
for m in provided.iter() {
try!(meth(w, *m));
try!(trait_item(w, *m));
}
try!(write!(w, "</div>"));
}
@ -1991,8 +2006,8 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
None => {}
}
fn docmeth(w: &mut fmt::Formatter, item: &clean::Item,
dox: bool) -> fmt::Result {
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, dox: bool)
-> fmt::Result {
try!(write!(w, "<h4 id='method.{}' class='method'>{}<code>",
*item.name.get_ref(),
ConciseStability(&item.stability)));
@ -2008,21 +2023,21 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
}
try!(write!(w, "<div class='impl-methods'>"));
for meth in i.impl_.methods.iter() {
try!(docmeth(w, meth, true));
for trait_item in i.impl_.items.iter() {
try!(doctraititem(w, trait_item, true));
}
fn render_default_methods(w: &mut fmt::Formatter,
t: &clean::Trait,
i: &clean::Impl) -> fmt::Result {
for method in t.methods.iter() {
let n = method.item().name.clone();
match i.methods.iter().find(|m| { m.name == n }) {
for trait_item in t.items.iter() {
let n = trait_item.item().name.clone();
match i.items.iter().find(|m| { m.name == n }) {
Some(..) => continue,
None => {}
}
try!(docmeth(w, method.item(), false));
try!(doctraititem(w, trait_item.item(), false));
}
Ok(())
}

View File

@ -202,7 +202,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
clean::ModuleItem(ref m)
if m.items.len() == 0 &&
i.doc_value().is_none() => None,
clean::ImplItem(ref i) if i.methods.len() == 0 => None,
clean::ImplItem(ref i) if i.items.len() == 0 => None,
_ => {
self.retained.insert(i.def_id.node);
Some(i)

View File

@ -21,7 +21,7 @@ use syntax::attr::{Deprecated, Experimental, Unstable, Stable, Frozen, Locked};
use syntax::ast::Public;
use clean::{Crate, Item, ModuleItem, Module, StructItem, Struct, EnumItem, Enum};
use clean::{ImplItem, Impl, TraitItem, Trait, TraitMethod, Provided, Required};
use clean::{ImplItem, Impl, Trait, TraitItem, ProvidedMethod, RequiredMethod};
use clean::{ViewItemItem, PrimitiveItem};
#[deriving(Zero, Encodable, Decodable, PartialEq, Eq)]
@ -110,7 +110,7 @@ fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) {
match item.inner {
// Require explicit `pub` to be visible
StructItem(Struct { fields: ref subitems, .. }) |
ImplItem(Impl { methods: ref subitems, trait_: None, .. }) => {
ImplItem(Impl { items: ref subitems, trait_: None, .. }) => {
let subcounts = subitems.iter().filter(|i| visible(*i))
.map(summarize_item)
.map(|s| s.val0())
@ -124,16 +124,21 @@ fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) {
.sum();
(item_counts + subcounts, None)
}
TraitItem(Trait { methods: ref methods, .. }) => {
fn extract_item<'a>(meth: &'a TraitMethod) -> &'a Item {
match *meth {
Provided(ref item) | Required(ref item) => item
TraitItem(Trait {
items: ref trait_items,
..
}) => {
fn extract_item<'a>(trait_item: &'a TraitItem) -> &'a Item {
match *trait_item {
ProvidedMethod(ref item) |
RequiredMethod(ref item) => item
}
}
let subcounts = methods.iter().map(extract_item)
.map(summarize_item)
.map(|s| s.val0())
.sum();
let subcounts = trait_items.iter()
.map(extract_item)
.map(summarize_item)
.map(|s| s.val0())
.sum();
(item_counts + subcounts, None)
}
ModuleItem(Module { items: ref items, .. }) => {

View File

@ -317,10 +317,10 @@ impl<'a> RustdocVisitor<'a> {
};
om.statics.push(s);
},
ast::ItemTrait(ref gen, _, ref tr, ref met) => {
ast::ItemTrait(ref gen, _, ref tr, ref items) => {
let t = Trait {
name: item.ident,
methods: met.iter().map(|x| (*x).clone()).collect(),
items: items.iter().map(|x| (*x).clone()).collect(),
generics: gen.clone(),
parents: tr.iter().map(|x| (*x).clone()).collect(),
id: item.id,
@ -331,12 +331,12 @@ impl<'a> RustdocVisitor<'a> {
};
om.traits.push(t);
},
ast::ItemImpl(ref gen, ref tr, ty, ref meths) => {
ast::ItemImpl(ref gen, ref tr, ty, ref items) => {
let i = Impl {
generics: gen.clone(),
trait_: tr.clone(),
for_: ty,
methods: meths.iter().map(|x| *x).collect(),
items: items.iter().map(|x| *x).collect(),
attrs: item.attrs.iter().map(|x| *x).collect(),
id: item.id,
where: item.span,

View File

@ -767,9 +767,14 @@ pub struct TypeMethod {
/// doesn't have an implementation, just a signature) or provided (meaning it
/// has a default implementation).
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum TraitMethod {
Required(TypeMethod),
Provided(Gc<Method>),
pub enum TraitItem {
RequiredMethod(TypeMethod),
ProvidedMethod(Gc<Method>),
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum ImplItem {
MethodImplItem(Gc<Method>),
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
@ -1273,11 +1278,11 @@ pub enum Item_ {
Option<TyParamBound>, // (optional) default bound not required for Self.
// Currently, only Sized makes sense here.
Vec<TraitRef> ,
Vec<TraitMethod>),
Vec<TraitItem>),
ItemImpl(Generics,
Option<TraitRef>, // (optional) trait this impl implements
P<Ty>, // self
Vec<Gc<Method>>),
Vec<ImplItem>),
/// A macro invocation (which includes macro definition)
ItemMac(Mac),
}
@ -1311,10 +1316,16 @@ pub enum UnboxedClosureKind {
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum InlinedItem {
IIItem(Gc<Item>),
IIMethod(DefId /* impl id */, bool /* is provided */, Gc<Method>),
IITraitItem(DefId /* impl id */, InlinedTraitItem),
IIForeign(Gc<ForeignItem>),
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum InlinedTraitItem {
ProvidedInlinedTraitItem(Gc<Method>),
RequiredInlinedTraitItem(Gc<Method>),
}
#[cfg(test)]
mod test {
use serialize::json;

View File

@ -60,9 +60,9 @@ impl MaybeFnLike for ast::Item {
}
}
impl MaybeFnLike for ast::TraitMethod {
impl MaybeFnLike for ast::TraitItem {
fn is_fn_like(&self) -> bool {
match *self { ast::Provided(_) => true, _ => false, }
match *self { ast::ProvidedMethod(_) => true, _ => false, }
}
}
@ -97,9 +97,9 @@ impl Code {
match node {
ast_map::NodeItem(item) if item.is_fn_like() =>
Some(FnLikeCode(new(node))),
ast_map::NodeTraitMethod(tm) if tm.is_fn_like() =>
ast_map::NodeTraitItem(tm) if tm.is_fn_like() =>
Some(FnLikeCode(new(node))),
ast_map::NodeMethod(_) =>
ast_map::NodeImplItem(_) =>
Some(FnLikeCode(new(node))),
ast_map::NodeExpr(e) if e.is_fn_like() =>
Some(FnLikeCode(new(node))),
@ -200,11 +200,15 @@ impl FnLikeNode {
}),
_ => fail!("item FnLikeNode that is not fn-like"),
},
ast_map::NodeTraitMethod(ref t) => match **t {
ast::Provided(ref m) => method(&**m),
ast_map::NodeTraitItem(ref t) => match **t {
ast::ProvidedMethod(ref m) => method(&**m),
_ => fail!("trait method FnLikeNode that is not fn-like"),
},
ast_map::NodeMethod(ref m) => method(&**m),
ast_map::NodeImplItem(ref ii) => {
match **ii {
ast::MethodImplItem(ref m) => method(&**m),
}
}
ast_map::NodeExpr(ref e) => match e.node {
ast::ExprFnBlock(_, ref decl, ref block) =>
closure(ClosureParts::new(*decl, *block, e.id, e.span)),

View File

@ -99,8 +99,8 @@ pub fn path_to_string<PI: Iterator<PathElem>>(mut path: PI) -> String {
pub enum Node {
NodeItem(Gc<Item>),
NodeForeignItem(Gc<ForeignItem>),
NodeTraitMethod(Gc<TraitMethod>),
NodeMethod(Gc<Method>),
NodeTraitItem(Gc<TraitItem>),
NodeImplItem(Gc<ImplItem>),
NodeVariant(P<Variant>),
NodeExpr(Gc<Expr>),
NodeStmt(Gc<Stmt>),
@ -125,8 +125,8 @@ enum MapEntry {
/// All the node types, with a parent ID.
EntryItem(NodeId, Gc<Item>),
EntryForeignItem(NodeId, Gc<ForeignItem>),
EntryTraitMethod(NodeId, Gc<TraitMethod>),
EntryMethod(NodeId, Gc<Method>),
EntryTraitItem(NodeId, Gc<TraitItem>),
EntryImplItem(NodeId, Gc<ImplItem>),
EntryVariant(NodeId, P<Variant>),
EntryExpr(NodeId, Gc<Expr>),
EntryStmt(NodeId, Gc<Stmt>),
@ -144,7 +144,7 @@ enum MapEntry {
struct InlinedParent {
path: Vec<PathElem> ,
/// Required by NodeTraitMethod and NodeMethod.
/// RequiredMethod by NodeTraitItem and NodeImplItem.
def_id: DefId
}
@ -153,8 +153,8 @@ impl MapEntry {
Some(match *self {
EntryItem(id, _) => id,
EntryForeignItem(id, _) => id,
EntryTraitMethod(id, _) => id,
EntryMethod(id, _) => id,
EntryTraitItem(id, _) => id,
EntryImplItem(id, _) => id,
EntryVariant(id, _) => id,
EntryExpr(id, _) => id,
EntryStmt(id, _) => id,
@ -172,8 +172,8 @@ impl MapEntry {
Some(match *self {
EntryItem(_, p) => NodeItem(p),
EntryForeignItem(_, p) => NodeForeignItem(p),
EntryTraitMethod(_, p) => NodeTraitMethod(p),
EntryMethod(_, p) => NodeMethod(p),
EntryTraitItem(_, p) => NodeTraitItem(p),
EntryImplItem(_, p) => NodeImplItem(p),
EntryVariant(_, p) => NodeVariant(p),
EntryExpr(_, p) => NodeExpr(p),
EntryStmt(_, p) => NodeStmt(p),
@ -324,13 +324,23 @@ impl Map {
}
}
NodeForeignItem(i) => PathName(i.ident.name),
NodeMethod(m) => match m.node {
MethDecl(ident, _, _, _, _, _, _, _) => PathName(ident.name),
MethMac(_) => fail!("no path elem for {:?}", node)
NodeImplItem(ii) => {
match *ii {
MethodImplItem(ref m) => {
match m.node {
MethDecl(ident, _, _, _, _, _, _, _) => {
PathName(ident.name)
}
MethMac(_) => {
fail!("no path elem for {:?}", node)
}
}
}
}
},
NodeTraitMethod(tm) => match *tm {
Required(ref m) => PathName(m.ident.name),
Provided(m) => match m.node {
NodeTraitItem(tm) => match *tm {
RequiredMethod(ref m) => PathName(m.ident.name),
ProvidedMethod(m) => match m.node {
MethDecl(ident, _, _, _, _, _, _, _) => {
PathName(ident.name)
}
@ -393,11 +403,15 @@ impl Map {
let attrs = match node {
NodeItem(ref i) => Some(i.attrs.as_slice()),
NodeForeignItem(ref fi) => Some(fi.attrs.as_slice()),
NodeTraitMethod(ref tm) => match **tm {
Required(ref type_m) => Some(type_m.attrs.as_slice()),
Provided(ref m) => Some(m.attrs.as_slice())
NodeTraitItem(ref tm) => match **tm {
RequiredMethod(ref type_m) => Some(type_m.attrs.as_slice()),
ProvidedMethod(ref m) => Some(m.attrs.as_slice())
},
NodeMethod(ref m) => Some(m.attrs.as_slice()),
NodeImplItem(ref ii) => {
match **ii {
MethodImplItem(ref m) => Some(m.attrs.as_slice()),
}
}
NodeVariant(ref v) => Some(v.node.attrs.as_slice()),
// unit/tuple structs take the attributes straight from
// the struct definition.
@ -428,13 +442,17 @@ impl Map {
let sp = match self.find(id) {
Some(NodeItem(item)) => item.span,
Some(NodeForeignItem(foreign_item)) => foreign_item.span,
Some(NodeTraitMethod(trait_method)) => {
Some(NodeTraitItem(trait_method)) => {
match *trait_method {
Required(ref type_method) => type_method.span,
Provided(ref method) => method.span,
RequiredMethod(ref type_method) => type_method.span,
ProvidedMethod(ref method) => method.span,
}
}
Some(NodeImplItem(ref impl_item)) => {
match **impl_item {
MethodImplItem(ref method) => method.span,
}
}
Some(NodeMethod(method)) => method.span,
Some(NodeVariant(variant)) => variant.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
@ -532,8 +550,8 @@ impl<'a,S:Str> Iterator<NodeId> for NodesMatchingSuffix<'a,S> {
let (p, name) = match self.map.find_entry(idx) {
Some(EntryItem(p, n)) => (p, n.name()),
Some(EntryForeignItem(p, n)) => (p, n.name()),
Some(EntryTraitMethod(p, n)) => (p, n.name()),
Some(EntryMethod(p, n)) => (p, n.name()),
Some(EntryTraitItem(p, n)) => (p, n.name()),
Some(EntryImplItem(p, n)) => (p, n.name()),
Some(EntryVariant(p, n)) => (p, n.name()),
_ => continue,
};
@ -553,11 +571,18 @@ impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() }
impl Named for Item { fn name(&self) -> Name { self.ident.name } }
impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
impl Named for Variant_ { fn name(&self) -> Name { self.name.name } }
impl Named for TraitMethod {
impl Named for TraitItem {
fn name(&self) -> Name {
match *self {
Required(ref tm) => tm.ident.name,
Provided(m) => m.name(),
RequiredMethod(ref tm) => tm.ident.name,
ProvidedMethod(m) => m.name(),
}
}
}
impl Named for ImplItem {
fn name(&self) -> Name {
match *self {
MethodImplItem(ref m) => m.name(),
}
}
}
@ -616,9 +641,15 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
assert_eq!(self.parent, i.id);
match i.node {
ItemImpl(_, _, _, ref ms) => {
for &m in ms.iter() {
self.insert(m.id, EntryMethod(self.parent, m));
ItemImpl(_, _, _, ref impl_items) => {
for impl_item in impl_items.iter() {
match *impl_item {
MethodImplItem(m) => {
self.insert(m.id,
EntryImplItem(self.parent,
box(GC) *impl_item));
}
}
}
}
ItemEnum(ref enum_definition, _) => {
@ -649,13 +680,13 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
for tm in methods.iter() {
match *tm {
Required(ref m) => {
self.insert(m.id, EntryTraitMethod(self.parent,
RequiredMethod(ref m) => {
self.insert(m.id, EntryTraitItem(self.parent,
box(GC) (*tm).clone()));
}
Provided(m) => {
self.insert(m.id, EntryTraitMethod(self.parent,
box(GC) Provided(m)));
ProvidedMethod(m) => {
self.insert(m.id, EntryTraitItem(self.parent,
box(GC) ProvidedMethod(m)));
}
}
}
@ -798,13 +829,18 @@ pub fn map_decoded_item<F: FoldOps>(map: &Map,
let ii = fold(&mut cx);
match ii {
IIItem(_) => {}
IIMethod(impl_did, is_provided, m) => {
let entry = if is_provided {
EntryTraitMethod(cx.parent, box(GC) Provided(m))
} else {
EntryMethod(cx.parent, m)
IITraitItem(impl_did, inlined_trait_item) => {
let (trait_item_id, entry) = match inlined_trait_item {
ProvidedInlinedTraitItem(m) => {
(m.id,
EntryTraitItem(cx.parent, box(GC) ProvidedMethod(m)))
}
RequiredInlinedTraitItem(m) => {
(m.id,
EntryImplItem(cx.parent, box(GC) MethodImplItem(m)))
}
};
cx.insert(m.id, entry);
cx.insert(trait_item_id, entry);
def_id = impl_did;
}
IIForeign(i) => {
@ -829,8 +865,8 @@ impl<'a> NodePrinter for pprust::State<'a> {
match *node {
NodeItem(a) => self.print_item(&*a),
NodeForeignItem(a) => self.print_foreign_item(&*a),
NodeTraitMethod(a) => self.print_trait_method(&*a),
NodeMethod(a) => self.print_method(&*a),
NodeTraitItem(a) => self.print_trait_method(&*a),
NodeImplItem(a) => self.print_impl_item(&*a),
NodeVariant(a) => self.print_variant(&*a),
NodeExpr(a) => self.print_expr(&*a),
NodeStmt(a) => self.print_stmt(&*a),
@ -870,17 +906,23 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String {
let path_str = map.path_to_str_with_ident(id, item.ident);
format!("foreign item {} (id={})", path_str, id)
}
Some(NodeMethod(m)) => match m.node {
MethDecl(ident, _, _, _, _, _, _, _) =>
format!("method {} in {} (id={})",
token::get_ident(ident),
map.path_to_string(id), id),
MethMac(ref mac) =>
format!("method macro {} (id={})",
pprust::mac_to_string(mac), id)
},
Some(NodeTraitMethod(ref tm)) => {
let m = ast_util::trait_method_to_ty_method(&**tm);
Some(NodeImplItem(ref ii)) => {
match **ii {
MethodImplItem(ref m) => {
match m.node {
MethDecl(ident, _, _, _, _, _, _, _) =>
format!("method {} in {} (id={})",
token::get_ident(ident),
map.path_to_string(id), id),
MethMac(ref mac) =>
format!("method macro {} (id={})",
pprust::mac_to_string(mac), id)
}
}
}
}
Some(NodeTraitItem(ref tm)) => {
let m = ast_util::trait_item_to_ty_method(&**tm);
format!("method {} in {} (id={})",
token::get_ident(m.ident),
map.path_to_string(id), id)

View File

@ -241,51 +241,52 @@ pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: &Ty) -> Ident {
token::gensym_ident(pretty.as_slice())
}
/// extract a TypeMethod from a TraitMethod. if the TraitMethod is
/// a default, pull out the useful fields to make a TypeMethod
//
// NB: to be used only after expansion is complete, and macros are gone.
pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
match *method {
Required(ref m) => (*m).clone(),
Provided(m) => {
match m.node {
MethDecl(ident,
ref generics,
abi,
explicit_self,
fn_style,
decl,
_,
vis) => {
TypeMethod {
ident: ident,
attrs: m.attrs.clone(),
fn_style: fn_style,
decl: decl,
generics: generics.clone(),
explicit_self: explicit_self,
id: m.id,
span: m.span,
vis: vis,
abi: abi,
}
},
MethMac(_) => fail!("expected non-macro method declaration")
pub fn trait_method_to_ty_method(method: &Method) -> TypeMethod {
match method.node {
MethDecl(ident,
ref generics,
abi,
explicit_self,
fn_style,
decl,
_,
vis) => {
TypeMethod {
ident: ident,
attrs: method.attrs.clone(),
fn_style: fn_style,
decl: decl,
generics: generics.clone(),
explicit_self: explicit_self,
id: method.id,
span: method.span,
vis: vis,
abi: abi,
}
}
},
MethMac(_) => fail!("expected non-macro method declaration")
}
}
pub fn split_trait_methods(trait_methods: &[TraitMethod])
/// extract a TypeMethod from a TraitItem. if the TraitItem is
/// a default, pull out the useful fields to make a TypeMethod
//
// NB: to be used only after expansion is complete, and macros are gone.
pub fn trait_item_to_ty_method(method: &TraitItem) -> TypeMethod {
match *method {
RequiredMethod(ref m) => (*m).clone(),
ProvidedMethod(ref m) => trait_method_to_ty_method(&**m),
}
}
pub fn split_trait_methods(trait_methods: &[TraitItem])
-> (Vec<TypeMethod> , Vec<Gc<Method>> ) {
let mut reqd = Vec::new();
let mut provd = Vec::new();
for trt_method in trait_methods.iter() {
match *trt_method {
Required(ref tm) => reqd.push((*tm).clone()),
Provided(m) => provd.push(m)
RequiredMethod(ref tm) => reqd.push((*tm).clone()),
ProvidedMethod(m) => provd.push(m)
}
};
(reqd, provd)
@ -543,12 +544,12 @@ impl<'a, O: IdVisitingOperation> Visitor<()> for IdVisitor<'a, O> {
visit::walk_struct_def(self, struct_def, ());
}
fn visit_trait_method(&mut self, tm: &ast::TraitMethod, _: ()) {
fn visit_trait_item(&mut self, tm: &ast::TraitItem, _: ()) {
match *tm {
ast::Required(ref m) => self.operation.visit_id(m.id),
ast::Provided(ref m) => self.operation.visit_id(m.id),
ast::RequiredMethod(ref m) => self.operation.visit_id(m.id),
ast::ProvidedMethod(ref m) => self.operation.visit_id(m.id),
}
visit::walk_trait_method(self, tm, ());
visit::walk_trait_item(self, tm, ());
}
}

View File

@ -452,8 +452,13 @@ impl<'a> TraitDef<'a> {
self.span,
ident,
(vec!(attr)).append(self.attributes.as_slice()),
ast::ItemImpl(trait_generics, opt_trait_ref,
self_type, methods))
ast::ItemImpl(trait_generics,
opt_trait_ref,
self_type,
methods.move_iter()
.map(|method| {
ast::MethodImplItem(method)
}).collect()))
}
fn expand_struct_def(&self,

View File

@ -834,26 +834,37 @@ pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_
let struct_def = folder.fold_struct_def(*struct_def);
ItemStruct(struct_def, folder.fold_generics(generics))
}
ItemImpl(ref generics, ref ifce, ty, ref methods) => {
ItemImpl(ref generics, ref ifce, ty, ref impl_items) => {
ItemImpl(folder.fold_generics(generics),
ifce.as_ref().map(|p| folder.fold_trait_ref(p)),
folder.fold_ty(ty),
methods.iter().flat_map(|x| folder.fold_method(*x).move_iter()).collect()
impl_items.iter()
.flat_map(|impl_item| {
match *impl_item {
MethodImplItem(x) => {
folder.fold_method(x)
.move_iter()
.map(|x| MethodImplItem(x))
}
}
}).collect()
)
}
ItemTrait(ref generics, ref unbound, ref traits, ref methods) => {
let methods = methods.iter().flat_map(|method| {
let r = match *method {
Required(ref m) =>
SmallVector::one(Required(folder.fold_type_method(m))).move_iter(),
Provided(method) => {
RequiredMethod(ref m) => {
SmallVector::one(RequiredMethod(
folder.fold_type_method(m))).move_iter()
}
ProvidedMethod(method) => {
// the awkward collect/iter idiom here is because
// even though an iter and a map satisfy the same trait bound,
// they're not actually the same type, so the method arms
// don't unify.
let methods : SmallVector<ast::TraitMethod> =
let methods : SmallVector<ast::TraitItem> =
folder.fold_method(method).move_iter()
.map(|m| Provided(m)).collect();
.map(|m| ProvidedMethod(m)).collect();
methods.move_iter()
}
};

View File

@ -13,7 +13,7 @@
use abi;
use ast::{BareFnTy, ClosureTy};
use ast::{StaticRegionTyParamBound, OtherRegionTyParamBound, TraitTyParamBound};
use ast::{Provided, Public, FnStyle};
use ast::{ProvidedMethod, Public, FnStyle};
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
use ast::{BlockCheckMode, UnBox};
@ -33,23 +33,24 @@ use ast::{ExprVstoreUniq, Once, Many};
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
use ast::{FnOnceUnboxedClosureKind};
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
use ast::{Ident, NormalFn, Inherited, Item, Item_, ItemStatic};
use ast::{Ident, NormalFn, Inherited, ImplItem, Item, Item_, ItemStatic};
use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl};
use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy, Lit, Lit_};
use ast::{LitBool, LitChar, LitByte, LitBinary};
use ast::{LitNil, LitStr, LitInt, Local, LocalLet};
use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, Matcher, MatchNonterminal};
use ast::{MatchSeq, MatchTok, Method, MutTy, BiMul, Mutability};
use ast::{MethodImplItem};
use ast::{NamedField, UnNeg, NoReturn, UnNot, P, Pat, PatEnum};
use ast::{PatIdent, PatLit, PatRange, PatRegion, PatStruct};
use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle};
use ast::{BiRem, Required};
use ast::{BiRem, RequiredMethod};
use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl};
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
use ast::{StructVariantKind, BiSub};
use ast::StrStyle;
use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
use ast::{TokenTree, TraitMethod, TraitRef, TTDelim, TTSeq, TTTok};
use ast::{TokenTree, TraitItem, TraitRef, TTDelim, TTSeq, TTTok};
use ast::{TTNonterminal, TupleVariantKind, Ty, Ty_, TyBot, TyBox};
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
@ -1238,7 +1239,7 @@ impl<'a> Parser<'a> {
}
/// Parse the methods in a trait declaration
pub fn parse_trait_methods(&mut self) -> Vec<TraitMethod> {
pub fn parse_trait_methods(&mut self) -> Vec<TraitItem> {
self.parse_unspanned_seq(
&token::LBRACE,
&token::RBRACE,
@ -1276,7 +1277,7 @@ impl<'a> Parser<'a> {
token::SEMI => {
p.bump();
debug!("parse_trait_methods(): parsing required method");
Required(TypeMethod {
RequiredMethod(TypeMethod {
ident: ident,
attrs: attrs,
fn_style: style,
@ -1294,7 +1295,7 @@ impl<'a> Parser<'a> {
let (inner_attrs, body) =
p.parse_inner_attrs_and_block();
let attrs = attrs.append(inner_attrs.as_slice());
Provided(box(GC) ast::Method {
ProvidedMethod(box(GC) ast::Method {
attrs: attrs,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
@ -4243,6 +4244,18 @@ impl<'a> Parser<'a> {
(ident, ItemTrait(tps, sized, traits, meths), None)
}
fn parse_impl_items(&mut self) -> (Vec<ImplItem>, Vec<Attribute>) {
let mut impl_items = Vec::new();
self.expect(&token::LBRACE);
let (inner_attrs, next) = self.parse_inner_attrs_and_next();
let mut method_attrs = Some(next);
while !self.eat(&token::RBRACE) {
impl_items.push(MethodImplItem(self.parse_method(method_attrs)));
method_attrs = None;
}
(impl_items, inner_attrs)
}
/// Parses two variants (with the region/type params always optional):
/// impl<T> Foo { ... }
/// impl<T> ToString for ~[T] { ... }
@ -4284,18 +4297,13 @@ impl<'a> Parser<'a> {
None
};
let mut meths = Vec::new();
self.expect(&token::LBRACE);
let (inner_attrs, next) = self.parse_inner_attrs_and_next();
let mut method_attrs = Some(next);
while !self.eat(&token::RBRACE) {
meths.push(self.parse_method(method_attrs));
method_attrs = None;
}
let (impl_items, attrs) = self.parse_impl_items();
let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
(ident, ItemImpl(generics, opt_trait, ty, meths), Some(inner_attrs))
(ident,
ItemImpl(generics, opt_trait, ty, impl_items),
Some(attrs))
}
/// Parse a::B<String,int>

View File

@ -10,9 +10,9 @@
use abi;
use ast::{FnMutUnboxedClosureKind, FnOnceUnboxedClosureKind};
use ast::{FnUnboxedClosureKind, P, OtherRegionTyParamBound};
use ast::{FnUnboxedClosureKind, MethodImplItem, P, OtherRegionTyParamBound};
use ast::{StaticRegionTyParamBound, TraitTyParamBound, UnboxedClosureKind};
use ast::{UnboxedFnTyParamBound, Required, Provided};
use ast::{UnboxedFnTyParamBound, RequiredMethod, ProvidedMethod};
use ast;
use ast_util;
use owned_slice::OwnedSlice;
@ -787,7 +787,10 @@ impl<'a> State<'a> {
item.span));
}
ast::ItemImpl(ref generics, ref opt_trait, ref ty, ref methods) => {
ast::ItemImpl(ref generics,
ref opt_trait,
ref ty,
ref impl_items) => {
try!(self.head(visibility_qualified(item.vis,
"impl").as_slice()));
if generics.is_parameterized() {
@ -809,8 +812,12 @@ impl<'a> State<'a> {
try!(space(&mut self.s));
try!(self.bopen());
try!(self.print_inner_attributes(item.attrs.as_slice()));
for meth in methods.iter() {
try!(self.print_method(&**meth));
for impl_item in impl_items.iter() {
match *impl_item {
ast::MethodImplItem(meth) => {
try!(self.print_method(&*meth));
}
}
}
try!(self.bclose(item.span));
}
@ -1061,10 +1068,16 @@ impl<'a> State<'a> {
}
pub fn print_trait_method(&mut self,
m: &ast::TraitMethod) -> IoResult<()> {
m: &ast::TraitItem) -> IoResult<()> {
match *m {
Required(ref ty_m) => self.print_ty_method(ty_m),
Provided(ref m) => self.print_method(&**m)
RequiredMethod(ref ty_m) => self.print_ty_method(ty_m),
ProvidedMethod(ref m) => self.print_method(&**m)
}
}
pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> IoResult<()> {
match *ii {
MethodImplItem(ref m) => self.print_method(&**m),
}
}

View File

@ -99,7 +99,7 @@ pub trait Visitor<E: Clone> {
walk_fn(self, fk, fd, b, s, e)
}
fn visit_ty_method(&mut self, t: &TypeMethod, e: E) { walk_ty_method(self, t, e) }
fn visit_trait_method(&mut self, t: &TraitMethod, e: E) { walk_trait_method(self, t, e) }
fn visit_trait_item(&mut self, t: &TraitItem, e: E) { walk_trait_item(self, t, e) }
fn visit_struct_def(&mut self, s: &StructDef, _: Ident, _: &Generics, _: NodeId, e: E) {
walk_struct_def(self, s, e)
}
@ -148,7 +148,16 @@ pub fn walk_inlined_item<E: Clone, V: Visitor<E>>(visitor: &mut V,
match *item {
IIItem(i) => visitor.visit_item(&*i, env),
IIForeign(i) => visitor.visit_foreign_item(&*i, env),
IIMethod(_, _, m) => walk_method_helper(visitor, &*m, env),
IITraitItem(_, iti) => {
match iti {
ProvidedInlinedTraitItem(m) => {
walk_method_helper(visitor, &*m, env)
}
RequiredInlinedTraitItem(m) => {
walk_method_helper(visitor, &*m, env)
}
}
}
}
}
@ -269,7 +278,7 @@ pub fn walk_item<E: Clone, V: Visitor<E>>(visitor: &mut V, item: &Item, env: E)
ItemImpl(ref type_parameters,
ref trait_reference,
typ,
ref methods) => {
ref impl_items) => {
visitor.visit_generics(type_parameters, env.clone());
match *trait_reference {
Some(ref trait_reference) => walk_trait_ref_helper(visitor,
@ -277,8 +286,12 @@ pub fn walk_item<E: Clone, V: Visitor<E>>(visitor: &mut V, item: &Item, env: E)
None => ()
}
visitor.visit_ty(&*typ, env.clone());
for method in methods.iter() {
walk_method_helper(visitor, &**method, env.clone())
for impl_item in impl_items.iter() {
match *impl_item {
MethodImplItem(method) => {
walk_method_helper(visitor, &*method, env.clone())
}
}
}
}
ItemStruct(ref struct_definition, ref generics) => {
@ -297,7 +310,7 @@ pub fn walk_item<E: Clone, V: Visitor<E>>(visitor: &mut V, item: &Item, env: E)
env.clone())
}
for method in methods.iter() {
visitor.visit_trait_method(method, env.clone())
visitor.visit_trait_item(method, env.clone())
}
}
ItemMac(ref macro) => visitor.visit_mac(macro, env.clone()),
@ -626,14 +639,14 @@ pub fn walk_ty_method<E: Clone, V: Visitor<E>>(visitor: &mut V,
}
}
pub fn walk_trait_method<E: Clone, V: Visitor<E>>(visitor: &mut V,
trait_method: &TraitMethod,
pub fn walk_trait_item<E: Clone, V: Visitor<E>>(visitor: &mut V,
trait_method: &TraitItem,
env: E) {
match *trait_method {
Required(ref method_type) => {
RequiredMethod(ref method_type) => {
visitor.visit_ty_method(method_type, env)
}
Provided(ref method) => walk_method_helper(visitor, &**method, env),
ProvidedMethod(ref method) => walk_method_helper(visitor, &**method, env),
}
}