diff --git a/src/libextra/sync.rs b/src/libextra/sync.rs index 56168f923ad7..3908b61381b7 100644 --- a/src/libextra/sync.rs +++ b/src/libextra/sync.rs @@ -381,7 +381,7 @@ impl Sem<~[Waitqueue]> { // The only other places that condvars get built are rwlock.write_cond() // and rwlock_write_mode. pub fn access_cond(&self, blk: &fn(c: &Condvar) -> U) -> U { - do self.access { + do self.access_waitqueue { blk(&Condvar { sem: self, order: Nothing }) } } diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index f487c73372fa..e7725436f2b4 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -176,6 +176,10 @@ pub static tag_item_method_tps: uint = 0x7b; pub static tag_item_method_fty: uint = 0x7c; pub static tag_item_method_transformed_self_ty: uint = 0x7d; +pub static tag_mod_child: uint = 0x7e; +pub static tag_misc_info: uint = 0x7f; +pub static tag_misc_info_crate_items: uint = 0x80; + pub struct LinkMeta { name: @str, vers: @str, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index bfc5d512b370..4ede9f96f1f4 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -97,18 +97,14 @@ pub fn get_enum_variants(tcx: ty::ctxt, def: ast::def_id) return decoder::get_enum_variants(cstore.intr, cdata, def.node, tcx) } -pub fn get_impls_for_mod(cstore: @mut cstore::CStore, def: ast::def_id, - name: Option) - -> @~[@resolve::Impl] { - let cdata = cstore::get_crate_data(cstore, def.crate); - do decoder::get_impls_for_mod(cstore.intr, cdata, def.node, name) |cnum| { - cstore::get_crate_data(cstore, cnum) - } +/// Returns information about the given implementation. +pub fn get_impl(cstore: @mut cstore::CStore, impl_def_id: ast::def_id) + -> resolve::Impl { + let cdata = cstore::get_crate_data(cstore, impl_def_id.crate); + decoder::get_impl(cstore.intr, cdata, impl_def_id.node) } -pub fn get_method(tcx: ty::ctxt, - def: ast::def_id) -> ty::Method -{ +pub fn get_method(tcx: ty::ctxt, def: ast::def_id) -> ty::Method { let cdata = cstore::get_crate_data(tcx.cstore, def.crate); decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx) } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b11badd65cc8..2ebaa2b739fc 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -458,64 +458,192 @@ pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) -> bool { return true; } -/// Iterates over all the paths in the given crate. -pub fn each_path(intr: @ident_interner, - cdata: cmd, - get_crate_data: GetCrateDataCb, - f: &fn(&str, def_like, ast::visibility) -> bool) - -> bool { - // FIXME #4572: This function needs to be nuked, as it's impossible to make fast. - // It's the source of most of the performance problems when compiling small crates. +struct EachItemContext<'self> { + intr: @ident_interner, + cdata: cmd, + get_crate_data: GetCrateDataCb<'self>, + path_builder: &'self mut ~str, + callback: &'self fn(&str, def_like, ast::visibility) -> bool, +} - let root = reader::Doc(cdata.data); - let items = reader::get_doc(root, tag_items); - let items_data = reader::get_doc(items, tag_items_data); +impl<'self> EachItemContext<'self> { + // Pushes the given name and returns the old length. + fn push_name(&mut self, string: &str) -> uint { + let path_len = self.path_builder.len(); + if path_len != 0 { + self.path_builder.push_str("::") + } + self.path_builder.push_str(string); + path_len + } - // First, go through all the explicit items. - for reader::tagged_docs(items_data, tag_items_data_item) |item_doc| { - let path = ast_map::path_to_str(item_path(item_doc), intr); - let path_is_empty = path.is_empty(); - if !path_is_empty { - // Extract the def ID. - let def_id = item_def_id(item_doc, cdata); + // Pops the given name. + fn pop_name(&mut self, old_len: uint) { + // XXX(pcwalton): There's no safe function to do this. :( + unsafe { + str::raw::set_len(self.path_builder, old_len) + } + } - // Construct the def for this item. - debug!("(each_path) yielding explicit item: %s", path); - let def_like = item_to_def_like(item_doc, def_id, cdata.cnum); - - let vis = item_visibility(item_doc); - - // Hand the information off to the iteratee. - if !f(path, def_like, vis) { - return false; + fn process_item_and_pop_name(&mut self, + doc: ebml::Doc, + def_id: ast::def_id, + old_len: uint) + -> bool { + let def_like = item_to_def_like(doc, def_id, self.cdata.cnum); + match def_like { + dl_def(def) => { + debug!("(iterating over each item of a module) processing \ + `%s` (def %?)", + *self.path_builder, + def); + } + _ => { + debug!("(iterating over each item of a module) processing \ + `%s` (%d:%d)", + *self.path_builder, + def_id.crate, + def_id.node); } } - // If this is a module, find the reexports. - for each_reexport(item_doc) |reexport_doc| { - let def_id_doc = - reader::get_doc(reexport_doc, - tag_items_data_item_reexport_def_id); - let def_id = reader::with_doc_data(def_id_doc, parse_def_id); - let def_id = translate_def_id(cdata, def_id); + let vis = item_visibility(doc); - let reexport_name_doc = - reader::get_doc(reexport_doc, - tag_items_data_item_reexport_name); - let reexport_name = reexport_name_doc.as_str_slice(); + let mut continue = (self.callback)(*self.path_builder, def_like, vis); - let reexport_path; - if path_is_empty { - reexport_path = reexport_name.to_owned(); - } else { - reexport_path = path + "::" + reexport_name; + let family = item_family(doc); + if family == ForeignMod { + // These are unnamed; pop the name now. + self.pop_name(old_len) + } + + if continue { + // Recurse if necessary. + match family { + Mod | ForeignMod | Trait | Impl => { + continue = self.each_item_of_module(def_id); + } + Freeze | Struct | UnsafeFn | Fn | PureFn | ForeignFn | + UnsafeStaticMethod | StaticMethod | PureStaticMethod | Type | + ForeignType | Variant | Enum | PublicField | PrivateField | + InheritedField => {} } + } - // This reexport may be in yet another crate - let other_crates_items = if def_id.crate == cdata.cnum { - items + if family != ForeignMod { + self.pop_name(old_len) + } + + continue + } + + fn each_item_of_module(&mut self, def_id: ast::def_id) -> bool { + // This item might not be in this crate. If it's not, look it up. + let (cdata, items) = if def_id.crate == self.cdata.cnum { + let items = reader::get_doc(reader::Doc(self.cdata.data), + tag_items); + (self.cdata, items) + } else { + let crate_data = (self.get_crate_data)(def_id.crate); + let root = reader::Doc(crate_data.data); + (crate_data, reader::get_doc(root, tag_items)) + }; + + // Look up the item. + let item_doc = match maybe_find_item(def_id.node, items) { + None => return false, + Some(item_doc) => item_doc, + }; + + self.each_child_of_module_or_crate(item_doc) + } + + fn each_child_of_module_or_crate(&mut self, item_doc: ebml::Doc) -> bool { + let mut continue = true; + + // Iterate over all children. + for reader::tagged_docs(item_doc, tag_mod_child) |child_info_doc| { + let child_def_id = reader::with_doc_data(child_info_doc, + parse_def_id); + let child_def_id = translate_def_id(self.cdata, child_def_id); + + // This item may be in yet another crate, if it was the child of + // a reexport. + let other_crates_items = if child_def_id.crate == + self.cdata.cnum { + reader::get_doc(reader::Doc(self.cdata.data), tag_items) } else { - let crate_data = get_crate_data(def_id.crate); + let crate_data = (self.get_crate_data)(child_def_id.crate); + let root = reader::Doc(crate_data.data); + reader::get_doc(root, tag_items) + }; + + debug!("(iterating over each item of a module) looking up item \ + %d:%d in `%s`, crate %d", + child_def_id.crate, + child_def_id.node, + *self.path_builder, + self.cdata.cnum); + + // Get the item. + match maybe_find_item(child_def_id.node, other_crates_items) { + None => {} + Some(child_item_doc) => { + // Push the name. + let child_name = item_name(self.intr, child_item_doc); + debug!("(iterating over each item of a module) pushing \ + name `%s` onto `%s`", + token::ident_to_str(&child_name), + *self.path_builder); + let old_len = + self.push_name(token::ident_to_str(&child_name)); + + // Process this item. + continue = self.process_item_and_pop_name(child_item_doc, + child_def_id, + old_len); + + if !continue { + break + } + } + } + } + + if !continue { + return false + } + + // Iterate over reexports. + for each_reexport(item_doc) |reexport_doc| { + let def_id_doc = reader::get_doc( + reexport_doc, + tag_items_data_item_reexport_def_id); + let orig_def_id = reader::with_doc_data(def_id_doc, parse_def_id); + + // NB: was "cdata" + let def_id = translate_def_id(self.cdata, orig_def_id); + + let name_doc = reader::get_doc(reexport_doc, + tag_items_data_item_reexport_name); + let name = name_doc.as_str_slice(); + + // Push the name. + debug!("(iterating over each item of a module) pushing \ + reexported name `%s` onto `%s` (crate %d, orig %d, \ + in crate %d)", + name, + *self.path_builder, + def_id.crate, + orig_def_id.crate, + self.cdata.cnum); + let old_len = self.push_name(name); + + // This reexport may be in yet another crate. + let other_crates_items = if def_id.crate == self.cdata.cnum { + reader::get_doc(reader::Doc(self.cdata.data), tag_items) + } else { + let crate_data = (self.get_crate_data)(def_id.crate); let root = reader::Doc(crate_data.data); reader::get_doc(root, tag_items) }; @@ -523,29 +651,53 @@ pub fn each_path(intr: @ident_interner, // Get the item. match maybe_find_item(def_id.node, other_crates_items) { None => {} - Some(item_doc) => { - // Construct the def for this item. - let def_like = item_to_def_like(item_doc, - def_id, - cdata.cnum); - - // Hand the information off to the iteratee. - debug!("(each_path) yielding reexported \ - item: %s", reexport_path); - - if (!f(reexport_path, def_like, ast::public)) { - return false; - } + Some(reexported_item_doc) => { + continue = self.process_item_and_pop_name( + reexported_item_doc, + def_id, + old_len); } } - } - } - return true; + if !continue { + break + } + } + + continue + } } -pub fn get_item_path(cdata: cmd, id: ast::node_id) - -> ast_map::path { +/// Iterates over all the paths in the given crate. +pub fn each_path(intr: @ident_interner, + cdata: cmd, + get_crate_data: GetCrateDataCb, + f: &fn(&str, def_like, ast::visibility) -> bool) + -> bool { + // FIXME #4572: This function needs to be nuked, as it's impossible to + // make fast. It's the source of most of the performance problems when + // compiling small crates. + + let root_doc = reader::Doc(cdata.data); + let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); + let crate_items_doc = reader::get_doc(misc_info_doc, + tag_misc_info_crate_items); + + let mut path_builder = ~""; + + let mut context = EachItemContext { + intr: intr, + cdata: cdata, + get_crate_data: get_crate_data, + path_builder: &mut path_builder, + callback: f, + }; + + // Iterate over all top-level crate items. + context.each_child_of_module_or_crate(crate_items_doc) +} + +pub fn get_item_path(cdata: cmd, id: ast::node_id) -> ast_map::path { item_path(lookup_item(id, cdata.data)) } @@ -661,35 +813,20 @@ fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc, rslt } -pub fn get_impls_for_mod(intr: @ident_interner, - cdata: cmd, - m_id: ast::node_id, - name: Option, - get_cdata: &fn(ast::crate_num) -> cmd) - -> @~[@resolve::Impl] { +/// Returns information about the given implementation. +pub fn get_impl(intr: @ident_interner, cdata: cmd, impl_id: ast::node_id) + -> resolve::Impl { let data = cdata.data; - let mod_item = lookup_item(m_id, data); - let mut result = ~[]; - for reader::tagged_docs(mod_item, tag_mod_impl) |doc| { - let did = reader::with_doc_data(doc, parse_def_id); - let local_did = translate_def_id(cdata, did); - debug!("(get impls for mod) getting did %? for '%?'", - local_did, name); - // The impl may be defined in a different crate. Ask the caller - // to give us the metadata - let impl_cdata = get_cdata(local_did.crate); - let impl_data = impl_cdata.data; - let item = lookup_item(local_did.node, impl_data); - let nm = item_name(intr, item); - if match name { Some(n) => { n == nm } None => { true } } { - let base_tps = item_ty_param_count(item); - result.push(@resolve::Impl { - did: local_did, ident: nm, - methods: item_impl_methods(intr, impl_cdata, item, base_tps) - }); - }; + let impl_item = lookup_item(impl_id, data); + let base_tps = item_ty_param_count(impl_item); + resolve::Impl { + did: ast::def_id { + crate: cdata.cnum, + node: impl_id, + }, + ident: item_name(intr, impl_item), + methods: item_impl_methods(intr, cdata, impl_item, base_tps), } - @result } pub fn get_method_name_and_explicit_self( diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 5ff52b1859ad..187f2a99ed4c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -22,7 +22,7 @@ use middle; use util::ppaux::ty_to_str; use core::hash::HashUtil; -use core::hashmap::HashMap; +use core::hashmap::{HashMap, HashSet}; use core::int; use core::io; use core::str; @@ -64,7 +64,8 @@ pub struct EncodeParams<'self> { discrim_symbols: &'self HashMap, link_meta: &'self LinkMeta, cstore: @mut cstore::CStore, - encode_inlined_item: encode_inlined_item<'self> + encode_inlined_item: encode_inlined_item<'self>, + reachable: @mut HashSet, } struct Stats { @@ -73,6 +74,7 @@ struct Stats { dep_bytes: uint, lang_item_bytes: uint, link_args_bytes: uint, + misc_bytes: uint, item_bytes: uint, index_bytes: uint, zero_bytes: uint, @@ -91,7 +93,8 @@ pub struct EncodeContext<'self> { link_meta: &'self LinkMeta, cstore: &'self cstore::CStore, encode_inlined_item: encode_inlined_item<'self>, - type_abbrevs: abbrev_map + type_abbrevs: abbrev_map, + reachable: @mut HashSet, } pub fn reachable(ecx: &EncodeContext, id: node_id) -> bool { @@ -470,45 +473,50 @@ fn encode_reexported_static_methods(ecx: &EncodeContext, } } -fn encode_info_for_mod(ecx: &EncodeContext, - ebml_w: &mut writer::Encoder, - md: &_mod, - id: node_id, - path: &[ast_map::path_elt], - name: ident) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(id)); - encode_family(ebml_w, 'm'); - encode_name(ecx, ebml_w, name); - debug!("(encoding info for module) encoding info for module ID %d", id); - - // Encode info about all the module children. - for md.items.iter().advance |item| { - match item.node { - item_impl(*) => { - let (ident, did) = (item.ident, item.id); - debug!("(encoding info for module) ... encoding impl %s \ - (%?/%?)", - ecx.tcx.sess.str_of(ident), - did, - ast_map::node_id_to_str(ecx.tcx.items, did, token::get_ident_interner())); - - ebml_w.start_tag(tag_mod_impl); - ebml_w.wr_str(def_to_str(local_def(did))); - ebml_w.end_tag(); +/// Iterates through "auxiliary node IDs", which are node IDs that describe +/// top-level items that are sub-items of the given item. Specifically: +/// +/// * For enums, iterates through the node IDs of the variants. +/// +/// * For newtype structs, iterates through the node ID of the constructor. +fn each_auxiliary_node_id(item: @item, callback: &fn(node_id) -> bool) + -> bool { + let mut continue = true; + match item.node { + item_enum(ref enum_def, _) => { + for enum_def.variants.each |variant| { + continue = callback(variant.node.id); + if !continue { + break + } } - _ => {} // FIXME #4573: Encode these too. } + item_struct(struct_def, _) => { + // If this is a newtype struct, return the constructor. + match struct_def.ctor_id { + Some(ctor_id) if struct_def.fields.len() > 0 && + struct_def.fields[0].node.kind == + ast::unnamed_field => { + continue = callback(ctor_id); + } + _ => {} + } + } + _ => {} } - encode_path(ecx, ebml_w, path, ast_map::path_mod(name)); + continue +} - // Encode the reexports of this module. +fn encode_reexports(ecx: &EncodeContext, + ebml_w: &mut writer::Encoder, + id: node_id, + path: &[ast_map::path_elt]) { debug!("(encoding info for module) encoding reexports for %d", id); match ecx.reexports2.find(&id) { Some(ref exports) => { debug!("(encoding info for module) found reexports for %d", id); - for exports.iter().advance |exp| { + for exports.each |exp| { debug!("(encoding info for module) reexport '%s' for %d", exp.name, id); ebml_w.start_tag(tag_items_data_item_reexport); @@ -527,6 +535,57 @@ fn encode_info_for_mod(ecx: &EncodeContext, id); } } +} + +fn encode_info_for_mod(ecx: &EncodeContext, + ebml_w: &mut writer::Encoder, + md: &_mod, + id: node_id, + path: &[ast_map::path_elt], + name: ident, + vis: visibility) { + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(id)); + encode_family(ebml_w, 'm'); + encode_name(ecx, ebml_w, name); + debug!("(encoding info for module) encoding info for module ID %d", id); + + // Encode info about all the module children. + for md.items.iter().advance |item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(item.id))); + ebml_w.end_tag(); + + for each_auxiliary_node_id(*item) |auxiliary_node_id| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(auxiliary_node_id))); + ebml_w.end_tag(); + } + + match item.node { + item_impl(*) => { + let (ident, did) = (item.ident, item.id); + debug!("(encoding info for module) ... encoding impl %s \ + (%?/%?)", + ecx.tcx.sess.str_of(ident), + did, + ast_map::node_id_to_str(ecx.tcx.items, did, token::get_ident_interner())); + + ebml_w.start_tag(tag_mod_impl); + ebml_w.wr_str(def_to_str(local_def(did))); + ebml_w.end_tag(); + } + _ => {} + } + } + + encode_path(ecx, ebml_w, path, ast_map::path_mod(name)); + + // Encode the reexports of this module, if this module is public. + if vis == public { + debug!("(encoding info for module) encoding reexports for %d", id); + encode_reexports(ecx, ebml_w, id, path); + } ebml_w.end_tag(); } @@ -799,6 +858,7 @@ fn encode_info_for_item(ecx: &EncodeContext, } encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); encode_symbol(ecx, ebml_w, item.id); + encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); ebml_w.end_tag(); @@ -811,6 +871,7 @@ fn encode_info_for_item(ecx: &EncodeContext, let tps_len = generics.ty_params.len(); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); encode_attributes(ebml_w, item.attrs); if tps_len > 0u || should_inline(item.attrs) { @@ -822,15 +883,29 @@ fn encode_info_for_item(ecx: &EncodeContext, } item_mod(ref m) => { add_to_index(); - encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident); + encode_info_for_mod(ecx, + ebml_w, + m, + item.id, + path, + item.ident, + item.vis); } - item_foreign_mod(_) => { + item_foreign_mod(ref fm) => { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); encode_family(ebml_w, 'n'); encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + + // Encode all the items in this module. + for fm.items.each |foreign_item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(foreign_item.id))); + ebml_w.end_tag(); + } + ebml_w.end_tag(); } item_ty(_, ref generics) => { @@ -998,6 +1073,10 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.start_tag(tag_item_trait_method); encode_def_id(ebml_w, method_def_id); ebml_w.end_tag(); + + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(method_def_id)); + ebml_w.end_tag(); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); for super_traits.iter().advance |ast_trait_ref| { @@ -1091,6 +1170,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, encode_family(ebml_w, purity_fn_family(purity)); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); + encode_name(ecx, ebml_w, nitem.ident); if abi.is_intrinsic() { (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem)); } else { @@ -1107,6 +1187,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext, } encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); encode_symbol(ecx, ebml_w, nitem.id); + encode_name(ecx, ebml_w, nitem.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); } } @@ -1120,9 +1201,13 @@ fn encode_info_for_items(ecx: &EncodeContext, let index = @mut ~[]; ebml_w.start_tag(tag_items_data); index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() }); - encode_info_for_mod(ecx, ebml_w, &crate.node.module, - crate_node_id, [], - syntax::parse::token::special_idents::invalid); + encode_info_for_mod(ecx, + ebml_w, + &crate.node.module, + crate_node_id, + [], + syntax::parse::token::special_idents::invalid, + public); let items = ecx.tcx.items; // See comment in `encode_side_tables_for_ii` in astencode @@ -1416,6 +1501,30 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.end_tag(); } +fn encode_misc_info(ecx: &EncodeContext, + crate: &crate, + ebml_w: &mut writer::Encoder) { + ebml_w.start_tag(tag_misc_info); + ebml_w.start_tag(tag_misc_info_crate_items); + for crate.node.module.items.each |&item| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(item.id))); + ebml_w.end_tag(); + + for each_auxiliary_node_id(item) |auxiliary_node_id| { + ebml_w.start_tag(tag_mod_child); + ebml_w.wr_str(def_to_str(local_def(auxiliary_node_id))); + ebml_w.end_tag(); + } + } + + // Encode reexports for the root module. + encode_reexports(ecx, ebml_w, 0, []); + + ebml_w.end_tag(); + ebml_w.end_tag(); +} + fn encode_crate_dep(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, dep: decoder::crate_dep) { @@ -1455,15 +1564,25 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { dep_bytes: 0, lang_item_bytes: 0, link_args_bytes: 0, + misc_bytes: 0, item_bytes: 0, index_bytes: 0, zero_bytes: 0, total_bytes: 0, n_inlines: 0 }; - let EncodeParams{item_symbols, diag, tcx, reexports2, - discrim_symbols, cstore, encode_inlined_item, - link_meta, _} = parms; + let EncodeParams { + item_symbols, + diag, + tcx, + reexports2, + discrim_symbols, + cstore, + encode_inlined_item, + link_meta, + reachable, + _ + } = parms; let type_abbrevs = @mut HashMap::new(); let stats = @mut stats; let ecx = EncodeContext { @@ -1476,7 +1595,8 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { link_meta: link_meta, cstore: cstore, encode_inlined_item: encode_inlined_item, - type_abbrevs: type_abbrevs + type_abbrevs: type_abbrevs, + reachable: reachable, }; let mut ebml_w = writer::Encoder(wr as @io::Writer); @@ -1502,6 +1622,11 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { encode_link_args(&ecx, &mut ebml_w); ecx.stats.link_args_bytes = *wr.pos - i; + // Encode miscellaneous info. + i = *wr.pos; + encode_misc_info(&ecx, crate, &mut ebml_w); + ecx.stats.misc_bytes = *wr.pos - i; + // Encode and index the items. ebml_w.start_tag(tag_items); i = *wr.pos; @@ -1529,6 +1654,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes)); io::println(fmt!(" lang item bytes: %u", ecx.stats.lang_item_bytes)); io::println(fmt!(" link args bytes: %u", ecx.stats.link_args_bytes)); + io::println(fmt!(" misc bytes: %u", ecx.stats.misc_bytes)); io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes)); io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes)); io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes)); diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 106c1d85cd77..12ddd3710458 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -77,6 +77,15 @@ fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool { } } +// The context we're in. If we're in a public context, then public symbols are +// marked reachable. If we're in a private context, then only trait +// implementations are marked reachable. +#[deriving(Eq)] +enum PrivacyContext { + PublicContext, + PrivateContext, +} + // Information needed while computing reachability. struct ReachableContext { // The type context. @@ -109,25 +118,31 @@ impl ReachableContext { let reachable_symbols = self.reachable_symbols; let worklist = self.worklist; let visitor = visit::mk_vt(@Visitor { - visit_item: |item, (_, visitor)| { + visit_item: |item, (privacy_context, visitor): + (PrivacyContext, visit::vt)| { match item.node { item_fn(*) => { - reachable_symbols.insert(item.id); + if privacy_context == PublicContext { + reachable_symbols.insert(item.id); + } if item_might_be_inlined(item) { worklist.push(item.id) } } item_struct(ref struct_def, _) => { match struct_def.ctor_id { - None => {} - Some(ctor_id) => { + Some(ctor_id) if + privacy_context == PublicContext => { reachable_symbols.insert(ctor_id); } + Some(_) | None => {} } } item_enum(ref enum_def, _) => { - for enum_def.variants.each |variant| { - reachable_symbols.insert(variant.node.id); + if privacy_context == PublicContext { + for enum_def.variants.each |variant| { + reachable_symbols.insert(variant.node.id); + } } } item_impl(ref generics, trait_ref, _, ref methods) => { @@ -137,9 +152,15 @@ impl ReachableContext { // treating implementations of reachable or cross- // crate traits as reachable. + let should_be_considered_public = |method: @method| { + (method.vis == public && + privacy_context == PublicContext) || + trait_ref.is_some() + }; + // Mark all public methods as reachable. - for methods.each |method| { - if method.vis == public || trait_ref.is_some() { + for methods.each |&method| { + if should_be_considered_public(method) { reachable_symbols.insert(method.id); } } @@ -147,9 +168,8 @@ impl ReachableContext { if generics_require_inlining(generics) { // If the impl itself has generics, add all public // symbols to the worklist. - for methods.each |method| { - if method.vis == public || - trait_ref.is_some() { + for methods.each |&method| { + if should_be_considered_public(method) { worklist.push(method.id) } } @@ -161,8 +181,7 @@ impl ReachableContext { let attrs = &method.attrs; if generics_require_inlining(generics) || attributes_specify_inlining(*attrs) || - method.vis == public || - trait_ref.is_some() { + should_be_considered_public(*method) { worklist.push(method.id) } } @@ -170,27 +189,31 @@ impl ReachableContext { } item_trait(_, _, ref trait_methods) => { // Mark all provided methods as reachable. - for trait_methods.each |trait_method| { - match *trait_method { - provided(method) => { - reachable_symbols.insert(method.id); - worklist.push(method.id) + if privacy_context == PublicContext { + for trait_methods.each |trait_method| { + match *trait_method { + provided(method) => { + reachable_symbols.insert(method.id); + worklist.push(method.id) + } + required(_) => {} } - required(_) => {} } } } _ => {} } - if item.vis == public { - visit::visit_item(item, ((), visitor)) + if item.vis == public && privacy_context == PublicContext { + visit::visit_item(item, (PublicContext, visitor)) + } else { + visit::visit_item(item, (PrivateContext, visitor)) } }, .. *visit::default_visitor() }); - visit::visit_crate(crate, ((), visitor)) + visit::visit_crate(crate, (PublicContext, visitor)) } // Returns true if the given def ID represents a local item that is @@ -247,7 +270,7 @@ impl ReachableContext { } } Some(_) => false, - None => tcx.sess.bug("def ID not in def map?!"), + None => false // This will happen for default methods. } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 7cf13c671b21..17c984c8a33c 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -654,7 +654,17 @@ impl NameBindings { Some(ref type_def) => { match (*type_def).type_def { Some(type_def) => Some(type_def), - None => None, + None => { + match type_def.module_def { + Some(module) => { + match module.def_id { + Some(did) => Some(def_mod(did)), + None => None, + } + } + None => None, + } + } } } } @@ -3149,12 +3159,14 @@ impl Resolver { Some(def_id) if def_id.crate == local_crate => { // OK. Continue. debug!("(recording exports for module subtree) recording \ - exports for local module"); + exports for local module `%s`", + self.module_to_str(module_)); } None => { // Record exports for the root module. debug!("(recording exports for module subtree) recording \ - exports for root module"); + exports for root module `%s`", + self.module_to_str(module_)); } Some(_) => { // Bail out. @@ -5037,6 +5049,9 @@ impl Resolver { self.trait_map.insert(expr.id, @mut traits); } expr_method_call(_, _, ident, _, _, _) => { + debug!("(recording candidate traits for expr) recording \ + traits for %d", + expr.id); let traits = self.search_for_traits_containing_method(ident); self.trait_map.insert(expr.id, @mut traits); } @@ -5112,7 +5127,6 @@ impl Resolver { debug!("(searching for traits containing method) looking for '%s'", self.session.str_of(name)); - let mut found_traits = ~[]; let mut search_module = self.current_module; match self.method_map.find(&name) { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 661b19480e05..df7f73a52436 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -64,7 +64,7 @@ use util::ppaux::{Repr, ty_to_str}; use middle::trans::type_::Type; use core::hash; -use core::hashmap::{HashMap}; +use core::hashmap::{HashMap, HashSet}; use core::int; use core::io; use core::libc::c_uint; @@ -2509,7 +2509,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef { variant)) } }; - if !exprt { + if !exprt && !ccx.reachable.contains(&id) { lib::llvm::SetLinkage(val, lib::llvm::InternalLinkage); } ccx.item_vals.insert(id, val); @@ -2816,13 +2816,13 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::encode_ encoder::EncodeParams { diag: diag, tcx: cx.tcx, - reachable: cx.reachable, reexports2: cx.exp_map2, item_symbols: item_symbols, discrim_symbols: discrim_symbols, link_meta: link_meta, cstore: cx.sess.cstore, - encode_inlined_item: ie + encode_inlined_item: ie, + reachable: cx.reachable, } } @@ -2890,7 +2890,7 @@ pub fn trans_crate(sess: session::Session, emap2: resolve::ExportMap2, reachable_map: @mut HashSet, maps: astencode::Maps) - -> (ModuleRef, LinkMeta) { + -> (ContextRef, ModuleRef, LinkMeta) { let mut symbol_hasher = hash::default_state(); let link_meta = link::build_link_meta(sess, crate, output, &mut symbol_hasher); @@ -2911,8 +2911,15 @@ pub fn trans_crate(sess: session::Session, // sess.bug("couldn't enable multi-threaded LLVM"); // } - let ccx = @mut CrateContext::new(sess, llmod_id, tcx, emap2, maps, - symbol_hasher, link_meta, reachable); + let ccx = @mut CrateContext::new(sess, + llmod_id, + tcx, + emap2, + maps, + symbol_hasher, + link_meta, + reachable_map); + { let _icx = push_ctxt("data"); trans_constants(ccx, crate); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 04bce4c02a81..a7ffa8e13b02 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -117,84 +117,7 @@ pub fn BuilderRef_res(B: BuilderRef) -> BuilderRef_res { } } -pub type ExternMap = @mut HashMap<@str, ValueRef>; - -// Crate context. Every crate we compile has one of these. -pub struct CrateContext { - sess: session::Session, - llmod: ModuleRef, - td: TargetData, - tn: @TypeNames, - externs: ExternMap, - intrinsics: HashMap<&'static str, ValueRef>, - item_vals: @mut HashMap, - exp_map2: resolve::ExportMap2, - item_symbols: @mut HashMap, - link_meta: LinkMeta, - enum_sizes: @mut HashMap, - discrims: @mut HashMap, - discrim_symbols: @mut HashMap, - tydescs: @mut HashMap, - // Set when running emit_tydescs to enforce that no more tydescs are - // created. - finished_tydescs: @mut bool, - // Track mapping of external ids to local items imported for inlining - external: @mut HashMap>, - // Cache instances of monomorphized functions - monomorphized: @mut HashMap, - monomorphizing: @mut HashMap, - // Cache computed type parameter uses (see type_use.rs) - type_use_cache: @mut HashMap, - // Cache generated vtables - vtables: @mut HashMap, - // Cache of constant strings, - const_cstr_cache: @mut HashMap<@str, ValueRef>, - - // Reverse-direction for const ptrs cast from globals. - // Key is an int, cast from a ValueRef holding a *T, - // Val is a ValueRef holding a *[T]. - // - // Needed because LLVM loses pointer->pointee association - // when we ptrcast, and we have to ptrcast during translation - // of a [T] const because we form a slice, a [*T,int] pair, not - // a pointer to an LLVM array type. - const_globals: @mut HashMap, - - // Cache of emitted const values - const_values: @mut HashMap, - - // Cache of external const values - extern_const_values: @mut HashMap, - - module_data: @mut HashMap<~str, ValueRef>, - lltypes: @mut HashMap, - llsizingtypes: @mut HashMap, - adt_reprs: @mut HashMap, - names: namegen, - next_addrspace: addrspace_gen, - symbol_hasher: @mut hash::State, - type_hashcodes: @mut HashMap, - type_short_names: @mut HashMap, - all_llvm_symbols: @mut HashSet<@str>, - tcx: ty::ctxt, - maps: astencode::Maps, - stats: @mut Stats, - upcalls: @upcall::Upcalls, - tydesc_type: TypeRef, - int_type: TypeRef, - float_type: TypeRef, - opaque_vec_type: TypeRef, - builder: BuilderRef_res, - shape_cx: shape::Ctxt, - crate_map: ValueRef, - // Set when at least one function uses GC. Needed so that - // decl_gc_metadata knows whether to link to the module metadata, which - // is not emitted by LLVM's GC pass when no functions use GC. - uses_gc: @mut bool, - dbg_cx: Option, - do_not_commit_warning_issued: @mut bool, - reachable_map: @mut HashSet, -} +pub type ExternMap = HashMap<@str, ValueRef>; // Types used for llself. pub struct ValSelfData { diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 7046c8b9f41b..9b81fc406b7c 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -21,7 +21,6 @@ use middle::resolve; use middle::trans::adt; use middle::trans::base; use middle::trans::debuginfo; -use middle::trans::reachable; use middle::trans::type_use; use middle::ty; @@ -48,7 +47,7 @@ pub struct CrateContext { intrinsics: HashMap<&'static str, ValueRef>, item_vals: HashMap, exp_map2: resolve::ExportMap2, - reachable: reachable::map, + reachable: @mut HashSet, item_symbols: HashMap, link_meta: LinkMeta, enum_sizes: HashMap, @@ -115,10 +114,15 @@ pub struct CrateContext { } impl CrateContext { - pub fn new(sess: session::Session, name: &str, tcx: ty::ctxt, - emap2: resolve::ExportMap2, maps: astencode::Maps, - symbol_hasher: hash::State, link_meta: LinkMeta, - reachable: reachable::map) -> CrateContext { + pub fn new(sess: session::Session, + name: &str, + tcx: ty::ctxt, + emap2: resolve::ExportMap2, + maps: astencode::Maps, + symbol_hasher: hash::State, + link_meta: LinkMeta, + reachable: @mut HashSet) + -> CrateContext { unsafe { let llcx = llvm::LLVMContextCreate(); set_task_llcx(llcx); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index d224d182950d..4c1c8e5c2c8a 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1393,6 +1393,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, method_map.insert(expr.id, (*entry)); } None => { + debug!("(checking method call) failing expr is %d", expr.id); + fcx.type_error_message(expr.span, |actual| { fmt!("type `%s` does not implement any method in scope \ diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index c3abf47f9e29..9de7315d0e71 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -17,7 +17,7 @@ use core::prelude::*; use metadata::csearch::{each_path, get_impl_trait}; -use metadata::csearch::{get_impls_for_mod}; +use metadata::csearch; use metadata::cstore::{CStore, iter_crate_data}; use metadata::decoder::{dl_def, dl_field, dl_impl}; use middle::resolve::{Impl, MethodInfo}; @@ -855,92 +855,67 @@ impl CoherenceChecker { // External crate handling - pub fn add_impls_for_module(&self, - impls_seen: &mut HashSet, - crate_store: @mut CStore, - module_def_id: def_id) { - let implementations = get_impls_for_mod(crate_store, - module_def_id, - None); - for implementations.iter().advance |implementation| { - debug!("coherence: adding impl from external crate: %s", - ty::item_path_str(self.crate_context.tcx, - implementation.did)); + pub fn add_external_impl(&self, + impls_seen: &mut HashSet, + crate_store: @mut CStore, + impl_def_id: def_id) { + let implementation = csearch::get_impl(crate_store, impl_def_id); - // Make sure we don't visit the same implementation - // multiple times. - if !impls_seen.insert(implementation.did) { - // Skip this one. - loop; - } - // Good. Continue. + debug!("coherence: adding impl from external crate: %s", + ty::item_path_str(self.crate_context.tcx, implementation.did)); - let self_type = lookup_item_type(self.crate_context.tcx, - implementation.did); - let associated_traits = get_impl_trait(self.crate_context.tcx, - implementation.did); + // Make sure we don't visit the same implementation multiple times. + if !impls_seen.insert(implementation.did) { + // Skip this one. + return + } + // Good. Continue. - // Do a sanity check to make sure that inherent methods have base - // types. - - if associated_traits.is_none() { - match get_base_type_def_id(self.inference_context, - dummy_sp(), - self_type.ty) { - None => { - let session = self.crate_context.tcx.sess; - session.bug(fmt!( - "no base type for external impl \ - with no trait: %s (type %s)!", - session.str_of(implementation.ident), - ty_to_str(self.crate_context.tcx,self_type.ty))); - } - Some(_) => { - // Nothing to do. - } - } - } - - let mut implementation = *implementation; - - // Record all the trait methods. - for associated_traits.iter().advance |trait_ref| { - self.instantiate_default_methods(implementation.did, - &**trait_ref); - // Could we avoid these copies when we don't need them? - let mut methods = /*bad?*/ copy implementation.methods; - self.add_provided_methods_to_impl( - &mut methods, - &trait_ref.def_id, - &implementation.did); - implementation = @Impl { methods: methods, - .. *implementation }; - - - self.add_trait_method(trait_ref.def_id, implementation); - } - - // Add the implementation to the mapping from - // implementation to base type def ID, if there is a base - // type for this implementation. + let self_type = lookup_item_type(self.crate_context.tcx, + implementation.did); + let associated_traits = get_impl_trait(self.crate_context.tcx, + implementation.did); + // Do a sanity check to make sure that inherent methods have base + // types. + if associated_traits.is_none() { match get_base_type_def_id(self.inference_context, - dummy_sp(), - self_type.ty) { + dummy_sp(), + self_type.ty) { None => { - // Nothing to do. + let session = self.crate_context.tcx.sess; + session.bug(fmt!("no base type for external impl with no \ + trait: %s (type %s)!", + session.str_of(implementation.ident), + ty_to_str(self.crate_context.tcx, + self_type.ty))); } - Some(base_type_def_id) => { - // inherent methods apply to `impl Type` but not - // `impl Trait for Type`: - if associated_traits.is_none() { - self.add_inherent_method(base_type_def_id, - implementation); - } + Some(_) => {} // Nothing to do. + } + } - self.base_type_def_ids.insert(implementation.did, - base_type_def_id); + // Record all the trait methods. + let implementation = @implementation; + for associated_traits.iter().advance |trait_ref| { + self.add_trait_method(trait_ref.def_id, implementation); + } + + // Add the implementation to the mapping from implementation to base + // type def ID, if there is a base type for this implementation. + match get_base_type_def_id(self.inference_context, + dummy_sp(), + self_type.ty) { + None => {} // Nothing to do. + Some(base_type_def_id) => { + // inherent methods apply to `impl Type` but not + // `impl Trait for Type`: + if associated_traits.is_none() { + self.add_inherent_method(base_type_def_id, + implementation); } + + self.base_type_def_ids.insert(implementation.did, + base_type_def_id); } } } @@ -952,22 +927,17 @@ impl CoherenceChecker { let crate_store = self.crate_context.tcx.sess.cstore; do iter_crate_data(crate_store) |crate_number, _crate_metadata| { - self.add_impls_for_module(&mut impls_seen, - crate_store, - def_id { crate: crate_number, - node: 0 }); - for each_path(crate_store, crate_number) |_, def_like, _| { match def_like { - dl_def(def_mod(def_id)) => { - self.add_impls_for_module(&mut impls_seen, - crate_store, - def_id); + dl_def(def_trait(def_id)) => { + self.add_default_methods_for_external_trait(def_id); } - dl_def(_) | dl_impl(_) | dl_field => { - // Skip this. - loop; + dl_impl(def_id) => { + self.add_external_impl(&mut impls_seen, + crate_store, + def_id) } + dl_def(_) | dl_field => loop, // Skip this. } } } diff --git a/src/libstd/char.rs b/src/libstd/char.rs index 797fd9e8c020..8f0870af5133 100644 --- a/src/libstd/char.rs +++ b/src/libstd/char.rs @@ -10,6 +10,7 @@ //! Utilities for manipulating the char type +use container::Container; use option::{None, Option, Some}; use str; use str::{StrSlice, OwnedStr}; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 7d848184493f..590292d0d327 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -29,6 +29,7 @@ #[allow(missing_doc)]; use cast; +use container::Container; use io; use iterator::IteratorUtil; use libc; @@ -1500,7 +1501,10 @@ mod tests { fn test_getenv_big() { let mut s = ~""; let mut i = 0; - while i < 100 { s += "aaaaaaaaaa"; i += 1; } + while i < 100 { + s = s + "aaaaaaaaaa"; + i += 1; + } let n = make_rand_name(); setenv(n, s); debug!(copy s); diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index 8a6c05ce6e2a..5baff8aee68d 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -42,6 +42,7 @@ fn main () { use cast; use cmp; +use container::Container; use int; use iterator::IteratorUtil; use local_data; diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 3c512d9bfd29..2144afc0fbd1 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -1140,6 +1140,17 @@ impl<'self> Str for @str { } } +impl<'self> Container for &'self str { + #[inline] + fn len(&self) -> uint { + do as_buf(*self) |_p, n| { n - 1u } + } + #[inline] + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + #[allow(missing_doc)] pub trait StrSlice<'self> { fn contains<'a>(&self, needle: &'a str) -> bool; @@ -1158,10 +1169,8 @@ pub trait StrSlice<'self> { fn any_line_iter(&self) -> AnyLineIterator<'self>; fn word_iter(&self) -> WordIterator<'self>; fn ends_with(&self, needle: &str) -> bool; - fn is_empty(&self) -> bool; fn is_whitespace(&self) -> bool; fn is_alphanumeric(&self) -> bool; - fn len(&self) -> uint; fn char_len(&self) -> uint; fn slice(&self, begin: uint, end: uint) -> &'self str; @@ -1362,9 +1371,6 @@ impl<'self> StrSlice<'self> for &'self str { self.split_iter(char::is_whitespace).filter(|s| !s.is_empty()) } - /// Returns true if the string has length 0 - #[inline] - fn is_empty(&self) -> bool { self.len() == 0 } /** * Returns true if the string contains only whitespace * @@ -1379,11 +1385,6 @@ impl<'self> StrSlice<'self> for &'self str { */ #[inline] fn is_alphanumeric(&self) -> bool { self.iter().all(char::is_alphanumeric) } - /// Returns the size in bytes not counting the null terminator - #[inline] - fn len(&self) -> uint { - do as_buf(*self) |_p, n| { n - 1u } - } /// Returns the number of characters that a string holds #[inline] fn char_len(&self) -> uint { self.iter().len_() } diff --git a/src/libstd/unstable/extfmt.rs b/src/libstd/unstable/extfmt.rs index 87bd25bdad32..624062a7ec40 100644 --- a/src/libstd/unstable/extfmt.rs +++ b/src/libstd/unstable/extfmt.rs @@ -94,6 +94,7 @@ use iterator::IteratorUtil; #[doc(hidden)] pub mod ct { use char; + use container::Container; use prelude::*; use str;