Rewrite each_path to allow performance improvements in the future.

Instead of determining paths from the path tag, we iterate through
modules' children recursively in the metadata. This will allow for
lazy external module resolution.
This commit is contained in:
Patrick Walton 2013-06-18 09:39:16 -07:00 committed by Corey Richardson
parent 89eb995195
commit e015bee286
17 changed files with 578 additions and 364 deletions

View File

@ -381,7 +381,7 @@ impl Sem<~[Waitqueue]> {
// The only other places that condvars get built are rwlock.write_cond() // The only other places that condvars get built are rwlock.write_cond()
// and rwlock_write_mode. // and rwlock_write_mode.
pub fn access_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U { pub fn access_cond<U>(&self, blk: &fn(c: &Condvar) -> U) -> U {
do self.access { do self.access_waitqueue {
blk(&Condvar { sem: self, order: Nothing }) blk(&Condvar { sem: self, order: Nothing })
} }
} }

View File

@ -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_fty: uint = 0x7c;
pub static tag_item_method_transformed_self_ty: uint = 0x7d; 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 { pub struct LinkMeta {
name: @str, name: @str,
vers: @str, vers: @str,

View File

@ -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) 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, /// Returns information about the given implementation.
name: Option<ast::ident>) pub fn get_impl(cstore: @mut cstore::CStore, impl_def_id: ast::def_id)
-> @~[@resolve::Impl] { -> resolve::Impl {
let cdata = cstore::get_crate_data(cstore, def.crate); let cdata = cstore::get_crate_data(cstore, impl_def_id.crate);
do decoder::get_impls_for_mod(cstore.intr, cdata, def.node, name) |cnum| { decoder::get_impl(cstore.intr, cdata, impl_def_id.node)
cstore::get_crate_data(cstore, cnum)
}
} }
pub fn get_method(tcx: ty::ctxt, pub fn get_method(tcx: ty::ctxt, def: ast::def_id) -> ty::Method {
def: ast::def_id) -> ty::Method
{
let cdata = cstore::get_crate_data(tcx.cstore, def.crate); let cdata = cstore::get_crate_data(tcx.cstore, def.crate);
decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx) decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx)
} }

View File

