From 8213e184477c19eba75840e9310266a6529de20a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 24 Feb 2014 18:13:51 -0800 Subject: [PATCH] rustc: Simplify crate loading constraints The previous code passed around a {name,version} pair everywhere, but this is better expressed as a CrateId. This patch changes these paths to store and pass around crate ids instead of these pairs of name/version. This also prepares the code to change the type of hash that is stored in crates. --- src/librustc/metadata/common.rs | 8 +- src/librustc/metadata/creader.rs | 230 ++++++++++++------------------ src/librustc/metadata/cstore.rs | 40 +----- src/librustc/metadata/decoder.rs | 40 +++--- src/librustc/metadata/encoder.rs | 19 +-- src/librustc/metadata/loader.rs | 54 +++---- src/librustc/middle/trans/base.rs | 2 +- src/libsyntax/crateid.rs | 9 ++ 8 files changed, 161 insertions(+), 241 deletions(-) diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 9cf4df287d2f..62f1dcedab45 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -70,12 +70,12 @@ pub static tag_crate_deps: uint = 0x18; pub static tag_crate_dep: uint = 0x19; pub static tag_crate_hash: uint = 0x1a; +pub static tag_crate_crateid: uint = 0x1b; -pub static tag_parent_item: uint = 0x1b; +pub static tag_parent_item: uint = 0x1c; -pub static tag_crate_dep_name: uint = 0x1c; -pub static tag_crate_dep_hash: uint = 0x1d; -pub static tag_crate_dep_vers: uint = 0x1e; +pub static tag_crate_dep_crateid: uint = 0x1d; +pub static tag_crate_dep_hash: uint = 0x1e; pub static tag_mod_impl: uint = 0x1f; diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 9f14b571d822..1108917cdb1d 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -79,7 +79,7 @@ struct cache_entry { cnum: ast::CrateNum, span: Span, hash: ~str, - crateid: CrateId, + crate_id: CrateId, } fn dump_crates(crate_cache: &[cache_entry]) { @@ -95,10 +95,10 @@ fn warn_if_multiple_versions(e: &mut Env, diag: @SpanHandler, crate_cache: &[cache_entry]) { if crate_cache.len() != 0u { - let name = crate_cache[crate_cache.len() - 1].crateid.name.clone(); + let name = crate_cache[crate_cache.len() - 1].crate_id.name.clone(); let (matches, non_matches) = crate_cache.partitioned(|entry| - name == entry.crateid.name); + name == entry.crate_id.name); assert!(!matches.is_empty()); @@ -107,7 +107,7 @@ fn warn_if_multiple_versions(e: &mut Env, format!("using multiple versions of crate `{}`", name)); for match_ in matches.iter() { diag.span_note(match_.span, "used here"); - loader::note_crateid_attr(diag, &match_.crateid); + loader::note_crateid_attr(diag, &match_.crate_id); } } @@ -146,14 +146,9 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) { return; } - match extract_crate_info(i) { + match extract_crate_info(e, i) { Some(info) => { - let cnum = resolve_crate(e, - None, - info.ident.clone(), - info.name.clone(), - info.version.clone(), - ~"", + let cnum = resolve_crate(e, None, info.ident, &info.crate_id, "", i.span); e.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } @@ -163,38 +158,33 @@ fn visit_view_item(e: &mut Env, i: &ast::ViewItem) { struct CrateInfo { ident: ~str, - name: ~str, - version: ~str, + crate_id: CrateId, id: ast::NodeId, } -fn extract_crate_info(i: &ast::ViewItem) -> Option { +fn extract_crate_info(e: &Env, i: &ast::ViewItem) -> Option { match i.node { ast::ViewItemExternMod(ident, ref path_opt, id) => { let ident = token::get_ident(ident); debug!("resolving extern crate stmt. ident: {:?} path_opt: {:?}", ident, path_opt); - let (name, version) = match *path_opt { + let crate_id = match *path_opt { Some((ref path_str, _)) => { let crateid: Option = from_str(path_str.get()); match crateid { - None => (~"", ~""), - Some(crateid) => { - let version = match crateid.version { - None => ~"", - Some(ref ver) => ver.to_str(), - }; - (crateid.name.to_str(), version) + None => { + e.sess.span_err(i.span, "malformed crate id"); + return None } + Some(id) => id } } - None => (ident.get().to_str(), ~""), + None => from_str(ident.get().to_str()).unwrap() }; Some(CrateInfo { - ident: ident.get().to_str(), - name: name, - version: version, - id: id, + ident: ident.get().to_str(), + crate_id: crate_id, + id: id, }) } _ => None @@ -285,100 +275,93 @@ fn visit_item(e: &Env, i: &ast::Item) { } } -fn existing_match(e: &Env, name: &str, version: &str, hash: &str) -> Option { +fn existing_match(e: &Env, crate_id: &CrateId, + hash: &str) -> Option { let crate_cache = e.crate_cache.borrow(); for c in crate_cache.get().iter() { - let crateid_version = match c.crateid.version { - None => ~"0.0", - Some(ref ver) => ver.to_str(), - }; - if (name.is_empty() || name == c.crateid.name) && - (version.is_empty() || version == crateid_version) && - (hash.is_empty() || hash == c.hash) { - return Some(c.cnum); + if crate_id.matches(&c.crate_id) && + (hash.is_empty() || hash == c.hash.as_slice()) { + return Some(c.cnum) } } None } fn resolve_crate(e: &mut Env, - root_ident: Option<~str>, - ident: ~str, - name: ~str, - version: ~str, - hash: ~str, + root_ident: Option<&str>, + ident: &str, + crate_id: &CrateId, + hash: &str, span: Span) -> ast::CrateNum { - match existing_match(e, name, version, hash) { - None => { - let load_ctxt = loader::Context { - sess: e.sess, - span: span, - ident: ident, - name: name, - version: version, - hash: hash, - os: e.os, - intr: e.intr - }; - let loader::Library { - dylib, rlib, metadata - } = load_ctxt.load_library_crate(root_ident.clone()); - - let attrs = decoder::get_crate_attributes(metadata.as_slice()); - let crateid = attr::find_crateid(attrs).unwrap(); - let hash = decoder::get_crate_hash(metadata.as_slice()); - - // Claim this crate number and cache it - let cnum = e.next_crate_num; - { - let mut crate_cache = e.crate_cache.borrow_mut(); - crate_cache.get().push(cache_entry { - cnum: cnum, + match existing_match(e, crate_id, hash) { + None => { + let load_ctxt = loader::Context { + sess: e.sess, span: span, + ident: ident, + crate_id: crate_id, hash: hash, - crateid: crateid, + os: e.os, + intr: e.intr + }; + let loader::Library { + dylib, rlib, metadata + } = load_ctxt.load_library_crate(root_ident); + + let crate_id = decoder::get_crate_id(metadata.as_slice()); + let hash = decoder::get_crate_hash(metadata.as_slice()); + + // Claim this crate number and cache it + let cnum = e.next_crate_num; + { + let mut crate_cache = e.crate_cache.borrow_mut(); + crate_cache.get().push(cache_entry { + cnum: cnum, + span: span, + hash: hash, + crate_id: crate_id, + }); + } + e.next_crate_num += 1; + + // Maintain a reference to the top most crate. + let root_crate = match root_ident { + Some(c) => c, + None => load_ctxt.ident.clone() + }; + + // Now resolve the crates referenced by this crate + let cnum_map = resolve_crate_deps(e, + Some(root_crate), + metadata.as_slice(), + span); + + let cmeta = @cstore::crate_metadata { + name: load_ctxt.crate_id.name.to_owned(), + data: metadata, + cnum_map: cnum_map, + cnum: cnum + }; + + let cstore = e.sess.cstore; + cstore.set_crate_data(cnum, cmeta); + cstore.add_used_crate_source(cstore::CrateSource { + dylib: dylib, + rlib: rlib, + cnum: cnum, }); + return cnum; + } + Some(cnum) => { + return cnum; } - e.next_crate_num += 1; - - // Maintain a reference to the top most crate. - let root_crate = match root_ident { - Some(c) => c, - None => load_ctxt.ident.clone() - }; - - // Now resolve the crates referenced by this crate - let cnum_map = resolve_crate_deps(e, - Some(root_crate), - metadata.as_slice(), - span); - - let cmeta = @cstore::crate_metadata { - name: load_ctxt.name, - data: metadata, - cnum_map: cnum_map, - cnum: cnum - }; - - let cstore = e.sess.cstore; - cstore.set_crate_data(cnum, cmeta); - cstore.add_used_crate_source(cstore::CrateSource { - dylib: dylib, - rlib: rlib, - cnum: cnum, - }); - return cnum; - } - Some(cnum) => { - return cnum; - } } } // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(e: &mut Env, - root_ident: Option<~str>, + root_ident: Option<&str>, cdata: &[u8], span : Span) -> cstore::cnum_map { debug!("resolving deps of external crate"); @@ -388,31 +371,13 @@ fn resolve_crate_deps(e: &mut Env, let r = decoder::get_crate_deps(cdata); for dep in r.iter() { let extrn_cnum = dep.cnum; - let cname_str = token::get_ident(dep.name); - debug!("resolving dep crate {} ver: {} hash: {}", - cname_str, dep.vers, dep.hash); - match existing_match(e, - cname_str.get(), - dep.vers, - dep.hash) { - Some(local_cnum) => { - debug!("already have it"); - // We've already seen this crate - cnum_map.insert(extrn_cnum, local_cnum); - } - None => { - debug!("need to load it"); - // This is a new one so we've got to load it - let local_cnum = resolve_crate(e, - root_ident.clone(), - cname_str.get().to_str(), - cname_str.get().to_str(), - dep.vers.clone(), - dep.hash.clone(), - span); - cnum_map.insert(extrn_cnum, local_cnum); - } - } + debug!("resolving dep crate {} hash: `{}`", dep.crate_id, dep.hash); + let local_cnum = resolve_crate(e, root_ident, + dep.crate_id.name.as_slice(), + &dep.crate_id, + dep.hash, + span); + cnum_map.insert(extrn_cnum, local_cnum); } return @RefCell::new(cnum_map); } @@ -439,14 +404,9 @@ impl Loader { impl CrateLoader for Loader { fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate { - let info = extract_crate_info(krate).unwrap(); - let cnum = resolve_crate(&mut self.env, - None, - info.ident.clone(), - info.name.clone(), - info.version.clone(), - ~"", - krate.span); + let info = extract_crate_info(&self.env, krate).unwrap(); + let cnum = resolve_crate(&mut self.env, None, info.ident, + &info.crate_id, "", krate.span); let library = self.env.sess.cstore.get_used_crate_source(cnum).unwrap(); MacroCrate { lib: library.dylib, diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index ce6b5af8d0e0..12461ddbe715 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -21,6 +21,7 @@ use collections::HashMap; use extra::c_vec::CVec; use syntax::ast; use syntax::parse::token::IdentInterner; +use syntax::crateid::CrateId; // A map from external crate numbers (as decoded from some crate file) to // local crate numbers (as generated during this session). Each external @@ -96,9 +97,9 @@ impl CStore { decoder::get_crate_hash(cdata.data()) } - pub fn get_crate_vers(&self, cnum: ast::CrateNum) -> ~str { + pub fn get_crate_id(&self, cnum: ast::CrateNum) -> CrateId { let cdata = self.get_crate_data(cnum); - decoder::get_crate_vers(cdata.data()) + decoder::get_crate_id(cdata.data()) } pub fn set_crate_data(&self, cnum: ast::CrateNum, data: @crate_metadata) { @@ -191,41 +192,6 @@ impl CStore { let extern_mod_crate_map = self.extern_mod_crate_map.borrow(); extern_mod_crate_map.get().find(&emod_id).map(|x| *x) } - - // returns hashes of crates directly used by this crate. Hashes are sorted by - // (crate name, crate version, crate hash) in lexicographic order (not semver) - pub fn get_dep_hashes(&self) -> ~[~str] { - let mut result = ~[]; - - let extern_mod_crate_map = self.extern_mod_crate_map.borrow(); - for (_, &cnum) in extern_mod_crate_map.get().iter() { - let cdata = self.get_crate_data(cnum); - let hash = decoder::get_crate_hash(cdata.data()); - let vers = decoder::get_crate_vers(cdata.data()); - debug!("Add hash[{}]: {} {}", cdata.name, vers, hash); - result.push(crate_hash { - name: cdata.name.clone(), - vers: vers, - hash: hash - }); - } - - result.sort(); - - debug!("sorted:"); - for x in result.iter() { - debug!(" hash[{}]: {}", x.name, x.hash); - } - - result.move_iter().map(|crate_hash { hash, ..}| hash).collect() - } -} - -#[deriving(Clone, TotalEq, TotalOrd)] -struct crate_hash { - name: ~str, - vers: ~str, - hash: ~str, } impl crate_metadata { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index f9f55fbc1bb0..f365ddef94f5 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -17,7 +17,6 @@ use metadata::common::*; use metadata::csearch::StaticMethodInfo; use metadata::csearch; use metadata::cstore; -use metadata::decoder; use metadata::tydecode::{parse_ty_data, parse_def_id, parse_type_param_def_data, parse_bare_fn_ty_data, parse_trait_ref_data}; @@ -44,6 +43,7 @@ use syntax::parse::token; use syntax::print::pprust; use syntax::ast; use syntax::codemap; +use syntax::crateid::CrateId; type Cmd = @crate_metadata; @@ -1108,9 +1108,8 @@ pub fn get_crate_attributes(data: &[u8]) -> ~[ast::Attribute] { #[deriving(Clone)] pub struct CrateDep { cnum: ast::CrateNum, - name: ast::Ident, - vers: ~str, - hash: ~str + crate_id: CrateId, + hash: ~str, } pub fn get_crate_deps(data: &[u8]) -> ~[CrateDep] { @@ -1123,10 +1122,13 @@ pub fn get_crate_deps(data: &[u8]) -> ~[CrateDep] { d.as_str_slice().to_str() } reader::tagged_docs(depsdoc, tag_crate_dep, |depdoc| { - deps.push(CrateDep {cnum: crate_num, - name: token::str_to_ident(docstr(depdoc, tag_crate_dep_name)), - vers: docstr(depdoc, tag_crate_dep_vers), - hash: docstr(depdoc, tag_crate_dep_hash)}); + let crate_id = from_str(docstr(depdoc, tag_crate_dep_crateid)).unwrap(); + let hash = docstr(depdoc, tag_crate_dep_hash); + deps.push(CrateDep { + cnum: crate_num, + crate_id: crate_id, + hash: hash, + }); crate_num += 1; true }); @@ -1135,17 +1137,9 @@ pub fn get_crate_deps(data: &[u8]) -> ~[CrateDep] { fn list_crate_deps(data: &[u8], out: &mut io::Writer) -> io::IoResult<()> { try!(write!(out, "=External Dependencies=\n")); - - let r = get_crate_deps(data); - for dep in r.iter() { - try!(write!(out, - "{} {}-{}-{}\n", - dep.cnum, - token::get_ident(dep.name), - dep.hash, - dep.vers)); + for dep in get_crate_deps(data).iter() { + try!(write!(out, "{} {}-{}\n", dep.cnum, dep.crate_id, dep.hash)); } - try!(write!(out, "\n")); Ok(()) } @@ -1156,12 +1150,10 @@ pub fn get_crate_hash(data: &[u8]) -> ~str { hashdoc.as_str_slice().to_str() } -pub fn get_crate_vers(data: &[u8]) -> ~str { - let attrs = decoder::get_crate_attributes(data); - match attr::find_crateid(attrs) { - None => ~"0.0", - Some(crateid) => crateid.version_or_default().to_str(), - } +pub fn get_crate_id(data: &[u8]) -> CrateId { + let cratedoc = reader::Doc(data); + let hashdoc = reader::get_doc(cratedoc, tag_crate_crateid); + from_str(hashdoc.as_str_slice()).unwrap() } pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Writer) -> io::IoResult<()> { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 285a7411270f..976c1ee92d3d 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -40,6 +40,7 @@ use syntax::ast_util::*; use syntax::ast_util; use syntax::attr::AttrMetaMethods; use syntax::attr; +use syntax::crateid::CrateId; use syntax::diagnostic::SpanHandler; use syntax::parse::token::InternedString; use syntax::parse::token::special_idents; @@ -1510,8 +1511,7 @@ fn encode_crate_deps(ebml_w: &mut writer::Encoder, cstore: &cstore::CStore) { cstore.iter_crate_data(|key, val| { let dep = decoder::CrateDep { cnum: key, - name: token::str_to_ident(val.name), - vers: decoder::get_crate_vers(val.data()), + crate_id: decoder::get_crate_id(val.data()), hash: decoder::get_crate_hash(val.data()) }; deps.push(dep); @@ -1729,12 +1729,8 @@ fn encode_misc_info(ecx: &EncodeContext, fn encode_crate_dep(ebml_w: &mut writer::Encoder, dep: decoder::CrateDep) { ebml_w.start_tag(tag_crate_dep); - ebml_w.start_tag(tag_crate_dep_name); - let s = token::get_ident(dep.name); - ebml_w.writer.write(s.get().as_bytes()); - ebml_w.end_tag(); - ebml_w.start_tag(tag_crate_dep_vers); - ebml_w.writer.write(dep.vers.as_bytes()); + ebml_w.start_tag(tag_crate_dep_crateid); + ebml_w.writer.write(dep.crate_id.to_str().as_bytes()); ebml_w.end_tag(); ebml_w.start_tag(tag_crate_dep_hash); ebml_w.writer.write(dep.hash.as_bytes()); @@ -1748,6 +1744,12 @@ fn encode_hash(ebml_w: &mut writer::Encoder, hash: &str) { ebml_w.end_tag(); } +fn encode_crate_id(ebml_w: &mut writer::Encoder, crate_id: &CrateId) { + ebml_w.start_tag(tag_crate_crateid); + ebml_w.writer.write(crate_id.to_str().as_bytes()); + ebml_w.end_tag(); +} + // NB: Increment this as you change the metadata encoding version. pub static metadata_encoding_version : &'static [u8] = &[0x72, //'r' as u8, @@ -1806,6 +1808,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate) let mut ebml_w = writer::Encoder(wr); + encode_crate_id(&mut ebml_w, &ecx.link_meta.crateid); encode_hash(&mut ebml_w, ecx.link_meta.crate_hash); let mut i = ebml_w.writer.tell().unwrap(); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 1f5b76953dcd..faef2412e780 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -44,13 +44,12 @@ pub enum Os { OsFreebsd } -pub struct Context { +pub struct Context<'a> { sess: Session, span: Span, - ident: ~str, - name: ~str, - version: ~str, - hash: ~str, + ident: &'a str, + crate_id: &'a CrateId, + hash: &'a str, os: Os, intr: @IdentInterner } @@ -79,8 +78,8 @@ fn realpath(p: &Path) -> Path { } } -impl Context { - pub fn load_library_crate(&self, root_ident: Option<~str>) -> Library { +impl<'a> Context<'a> { + pub fn load_library_crate(&self, root_ident: Option<&str>) -> Library { match self.find_library_crate() { Some(t) => t, None => { @@ -101,8 +100,8 @@ impl Context { let (dyprefix, dysuffix) = self.dylibname(); // want: crate_name.dir_part() + prefix + crate_name.file_part + "-" - let dylib_prefix = format!("{}{}-", dyprefix, self.name); - let rlib_prefix = format!("lib{}-", self.name); + let dylib_prefix = format!("{}{}-", dyprefix, self.crate_id.name); + let rlib_prefix = format!("lib{}-", self.crate_id.name); let mut candidates = HashMap::new(); @@ -196,7 +195,8 @@ impl Context { 1 => Some(libraries[0]), _ => { self.sess.span_err(self.span, - format!("multiple matching crates for `{}`", self.name)); + format!("multiple matching crates for `{}`", + self.crate_id.name)); self.sess.note("candidates:"); for lib in libraries.iter() { match lib.dylib { @@ -243,11 +243,12 @@ impl Context { debug!("matching -- {}, hash: {}", file, hash); let vers = match parts.next() { Some(v) => v, None => return None }; debug!("matching -- {}, vers: {}", file, vers); - if !self.version.is_empty() && self.version.as_slice() != vers { - return None + match self.crate_id.version { + Some(ref version) if version.as_slice() != vers => return None, + Some(..) | None => {} } debug!("matching -- {}, vers ok (requested {})", file, - self.version); + self.crate_id.version); // hashes in filenames are prefixes of the "true hash" if self.hash.is_empty() || self.hash.starts_with(hash) { debug!("matching -- {}, hash ok (requested {})", file, self.hash); @@ -275,7 +276,7 @@ impl Context { if m.len() > 1 { self.sess.span_err(self.span, format!("multiple {} candidates for `{}` \ - found", flavor, self.name)); + found", flavor, self.crate_id.name)); for (i, path) in m.iter().enumerate() { self.sess.span_note(self.span, format!(r"candidate \#{}: {}", i + 1, @@ -289,8 +290,7 @@ impl Context { info!("{} reading meatadata from: {}", flavor, lib.display()); match get_metadata_section(self.os, &lib) { Some(blob) => { - if crate_matches(blob.as_slice(), self.name, - self.version, self.hash) { + if crate_matches(blob.as_slice(), self.crate_id, self.hash){ *slot = Some(blob); } else { info!("metadata mismatch"); @@ -323,23 +323,13 @@ pub fn note_crateid_attr(diag: @SpanHandler, crateid: &CrateId) { diag.handler().note(format!("crate_id: {}", crateid.to_str())); } -fn crate_matches(crate_data: &[u8], - name: &str, - version: &str, - hash: &str) -> bool { - let attrs = decoder::get_crate_attributes(crate_data); - match attr::find_crateid(attrs) { - None => false, - Some(crateid) => { - if !hash.is_empty() { - let chash = decoder::get_crate_hash(crate_data); - if chash.as_slice() != hash { return false; } - } - name == crateid.name && - (version.is_empty() || - crateid.version_or_default() == version) - } +fn crate_matches(crate_data: &[u8], crate_id: &CrateId, hash: &str) -> bool { + let other_id = decoder::get_crate_id(crate_data); + if !crate_id.matches(&other_id) { return false } + if hash != "" && hash != decoder::get_crate_hash(crate_data).as_slice() { + return false } + return true; } impl ArchiveMetadata { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 6a7694b2b81a..553dbe2ae6e3 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2488,7 +2488,7 @@ pub fn fill_crate_map(ccx: @CrateContext, map: ValueRef) { let cdata = cstore.get_crate_data(i); let nm = symname(format!("_rust_crate_map_{}", cdata.name), cstore.get_crate_hash(i), - cstore.get_crate_vers(i)); + cstore.get_crate_id(i).version_or_default()); let cr = nm.with_c_str(|buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type.to_ref(), buf) diff --git a/src/libsyntax/crateid.rs b/src/libsyntax/crateid.rs index 659cd13c94dd..b5f02fb7e644 100644 --- a/src/libsyntax/crateid.rs +++ b/src/libsyntax/crateid.rs @@ -107,6 +107,15 @@ impl CrateId { pub fn short_name_with_version(&self) -> ~str { format!("{}-{}", self.name, self.version_or_default()) } + + pub fn matches(&self, other: &CrateId) -> bool { + // FIXME: why does this not match on `path`? + if self.name != other.name { return false } + match (&self.version, &other.version) { + (&Some(ref v1), &Some(ref v2)) => v1 == v2, + _ => true, + } + } } #[test]