@ -458,64 +458,192 @@ pub fn each_lang_item(cdata: cmd, f: &fn(ast::node_id, uint) -> bool) -> bool {
return true; return true;
} }
/// Iterates over all the paths in the given crate. struct EachItemContext<'self> {
pub fn each_path(intr: @ident_interner, intr: @ident_interner,
cdata: cmd, cdata: cmd,
get_crate_data: GetCrateDataCb, get_crate_data: GetCrateDataCb<'self>,
f: &fn(&str, def_like, ast::visibility) -> bool) path_builder: &'self mut ~str,
callback: &'self fn(&str, def_like, ast::visibility) -> bool,
}
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
}
// 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)
}
}
fn process_item_and_pop_name(&mut self,
doc: ebml::Doc,
def_id: ast::def_id,
old_len: uint)
-> bool { -> bool {
// FIXME #4572: This function needs to be nuked, as it's impossible to make fast. let def_like = item_to_def_like(doc, def_id, self.cdata.cnum);
// It's the source of most of the performance problems when compiling small crates. match def_like {
dl_def(def) => {
let root = reader::Doc(cdata.data); debug!("(iterating over each item of a module) processing \
let items = reader::get_doc(root, tag_items); `%s` (def %?)",
let items_data = reader::get_doc(items, tag_items_data); *self.path_builder,
def);
// 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); debug!("(iterating over each item of a module) processing \
let path_is_empty = path.is_empty(); `%s` (%d:%d)",
if !path_is_empty { *self.path_builder,
// Extract the def ID. def_id.crate,
let def_id = item_def_id(item_doc, cdata); def_id.node);
// 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;
} }
} }
// If this is a module, find the reexports. let vis = item_visibility(doc);
let mut continue = (self.callback)(*self.path_builder, def_like, vis);
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 => {}
}
}
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 = (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| { for each_reexport(item_doc) |reexport_doc| {
let def_id_doc = let def_id_doc = reader::get_doc(
reader::get_doc(reexport_doc, reexport_doc,
tag_items_data_item_reexport_def_id); tag_items_data_item_reexport_def_id);
let def_id = reader::with_doc_data(def_id_doc, parse_def_id); let orig_def_id = reader::with_doc_data(def_id_doc, parse_def_id);
let def_id = translate_def_id(cdata, def_id);
let reexport_name_doc = // NB: was "cdata"
reader::get_doc(reexport_doc, 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); tag_items_data_item_reexport_name);
let reexport_name = reexport_name_doc.as_str_slice(); let name = name_doc.as_str_slice();
let reexport_path; // Push the name.
if path_is_empty { debug!("(iterating over each item of a module) pushing \
reexport_path = reexport_name.to_owned(); reexported name `%s` onto `%s` (crate %d, orig %d, \
} else { in crate %d)",
reexport_path = path + "::" + reexport_name; 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 // This reexport may be in yet another crate.
let other_crates_items = if def_id.crate == cdata.cnum { let other_crates_items = if def_id.crate == self.cdata.cnum {
items reader::get_doc(reader::Doc(self.cdata.data), tag_items)
} else { } else {
let crate_data = get_crate_data(def_id.crate); let crate_data = (self.get_crate_data)(def_id.crate);
let root = reader::Doc(crate_data.data); let root = reader::Doc(crate_data.data);
reader::get_doc(root, tag_items) reader::get_doc(root, tag_items)
}; };
@ -523,29 +651,53 @@ pub fn each_path(intr: @ident_interner,
// Get the item. // Get the item.
match maybe_find_item(def_id.node, other_crates_items) { match maybe_find_item(def_id.node, other_crates_items) {
None => {} None => {}
Some(item_doc) => { Some(reexported_item_doc) => {
// Construct the def for this item. continue = self.process_item_and_pop_name(
let def_like = item_to_def_like(item_doc, reexported_item_doc,
def_id, def_id,
cdata.cnum); old_len);
// 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;
}
}
}
} }
} }
return true; if !continue {
break
}
}
continue
}
} }
pub fn get_item_path(cdata: cmd, id: ast::node_id) /// Iterates over all the paths in the given crate.
-> ast_map::path { 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)) item_path(lookup_item(id, cdata.data))
} }
@ -661,35 +813,20 @@ fn item_impl_methods(intr: @ident_interner, cdata: cmd, item: ebml::Doc,
rslt rslt
} }
pub fn get_impls_for_mod(intr: @ident_interner, /// Returns information about the given implementation.
cdata: cmd, pub fn get_impl(intr: @ident_interner, cdata: cmd, impl_id: ast::node_id)
m_id: ast::node_id, -> resolve::Impl {
name: Option<ast::ident>,
get_cdata: &fn(ast::crate_num) -> cmd)
-> @~[@resolve::Impl] {
let data = cdata.data; let data = cdata.data;
let mod_item = lookup_item(m_id, data); let impl_item = lookup_item(impl_id, data);
let mut result = ~[]; let base_tps = item_ty_param_count(impl_item);
for reader::tagged_docs(mod_item, tag_mod_impl) |doc| { resolve::Impl {
let did = reader::with_doc_data(doc, parse_def_id); did: ast::def_id {
let local_did = translate_def_id(cdata, did); crate: cdata.cnum,
debug!("(get impls for mod) getting did %? for '%?'", node: impl_id,
local_did, name); },
// The impl may be defined in a different crate. Ask the caller ident: item_name(intr, impl_item),
// to give us the metadata methods: item_impl_methods(intr, cdata, impl_item, base_tps),
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)
});
};
} }
@result
} }
pub fn get_method_name_and_explicit_self( pub fn get_method_name_and_explicit_self(

View File

@ -22,7 +22,7 @@ use middle;
use util::ppaux::ty_to_str; use util::ppaux::ty_to_str;
use core::hash::HashUtil; use core::hash::HashUtil;
use core::hashmap::HashMap; use core::hashmap::{HashMap, HashSet};
use core::int; use core::int;
use core::io; use core::io;
use core::str; use core::str;
@ -64,7 +64,8 @@ pub struct EncodeParams<'self> {
discrim_symbols: &'self HashMap<ast::node_id, @str>, discrim_symbols: &'self HashMap<ast::node_id, @str>,
link_meta: &'self LinkMeta, link_meta: &'self LinkMeta,
cstore: @mut cstore::CStore, cstore: @mut cstore::CStore,
encode_inlined_item: encode_inlined_item<'self> encode_inlined_item: encode_inlined_item<'self>,
reachable: @mut HashSet<ast::node_id>,
} }
struct Stats { struct Stats {
@ -73,6 +74,7 @@ struct Stats {
dep_bytes: uint, dep_bytes: uint,
lang_item_bytes: uint, lang_item_bytes: uint,
link_args_bytes: uint, link_args_bytes: uint,
misc_bytes: uint,
item_bytes: uint, item_bytes: uint,
index_bytes: uint, index_bytes: uint,
zero_bytes: uint, zero_bytes: uint,
@ -91,7 +93,8 @@ pub struct EncodeContext<'self> {
link_meta: &'self LinkMeta, link_meta: &'self LinkMeta,
cstore: &'self cstore::CStore, cstore: &'self cstore::CStore,
encode_inlined_item: encode_inlined_item<'self>, encode_inlined_item: encode_inlined_item<'self>,
type_abbrevs: abbrev_map type_abbrevs: abbrev_map,
reachable: @mut HashSet<ast::node_id>,
} }
pub fn reachable(ecx: &EncodeContext, id: node_id) -> bool { 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, /// Iterates through "auxiliary node IDs", which are node IDs that describe
ebml_w: &mut writer::Encoder, /// top-level items that are sub-items of the given item. Specifically:
md: &_mod, ///
id: node_id, /// * For enums, iterates through the node IDs of the variants.
path: &[ast_map::path_elt], ///
name: ident) { /// * For newtype structs, iterates through the node ID of the constructor.
ebml_w.start_tag(tag_items_data_item); fn each_auxiliary_node_id(item: @item, callback: &fn(node_id) -> bool)
encode_def_id(ebml_w, local_def(id)); -> bool {
encode_family(ebml_w, 'm'); let mut continue = true;
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 { match item.node {
item_impl(*) => { item_enum(ref enum_def, _) => {
let (ident, did) = (item.ident, item.id); for enum_def.variants.each |variant| {
debug!("(encoding info for module) ... encoding impl %s \ continue = callback(variant.node.id);
(%?/%?)", if !continue {
ecx.tcx.sess.str_of(ident), break
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();
}
_ => {} // 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); debug!("(encoding info for module) encoding reexports for %d", id);
match ecx.reexports2.find(&id) { match ecx.reexports2.find(&id) {
Some(ref exports) => { Some(ref exports) => {
debug!("(encoding info for module) found reexports for %d", id); 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", debug!("(encoding info for module) reexport '%s' for %d",
exp.name, id); exp.name, id);
ebml_w.start_tag(tag_items_data_item_reexport); ebml_w.start_tag(tag_items_data_item_reexport);
@ -527,6 +535,57 @@ fn encode_info_for_mod(ecx: &EncodeContext,
id); 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(); 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_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_symbol(ecx, ebml_w, 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)); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
ebml_w.end_tag(); ebml_w.end_tag();
@ -811,6 +871,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
let tps_len = generics.ty_params.len(); let tps_len = generics.ty_params.len();
encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); 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_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_attributes(ebml_w, item.attrs); encode_attributes(ebml_w, item.attrs);
if tps_len > 0u || should_inline(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) => { item_mod(ref m) => {
add_to_index(); 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(); add_to_index();
ebml_w.start_tag(tag_items_data_item); ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id)); encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'n'); encode_family(ebml_w, 'n');
encode_name(ecx, ebml_w, item.ident); encode_name(ecx, ebml_w, item.ident);
encode_path(ecx, ebml_w, path, ast_map::path_name(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(); ebml_w.end_tag();
} }
item_ty(_, ref generics) => { item_ty(_, ref generics) => {
@ -998,6 +1073,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
ebml_w.start_tag(tag_item_trait_method); ebml_w.start_tag(tag_item_trait_method);
encode_def_id(ebml_w, method_def_id); encode_def_id(ebml_w, method_def_id);
ebml_w.end_tag(); 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)); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
for super_traits.iter().advance |ast_trait_ref| { 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_family(ebml_w, purity_fn_family(purity));
encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params);
encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
encode_name(ecx, ebml_w, nitem.ident);
if abi.is_intrinsic() { if abi.is_intrinsic() {
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem)); (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem));
} else { } 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_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id));
encode_symbol(ecx, ebml_w, 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)); 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 ~[]; let index = @mut ~[];
ebml_w.start_tag(tag_items_data); ebml_w.start_tag(tag_items_data);
index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() }); index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() });
encode_info_for_mod(ecx, ebml_w, &crate.node.module, encode_info_for_mod(ecx,
crate_node_id, [], ebml_w,
syntax::parse::token::special_idents::invalid); &crate.node.module,
crate_node_id,
[],
syntax::parse::token::special_idents::invalid,
public);
let items = ecx.tcx.items; let items = ecx.tcx.items;
// See comment in `encode_side_tables_for_ii` in astencode // 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(); 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, fn encode_crate_dep(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder, ebml_w: &mut writer::Encoder,
dep: decoder::crate_dep) { dep: decoder::crate_dep) {
@ -1455,15 +1564,25 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
dep_bytes: 0, dep_bytes: 0,
lang_item_bytes: 0, lang_item_bytes: 0,
link_args_bytes: 0, link_args_bytes: 0,
misc_bytes: 0,
item_bytes: 0, item_bytes: 0,
index_bytes: 0, index_bytes: 0,
zero_bytes: 0, zero_bytes: 0,
total_bytes: 0, total_bytes: 0,
n_inlines: 0 n_inlines: 0
}; };
let EncodeParams{item_symbols, diag, tcx, reexports2, let EncodeParams {
discrim_symbols, cstore, encode_inlined_item, item_symbols,
link_meta, _} = parms; diag,
tcx,
reexports2,
discrim_symbols,
cstore,
encode_inlined_item,
link_meta,
reachable,
_
} = parms;
let type_abbrevs = @mut HashMap::new(); let type_abbrevs = @mut HashMap::new();
let stats = @mut stats; let stats = @mut stats;
let ecx = EncodeContext { let ecx = EncodeContext {
@ -1476,7 +1595,8 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] {
link_meta: link_meta, link_meta: link_meta,
cstore: cstore, cstore: cstore,
encode_inlined_item: encode_inlined_item, 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); 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); encode_link_args(&ecx, &mut ebml_w);
ecx.stats.link_args_bytes = *wr.pos - i; 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. // Encode and index the items.
ebml_w.start_tag(tag_items); ebml_w.start_tag(tag_items);
i = *wr.pos; 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!(" dep bytes: %u", ecx.stats.dep_bytes));
io::println(fmt!(" lang item bytes: %u", ecx.stats.lang_item_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!(" 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!(" item bytes: %u", ecx.stats.item_bytes));
io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes)); io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes));
io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes)); io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes));

View File

@ -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. // Information needed while computing reachability.
struct ReachableContext { struct ReachableContext {
// The type context. // The type context.
@ -109,27 +118,33 @@ impl ReachableContext {
let reachable_symbols = self.reachable_symbols; let reachable_symbols = self.reachable_symbols;
let worklist = self.worklist; let worklist = self.worklist;
let visitor = visit::mk_vt(@Visitor { let visitor = visit::mk_vt(@Visitor {
visit_item: |item, (_, visitor)| { visit_item: |item, (privacy_context, visitor):
(PrivacyContext, visit::vt<PrivacyContext>)| {
match item.node { match item.node {
item_fn(*) => { item_fn(*) => {
if privacy_context == PublicContext {
reachable_symbols.insert(item.id); reachable_symbols.insert(item.id);
}
if item_might_be_inlined(item) { if item_might_be_inlined(item) {
worklist.push(item.id) worklist.push(item.id)
} }
} }
item_struct(ref struct_def, _) => { item_struct(ref struct_def, _) => {
match struct_def.ctor_id { match struct_def.ctor_id {
None => {} Some(ctor_id) if
Some(ctor_id) => { privacy_context == PublicContext => {
reachable_symbols.insert(ctor_id); reachable_symbols.insert(ctor_id);
} }
Some(_) | None => {}
} }
} }
item_enum(ref enum_def, _) => { item_enum(ref enum_def, _) => {
if privacy_context == PublicContext {
for enum_def.variants.each |variant| { for enum_def.variants.each |variant| {
reachable_symbols.insert(variant.node.id); reachable_symbols.insert(variant.node.id);
} }
} }
}
item_impl(ref generics, trait_ref, _, ref methods) => { item_impl(ref generics, trait_ref, _, ref methods) => {
// XXX(pcwalton): We conservatively assume any methods // XXX(pcwalton): We conservatively assume any methods
// on a trait implementation are reachable, when this // on a trait implementation are reachable, when this
@ -137,9 +152,15 @@ impl ReachableContext {
// treating implementations of reachable or cross- // treating implementations of reachable or cross-
// crate traits as reachable. // 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. // Mark all public methods as reachable.
for methods.each |method| { for methods.each |&method| {
if method.vis == public || trait_ref.is_some() { if should_be_considered_public(method) {
reachable_symbols.insert(method.id); reachable_symbols.insert(method.id);
} }
} }
@ -147,9 +168,8 @@ impl ReachableContext {
if generics_require_inlining(generics) { if generics_require_inlining(generics) {
// If the impl itself has generics, add all public // If the impl itself has generics, add all public
// symbols to the worklist. // symbols to the worklist.
for methods.each |method| { for methods.each |&method| {
if method.vis == public || if should_be_considered_public(method) {
trait_ref.is_some() {
worklist.push(method.id) worklist.push(method.id)
} }
} }
@ -161,8 +181,7 @@ impl ReachableContext {
let attrs = &method.attrs; let attrs = &method.attrs;
if generics_require_inlining(generics) || if generics_require_inlining(generics) ||
attributes_specify_inlining(*attrs) || attributes_specify_inlining(*attrs) ||
method.vis == public || should_be_considered_public(*method) {
trait_ref.is_some() {
worklist.push(method.id) worklist.push(method.id)
} }
} }
@ -170,6 +189,7 @@ impl ReachableContext {
} }
item_trait(_, _, ref trait_methods) => { item_trait(_, _, ref trait_methods) => {
// Mark all provided methods as reachable. // Mark all provided methods as reachable.
if privacy_context == PublicContext {
for trait_methods.each |trait_method| { for trait_methods.each |trait_method| {
match *trait_method { match *trait_method {
provided(method) => { provided(method) => {
@ -180,17 +200,20 @@ impl ReachableContext {
} }
} }
} }
}
_ => {} _ => {}
} }
if item.vis == public { if item.vis == public && privacy_context == PublicContext {
visit::visit_item(item, ((), visitor)) visit::visit_item(item, (PublicContext, visitor))
} else {
visit::visit_item(item, (PrivateContext, visitor))
} }
}, },
.. *visit::default_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 // Returns true if the given def ID represents a local item that is
@ -247,7 +270,7 @@ impl ReachableContext {
} }
} }
Some(_) => false, Some(_) => false,
None => tcx.sess.bug("def ID not in def map?!"), None => false // This will happen for default methods.
} }
} }

View File

@ -654,9 +654,19 @@ impl NameBindings {
Some(ref type_def) => { Some(ref type_def) => {
match (*type_def).type_def { match (*type_def).type_def {
Some(type_def) => Some(type_def), Some(type_def) => Some(type_def),
None => {
match type_def.module_def {
Some(module) => {
match module.def_id {
Some(did) => Some(def_mod(did)),
None => None, None => None,
} }
} }
None => None,
}
}
}
}
} }
} }
ValueNS => { ValueNS => {
@ -3149,12 +3159,14 @@ impl Resolver {
Some(def_id) if def_id.crate == local_crate => { Some(def_id) if def_id.crate == local_crate => {
// OK. Continue. // OK. Continue.
debug!("(recording exports for module subtree) recording \ debug!("(recording exports for module subtree) recording \
exports for local module"); exports for local module `%s`",
self.module_to_str(module_));
} }
None => { None => {
// Record exports for the root module. // Record exports for the root module.
debug!("(recording exports for module subtree) recording \ debug!("(recording exports for module subtree) recording \
exports for root module"); exports for root module `%s`",
self.module_to_str(module_));
} }
Some(_) => { Some(_) => {
// Bail out. // Bail out.
@ -5037,6 +5049,9 @@ impl Resolver {
self.trait_map.insert(expr.id, @mut traits); self.trait_map.insert(expr.id, @mut traits);
} }
expr_method_call(_, _, ident, _, _, _) => { 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); let traits = self.search_for_traits_containing_method(ident);
self.trait_map.insert(expr.id, @mut traits); self.trait_map.insert(expr.id, @mut traits);
} }
@ -5112,7 +5127,6 @@ impl Resolver {
debug!("(searching for traits containing method) looking for '%s'", debug!("(searching for traits containing method) looking for '%s'",
self.session.str_of(name)); self.session.str_of(name));
let mut found_traits = ~[]; let mut found_traits = ~[];
let mut search_module = self.current_module; let mut search_module = self.current_module;
match self.method_map.find(&name) { match self.method_map.find(&name) {

View File

@ -64,7 +64,7 @@ use util::ppaux::{Repr, ty_to_str};
use middle::trans::type_::Type; use middle::trans::type_::Type;
use core::hash; use core::hash;
use core::hashmap::{HashMap}; use core::hashmap::{HashMap, HashSet};
use core::int; use core::int;
use core::io; use core::io;
use core::libc::c_uint; use core::libc::c_uint;
@ -2509,7 +2509,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::node_id) -> ValueRef {
variant)) variant))
} }
}; };
if !exprt { if !exprt && !ccx.reachable.contains(&id) {
lib::llvm::SetLinkage(val, lib::llvm::InternalLinkage); lib::llvm::SetLinkage(val, lib::llvm::InternalLinkage);
} }
ccx.item_vals.insert(id, val); 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 { encoder::EncodeParams {
diag: diag, diag: diag,
tcx: cx.tcx, tcx: cx.tcx,
reachable: cx.reachable,
reexports2: cx.exp_map2, reexports2: cx.exp_map2,
item_symbols: item_symbols, item_symbols: item_symbols,
discrim_symbols: discrim_symbols, discrim_symbols: discrim_symbols,
link_meta: link_meta, link_meta: link_meta,
cstore: cx.sess.cstore, 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, emap2: resolve::ExportMap2,
reachable_map: @mut HashSet<ast::node_id>, reachable_map: @mut HashSet<ast::node_id>,
maps: astencode::Maps) maps: astencode::Maps)
-> (ModuleRef, LinkMeta) { -> (ContextRef, ModuleRef, LinkMeta) {
let mut symbol_hasher = hash::default_state(); let mut symbol_hasher = hash::default_state();
let link_meta = link::build_link_meta(sess, crate, output, &mut symbol_hasher); 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"); // sess.bug("couldn't enable multi-threaded LLVM");
// } // }
let ccx = @mut CrateContext::new(sess, llmod_id, tcx, emap2, maps, let ccx = @mut CrateContext::new(sess,
symbol_hasher, link_meta, reachable); llmod_id,
tcx,
emap2,
maps,
symbol_hasher,
link_meta,
reachable_map);
{ {
let _icx = push_ctxt("data"); let _icx = push_ctxt("data");
trans_constants(ccx, crate); trans_constants(ccx, crate);

View File

@ -117,84 +117,7 @@ pub fn BuilderRef_res(B: BuilderRef) -> BuilderRef_res {
} }
} }
pub type ExternMap = @mut HashMap<@str, ValueRef>; pub type ExternMap = 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<ast::node_id, ValueRef>,
exp_map2: resolve::ExportMap2,
item_symbols: @mut HashMap<ast::node_id, ~str>,
link_meta: LinkMeta,
enum_sizes: @mut HashMap<ty::t, uint>,
discrims: @mut HashMap<ast::def_id, ValueRef>,
discrim_symbols: @mut HashMap<ast::node_id, @str>,
tydescs: @mut HashMap<ty::t, @mut tydesc_info>,
// 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<ast::def_id, Option<ast::node_id>>,
// Cache instances of monomorphized functions
monomorphized: @mut HashMap<mono_id, ValueRef>,
monomorphizing: @mut HashMap<ast::def_id, uint>,
// Cache computed type parameter uses (see type_use.rs)
type_use_cache: @mut HashMap<ast::def_id, @~[type_use::type_uses]>,
// Cache generated vtables
vtables: @mut HashMap<mono_id, ValueRef>,
// 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<int, ValueRef>,
// Cache of emitted const values
const_values: @mut HashMap<ast::node_id, ValueRef>,
// Cache of external const values
extern_const_values: @mut HashMap<ast::def_id, ValueRef>,
module_data: @mut HashMap<~str, ValueRef>,
lltypes: @mut HashMap<ty::t, TypeRef>,
llsizingtypes: @mut HashMap<ty::t, TypeRef>,
adt_reprs: @mut HashMap<ty::t, @adt::Repr>,
names: namegen,
next_addrspace: addrspace_gen,
symbol_hasher: @mut hash::State,
type_hashcodes: @mut HashMap<ty::t, @str>,
type_short_names: @mut HashMap<ty::t, ~str>,
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<debuginfo::DebugContext>,
do_not_commit_warning_issued: @mut bool,
reachable_map: @mut HashSet<ast::node_id>,
}
// Types used for llself. // Types used for llself.
pub struct ValSelfData { pub struct ValSelfData {

View File

@ -21,7 +21,6 @@ use middle::resolve;
use middle::trans::adt; use middle::trans::adt;
use middle::trans::base; use middle::trans::base;
use middle::trans::debuginfo; use middle::trans::debuginfo;
use middle::trans::reachable;
use middle::trans::type_use; use middle::trans::type_use;
use middle::ty; use middle::ty;
@ -48,7 +47,7 @@ pub struct CrateContext {
intrinsics: HashMap<&'static str, ValueRef>, intrinsics: HashMap<&'static str, ValueRef>,
item_vals: HashMap<ast::node_id, ValueRef>, item_vals: HashMap<ast::node_id, ValueRef>,
exp_map2: resolve::ExportMap2, exp_map2: resolve::ExportMap2,
reachable: reachable::map, reachable: @mut HashSet<ast::node_id>,
item_symbols: HashMap<ast::node_id, ~str>, item_symbols: HashMap<ast::node_id, ~str>,
link_meta: LinkMeta, link_meta: LinkMeta,
enum_sizes: HashMap<ty::t, uint>, enum_sizes: HashMap<ty::t, uint>,
@ -115,10 +114,15 @@ pub struct CrateContext {
} }
impl CrateContext { impl CrateContext {
pub fn new(sess: session::Session, name: &str, tcx: ty::ctxt, pub fn new(sess: session::Session,
emap2: resolve::ExportMap2, maps: astencode::Maps, name: &str,
symbol_hasher: hash::State, link_meta: LinkMeta, tcx: ty::ctxt,
reachable: reachable::map) -> CrateContext { emap2: resolve::ExportMap2,
maps: astencode::Maps,
symbol_hasher: hash::State,
link_meta: LinkMeta,
reachable: @mut HashSet<ast::node_id>)
-> CrateContext {
unsafe { unsafe {
let llcx = llvm::LLVMContextCreate(); let llcx = llvm::LLVMContextCreate();
set_task_llcx(llcx); set_task_llcx(llcx);

View File

@ -1393,6 +1393,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
method_map.insert(expr.id, (*entry)); method_map.insert(expr.id, (*entry));
} }
None => { None => {
debug!("(checking method call) failing expr is %d", expr.id);
fcx.type_error_message(expr.span, fcx.type_error_message(expr.span,
|actual| { |actual| {
fmt!("type `%s` does not implement any method in scope \ fmt!("type `%s` does not implement any method in scope \

View File

@ -17,7 +17,7 @@
use core::prelude::*; use core::prelude::*;
use metadata::csearch::{each_path, get_impl_trait}; 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::cstore::{CStore, iter_crate_data};
use metadata::decoder::{dl_def, dl_field, dl_impl}; use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::resolve::{Impl, MethodInfo}; use middle::resolve::{Impl, MethodInfo};
@ -855,23 +855,19 @@ impl CoherenceChecker {
// External crate handling // External crate handling
pub fn add_impls_for_module(&self, pub fn add_external_impl(&self,
impls_seen: &mut HashSet<def_id>, impls_seen: &mut HashSet<def_id>,
crate_store: @mut CStore, crate_store: @mut CStore,
module_def_id: def_id) { impl_def_id: def_id) {
let implementations = get_impls_for_mod(crate_store, let implementation = csearch::get_impl(crate_store, impl_def_id);
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));
// Make sure we don't visit the same implementation debug!("coherence: adding impl from external crate: %s",
// multiple times. ty::item_path_str(self.crate_context.tcx, implementation.did));
// Make sure we don't visit the same implementation multiple times.
if !impls_seen.insert(implementation.did) { if !impls_seen.insert(implementation.did) {
// Skip this one. // Skip this one.
loop; return
} }
// Good. Continue. // Good. Continue.
@ -882,54 +878,34 @@ impl CoherenceChecker {
// Do a sanity check to make sure that inherent methods have base // Do a sanity check to make sure that inherent methods have base
// types. // types.
if associated_traits.is_none() { if associated_traits.is_none() {
match get_base_type_def_id(self.inference_context, match get_base_type_def_id(self.inference_context,
dummy_sp(), dummy_sp(),
self_type.ty) { self_type.ty) {
None => { None => {
let session = self.crate_context.tcx.sess; let session = self.crate_context.tcx.sess;
session.bug(fmt!( session.bug(fmt!("no base type for external impl with no \
"no base type for external impl \ trait: %s (type %s)!",
with no trait: %s (type %s)!",
session.str_of(implementation.ident), session.str_of(implementation.ident),
ty_to_str(self.crate_context.tcx,self_type.ty))); ty_to_str(self.crate_context.tcx,
self_type.ty)));
} }
Some(_) => { Some(_) => {} // Nothing to do.
// Nothing to do.
} }
} }
}
let mut implementation = *implementation;
// Record all the trait methods. // Record all the trait methods.
let implementation = @implementation;
for associated_traits.iter().advance |trait_ref| { 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); self.add_trait_method(trait_ref.def_id, implementation);
} }
// Add the implementation to the mapping from // Add the implementation to the mapping from implementation to base
// implementation to base type def ID, if there is a base // type def ID, if there is a base type for this implementation.
// type for this implementation.
match get_base_type_def_id(self.inference_context, match get_base_type_def_id(self.inference_context,
dummy_sp(), dummy_sp(),
self_type.ty) { self_type.ty) {
None => { None => {} // Nothing to do.
// Nothing to do.
}
Some(base_type_def_id) => { Some(base_type_def_id) => {
// inherent methods apply to `impl Type` but not // inherent methods apply to `impl Type` but not
// `impl Trait for Type`: // `impl Trait for Type`:
@ -943,7 +919,6 @@ impl CoherenceChecker {
} }
} }
} }
}
// Adds implementations and traits from external crates to the coherence // Adds implementations and traits from external crates to the coherence
// info. // info.
@ -952,22 +927,17 @@ impl CoherenceChecker {
let crate_store = self.crate_context.tcx.sess.cstore; let crate_store = self.crate_context.tcx.sess.cstore;
do iter_crate_data(crate_store) |crate_number, _crate_metadata| { 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, _| { for each_path(crate_store, crate_number) |_, def_like, _| {
match def_like { match def_like {
dl_def(def_mod(def_id)) => { dl_def(def_trait(def_id)) => {
self.add_impls_for_module(&mut impls_seen, self.add_default_methods_for_external_trait(def_id);
}
dl_impl(def_id) => {
self.add_external_impl(&mut impls_seen,
crate_store, crate_store,
def_id); def_id)
}
dl_def(_) | dl_impl(_) | dl_field => {
// Skip this.
loop;
} }
dl_def(_) | dl_field => loop, // Skip this.
} }
} }
} }

View File

@ -10,6 +10,7 @@
//! Utilities for manipulating the char type //! Utilities for manipulating the char type
use container::Container;
use option::{None, Option, Some}; use option::{None, Option, Some};
use str; use str;
use str::{StrSlice, OwnedStr}; use str::{StrSlice, OwnedStr};

View File

@ -29,6 +29,7 @@
#[allow(missing_doc)]; #[allow(missing_doc)];
use cast; use cast;
use container::Container;
use io; use io;
use iterator::IteratorUtil; use iterator::IteratorUtil;
use libc; use libc;
@ -1500,7 +1501,10 @@ mod tests {
fn test_getenv_big() { fn test_getenv_big() {
let mut s = ~""; let mut s = ~"";
let mut i = 0; let mut i = 0;
while i < 100 { s += "aaaaaaaaaa"; i += 1; } while i < 100 {
s = s + "aaaaaaaaaa";
i += 1;
}
let n = make_rand_name(); let n = make_rand_name();
setenv(n, s); setenv(n, s);
debug!(copy s); debug!(copy s);

View File

@ -42,6 +42,7 @@ fn main () {
use cast; use cast;
use cmp; use cmp;
use container::Container;
use int; use int;
use iterator::IteratorUtil; use iterator::IteratorUtil;
use local_data; use local_data;

View File

@ -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)] #[allow(missing_doc)]
pub trait StrSlice<'self> { pub trait StrSlice<'self> {
fn contains<'a>(&self, needle: &'a str) -> bool; fn contains<'a>(&self, needle: &'a str) -> bool;
@ -1158,10 +1169,8 @@ pub trait StrSlice<'self> {
fn any_line_iter(&self) -> AnyLineIterator<'self>; fn any_line_iter(&self) -> AnyLineIterator<'self>;
fn word_iter(&self) -> WordIterator<'self>; fn word_iter(&self) -> WordIterator<'self>;
fn ends_with(&self, needle: &str) -> bool; fn ends_with(&self, needle: &str) -> bool;
fn is_empty(&self) -> bool;
fn is_whitespace(&self) -> bool; fn is_whitespace(&self) -> bool;
fn is_alphanumeric(&self) -> bool; fn is_alphanumeric(&self) -> bool;
fn len(&self) -> uint;
fn char_len(&self) -> uint; fn char_len(&self) -> uint;
fn slice(&self, begin: uint, end: uint) -> &'self str; 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()) 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 * Returns true if the string contains only whitespace
* *
@ -1379,11 +1385,6 @@ impl<'self> StrSlice<'self> for &'self str {
*/ */
#[inline] #[inline]
fn is_alphanumeric(&self) -> bool { self.iter().all(char::is_alphanumeric) } 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 /// Returns the number of characters that a string holds
#[inline] #[inline]
fn char_len(&self) -> uint { self.iter().len_() } fn char_len(&self) -> uint { self.iter().len_() }

View File

@ -94,6 +94,7 @@ use iterator::IteratorUtil;
#[doc(hidden)] #[doc(hidden)]
pub mod ct { pub mod ct {
use char; use char;
use container::Container;
use prelude::*; use prelude::*;
use str; use str;