diff --git a/mk/crates.mk b/mk/crates.mk index fafe77c78da..e20cb06e3a8 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -53,7 +53,8 @@ TARGET_CRATES := libc std flate arena term \ serialize getopts collections test time rand \ log regex graphviz core rbml alloc \ unicode -RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_driver rustc_trans rustc_back rustc_llvm +RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \ + rustc_trans rustc_back rustc_llvm HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc regex_macros fmt_macros CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc @@ -67,11 +68,12 @@ DEPS_std := core libc rand alloc collections unicode \ DEPS_graphviz := std DEPS_syntax := std term serialize log fmt_macros arena libc DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \ - rustc_typeck log syntax serialize rustc_llvm rustc_trans + rustc_typeck rustc_resolve log syntax serialize rustc_llvm rustc_trans DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ log syntax serialize rustc_llvm DEPS_rustc_typeck := rustc syntax DEPS_rustc_borrowck := rustc log graphviz syntax +DEPS_rustc_resolve := rustc log syntax DEPS_rustc := syntax flate arena serialize getopts rbml \ time log graphviz rustc_llvm rustc_back DEPS_rustc_llvm := native:rustllvm libc std @@ -118,9 +120,11 @@ DOC_CRATES := $(filter-out rustc, \ $(filter-out rustc_trans, \ $(filter-out rustc_typeck, \ $(filter-out rustc_borrowck, \ + $(filter-out rustc_resolve, \ $(filter-out rustc_driver, \ - $(filter-out syntax, $(CRATES))))))) -COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_typeck rustc_driver syntax + $(filter-out syntax, $(CRATES)))))))) +COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \ + rustc_typeck rustc_driver syntax # This macro creates some simple definitions for each crate being built, just # some munging of all of the parameters above. diff --git a/mk/tests.mk b/mk/tests.mk index 3340f9b4969..a5495a44a11 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -21,7 +21,8 @@ $(eval $(call RUST_CRATE,coretest)) TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) coretest TEST_DOC_CRATES = $(DOC_CRATES) -TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_trans,$(HOST_CRATES)) +TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans,\ + $(HOST_CRATES)) TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES) ###################################################################### diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 90e9973c3f3..669a5144970 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -90,7 +90,6 @@ pub mod middle { pub mod reachable; pub mod region; pub mod recursion_limit; - pub mod resolve; pub mod resolve_lifetime; pub mod stability; pub mod subst; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index a474af7c6e1..b702f4925d8 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -19,7 +19,6 @@ use metadata::cstore; use metadata::decoder; use middle::def; use middle::lang_items; -use middle::resolve; use middle::ty; use rbml; @@ -148,7 +147,7 @@ pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) } pub fn get_trait_item_name_and_kind(cstore: &cstore::CStore, def: ast::DefId) - -> (ast::Name, resolve::TraitItemKind) { + -> (ast::Name, def::TraitItemKind) { let cdata = cstore.get_crate_data(def.krate); decoder::get_trait_item_name_and_kind(cstore.intr.clone(), &*cdata, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b89c5dbcd08..d8168814c6c 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -27,7 +27,6 @@ use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, parse_predicate_data}; use middle::def; use middle::lang_items; -use middle::resolve::{TraitItemKind, TypeTraitItemKind}; use middle::subst; use middle::ty::{ImplContainer, TraitContainer}; use middle::ty::{mod, Ty}; @@ -785,15 +784,15 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId) pub fn get_trait_item_name_and_kind(intr: Rc, cdata: Cmd, id: ast::NodeId) - -> (ast::Name, TraitItemKind) { + -> (ast::Name, def::TraitItemKind) { let doc = lookup_item(id, cdata.data()); let name = item_name(&*intr, doc); match item_sort(doc) { 'r' | 'p' => { let explicit_self = get_explicit_self(doc); - (name, TraitItemKind::from_explicit_self_category(explicit_self)) + (name, def::TraitItemKind::from_explicit_self_category(explicit_self)) } - 't' => (name, TypeTraitItemKind), + 't' => (name, def::TypeTraitItemKind), c => { panic!("get_trait_item_name_and_kind(): unknown trait item kind \ in metadata: `{}`", c) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index cc383aa217a..deb86397eda 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -21,10 +21,10 @@ use metadata::common::*; use metadata::cstore; use metadata::decoder; use metadata::tyencode; +use middle::def; use middle::ty::{lookup_item_type}; use middle::ty::{mod, Ty}; use middle::stability; -use middle; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use serialize::Encodable; @@ -66,7 +66,7 @@ pub type EncodeInlinedItem<'a> = |ecx: &EncodeContext, pub struct EncodeParams<'a, 'tcx: 'a> { pub diag: &'a SpanHandler, pub tcx: &'a ty::ctxt<'tcx>, - pub reexports2: &'a middle::resolve::ExportMap2, + pub reexports: &'a def::ExportMap, pub item_symbols: &'a RefCell>, pub link_meta: &'a LinkMeta, pub cstore: &'a cstore::CStore, @@ -77,7 +77,7 @@ pub struct EncodeParams<'a, 'tcx: 'a> { pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a SpanHandler, pub tcx: &'a ty::ctxt<'tcx>, - pub reexports2: &'a middle::resolve::ExportMap2, + pub reexports: &'a def::ExportMap, pub item_symbols: &'a RefCell>, pub link_meta: &'a LinkMeta, pub cstore: &'a cstore::CStore, @@ -379,7 +379,7 @@ fn encode_path>(rbml_w: &mut Encoder, path: PI) { } fn encode_reexported_static_method(rbml_w: &mut Encoder, - exp: &middle::resolve::Export2, + exp: &def::Export, method_def_id: DefId, method_name: ast::Name) { debug!("(encode reexported static method) {}::{}", @@ -398,7 +398,7 @@ fn encode_reexported_static_method(rbml_w: &mut Encoder, fn encode_reexported_static_base_methods(ecx: &EncodeContext, rbml_w: &mut Encoder, - exp: &middle::resolve::Export2) + exp: &def::Export) -> bool { let impl_items = ecx.tcx.impl_items.borrow(); match ecx.tcx.inherent_impls.borrow().get(&exp.def_id) { @@ -428,7 +428,7 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext, fn encode_reexported_static_trait_methods(ecx: &EncodeContext, rbml_w: &mut Encoder, - exp: &middle::resolve::Export2) + exp: &def::Export) -> bool { match ecx.tcx.trait_items_cache.borrow().get(&exp.def_id) { Some(trait_items) => { @@ -449,10 +449,8 @@ fn encode_reexported_static_trait_methods(ecx: &EncodeContext, fn encode_reexported_static_methods(ecx: &EncodeContext, rbml_w: &mut Encoder, mod_path: PathElems, - exp: &middle::resolve::Export2) { + exp: &def::Export) { if let Some(ast_map::NodeItem(item)) = ecx.tcx.map.find(exp.def_id.node) { - let original_name = token::get_ident(item.ident); - let path_differs = ecx.tcx.map.with_path(exp.def_id.node, |path| { let (mut a, mut b) = (path, mod_path.clone()); loop { @@ -474,16 +472,16 @@ fn encode_reexported_static_methods(ecx: &EncodeContext, // encoded metadata for static methods relative to Bar, // but not yet for Foo. // - if path_differs || original_name.get() != exp.name { + if path_differs || item.ident.name != exp.name { if !encode_reexported_static_base_methods(ecx, rbml_w, exp) { if encode_reexported_static_trait_methods(ecx, rbml_w, exp) { debug!("(encode reexported static methods) {} [trait]", - original_name); + item.ident.name); } } else { debug!("(encode reexported static methods) {} [base]", - original_name); + item.ident.name); } } } @@ -519,7 +517,7 @@ fn encode_reexports(ecx: &EncodeContext, id: NodeId, path: PathElems) { debug!("(encoding info for module) encoding reexports for {}", id); - match ecx.reexports2.get(&id) { + match ecx.reexports.get(&id) { Some(ref exports) => { debug!("(encoding info for module) found reexports for {}", id); for exp in exports.iter() { @@ -534,7 +532,7 @@ fn encode_reexports(ecx: &EncodeContext, rbml_w.wr_str(def_to_string(exp.def_id).as_slice()); rbml_w.end_tag(); rbml_w.start_tag(tag_items_data_item_reexport_name); - rbml_w.wr_str(exp.name.as_slice()); + rbml_w.wr_str(exp.name.as_str()); rbml_w.end_tag(); rbml_w.end_tag(); encode_reexported_static_methods(ecx, rbml_w, path.clone(), exp); @@ -2071,7 +2069,7 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter, item_symbols, diag, tcx, - reexports2, + reexports, cstore, encode_inlined_item, link_meta, @@ -2081,7 +2079,7 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter, let ecx = EncodeContext { diag: diag, tcx: tcx, - reexports2: reexports2, + reexports: reexports, item_symbols: item_symbols, link_meta: link_meta, cstore: cstore, diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index b32eb64025f..90242a3252e 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -12,8 +12,7 @@ // recursively. use session::Session; -use middle::resolve; -use middle::def::{DefStatic, DefConst}; +use middle::def::{DefStatic, DefConst, DefMap}; use syntax::ast; use syntax::{ast_util, ast_map}; @@ -22,7 +21,7 @@ use syntax::visit; struct CheckCrateVisitor<'a, 'ast: 'a> { sess: &'a Session, - def_map: &'a resolve::DefMap, + def_map: &'a DefMap, ast_map: &'a ast_map::Map<'ast> } @@ -34,7 +33,7 @@ impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> { pub fn check_crate<'ast>(sess: &Session, krate: &ast::Crate, - def_map: &resolve::DefMap, + def_map: &DefMap, ast_map: &ast_map::Map<'ast>) { let mut visitor = CheckCrateVisitor { sess: sess, @@ -60,7 +59,7 @@ struct CheckItemRecursionVisitor<'a, 'ast: 'a> { root_it: &'a ast::Item, sess: &'a Session, ast_map: &'a ast_map::Map<'ast>, - def_map: &'a resolve::DefMap, + def_map: &'a DefMap, idstack: Vec } @@ -68,7 +67,7 @@ struct CheckItemRecursionVisitor<'a, 'ast: 'a> { // FIXME: Should use the dependency graph when it's available (#1356) pub fn check_item_recursion<'a>(sess: &'a Session, ast_map: &'a ast_map::Map, - def_map: &'a resolve::DefMap, + def_map: &'a DefMap, it: &'a ast::Item) { let mut visitor = CheckItemRecursionVisitor { diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 20a0dbdc1ee..a582907612f 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -10,11 +10,16 @@ pub use self::Def::*; pub use self::MethodProvenance::*; +pub use self::TraitItemKind::*; use middle::subst::ParamSpace; +use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory}; +use util::nodemap::NodeMap; use syntax::ast; use syntax::ast_util::local_def; +use std::cell::RefCell; + #[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Def { DefFn(ast::DefId, bool /* is_ctor */), @@ -56,6 +61,18 @@ pub enum Def { DefMethod(ast::DefId /* method */, Option /* trait */, MethodProvenance), } +// Definition mapping +pub type DefMap = RefCell>; +// This is the replacement export map. It maps a module to all of the exports +// within. +pub type ExportMap = NodeMap>; + +#[deriving(Copy)] +pub struct Export { + pub name: ast::Name, // The name of the target. + pub def_id: ast::DefId, // The definition of the target. +} + #[deriving(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum MethodProvenance { FromTrait(ast::DefId), @@ -88,6 +105,25 @@ impl TyParamProvenance { } } +#[deriving(Clone, Copy, Eq, PartialEq)] +pub enum TraitItemKind { + NonstaticMethodTraitItemKind, + StaticMethodTraitItemKind, + TypeTraitItemKind, +} + +impl TraitItemKind { + pub fn from_explicit_self_category(explicit_self_category: + ExplicitSelfCategory) + -> TraitItemKind { + if explicit_self_category == StaticExplicitSelfCategory { + StaticMethodTraitItemKind + } else { + NonstaticMethodTraitItemKind + } + } +} + impl Def { pub fn def_id(&self) -> ast::DefId { match *self { @@ -122,4 +158,3 @@ impl Def { } } } - diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 8ef8e091c94..0a6c29d1cb6 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -9,7 +9,6 @@ // except according to those terms. use middle::def::*; -use middle::resolve; use middle::ty; use util::nodemap::FnvHashMap; @@ -21,7 +20,7 @@ pub type PatIdMap = FnvHashMap; // This is used because same-named variables in alternative patterns need to // use the NodeId of their namesake in the first pattern. -pub fn pat_id_map(dm: &resolve::DefMap, pat: &ast::Pat) -> PatIdMap { +pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap { let mut map = FnvHashMap::new(); pat_bindings(dm, pat, |_bm, p_id, _s, path1| { map.insert(path1.node, p_id); @@ -29,7 +28,7 @@ pub fn pat_id_map(dm: &resolve::DefMap, pat: &ast::Pat) -> PatIdMap { map } -pub fn pat_is_refutable(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { +pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { ast::PatLit(_) | ast::PatRange(_, _) => true, ast::PatEnum(_, _) | @@ -45,7 +44,7 @@ pub fn pat_is_refutable(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { } } -pub fn pat_is_variant_or_struct(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { +pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | @@ -59,7 +58,7 @@ pub fn pat_is_variant_or_struct(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { } } -pub fn pat_is_const(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { +pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { ast::PatIdent(_, _, None) | ast::PatEnum(..) => { match dm.borrow().get(&pat.id) { @@ -71,7 +70,7 @@ pub fn pat_is_const(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { } } -pub fn pat_is_binding(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { +pub fn pat_is_binding(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { ast::PatIdent(..) => { !pat_is_variant_or_struct(dm, pat) && @@ -81,7 +80,7 @@ pub fn pat_is_binding(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { } } -pub fn pat_is_binding_or_wild(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { +pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { ast::PatIdent(..) => pat_is_binding(dm, pat), ast::PatWild(_) => true, @@ -91,7 +90,7 @@ pub fn pat_is_binding_or_wild(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { /// Call `it` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` -pub fn pat_bindings(dm: &resolve::DefMap, pat: &ast::Pat, mut it: I) where +pub fn pat_bindings(dm: &DefMap, pat: &ast::Pat, mut it: I) where I: FnMut(ast::BindingMode, ast::NodeId, Span, &ast::SpannedIdent), { walk_pat(pat, |p| { @@ -107,7 +106,7 @@ pub fn pat_bindings(dm: &resolve::DefMap, pat: &ast::Pat, mut it: I) where /// Checks if the pattern contains any patterns that bind something to /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`. -pub fn pat_contains_bindings(dm: &resolve::DefMap, pat: &ast::Pat) -> bool { +pub fn pat_contains_bindings(dm: &DefMap, pat: &ast::Pat) -> bool { let mut contains_bindings = false; walk_pat(pat, |p| { if pat_is_binding(dm, p) { diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 8cce1321d72..8c566dd288e 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -11,17 +11,20 @@ //! A pass that checks to make sure private fields and methods aren't used //! outside their scopes. This pass will also generate a set of exported items //! which are available for use externally when compiled as a library. +pub use self::PrivateDep::*; +pub use self::ImportUse::*; +pub use self::LastPrivate::*; use self::PrivacyResult::*; use self::FieldName::*; use std::mem::replace; use metadata::csearch; -use middle::{def, resolve}; +use middle::def; use middle::ty::{mod, Ty}; use middle::ty::{MethodCall, MethodMap, MethodOrigin, MethodParam, MethodTypeParam}; use middle::ty::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject}; -use util::nodemap::{NodeMap, NodeSet}; +use util::nodemap::{DefIdSet, NodeMap, NodeSet}; use syntax::{ast, ast_map}; use syntax::ast_util::{is_local, local_def, PostExpansionMethod}; @@ -29,16 +32,59 @@ use syntax::codemap::Span; use syntax::parse::token; use syntax::visit::{mod, Visitor}; -type Context<'a, 'tcx> = (&'a MethodMap<'tcx>, &'a resolve::ExportMap2); +type Context<'a, 'tcx> = (&'a MethodMap<'tcx>, &'a def::ExportMap); /// A set of AST nodes exported by the crate. pub type ExportedItems = NodeSet; +/// A set containing all exported definitions from external crates. +/// The set does not contain any entries from local crates. +pub type ExternalExports = DefIdSet; + /// A set of AST nodes that are fully public in the crate. This map is used for /// documentation purposes (reexporting a private struct inlines the doc, /// reexporting a public struct doesn't inline the doc). pub type PublicItems = NodeSet; +// FIXME: dox +pub type LastPrivateMap = NodeMap; + +#[deriving(Copy, Show)] +pub enum LastPrivate { + LastMod(PrivateDep), + // `use` directives (imports) can refer to two separate definitions in the + // type and value namespaces. We record here the last private node for each + // and whether the import is in fact used for each. + // If the Option fields are None, it means there is no definition + // in that namespace. + LastImport{value_priv: Option, + value_used: ImportUse, + type_priv: Option, + type_used: ImportUse}, +} + +#[deriving(Copy, Show)] +pub enum PrivateDep { + AllPublic, + DependsOn(ast::DefId), +} + +// How an import is used. +#[deriving(Copy, PartialEq, Show)] +pub enum ImportUse { + Unused, // The import is not used. + Used, // The import is used. +} + +impl LastPrivate { + pub fn or(self, other: LastPrivate) -> LastPrivate { + match (self, other) { + (me, LastMod(AllPublic)) => me, + (_, other) => other, + } + } +} + /// Result of a checking operation - None => no errors were found. Some => an /// error and contains the span and message for reporting that error and /// optionally the same for a note about the error. @@ -136,7 +182,7 @@ impl<'v> Visitor<'v> for ParentVisitor { struct EmbargoVisitor<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, - exp_map2: &'a resolve::ExportMap2, + export_map: &'a def::ExportMap, // This flag is an indicator of whether the previous item in the // hierarchical chain was exported or not. This is the indicator of whether @@ -342,8 +388,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // This code is here instead of in visit_item so that the // crate module gets processed as well. if self.prev_exported { - assert!(self.exp_map2.contains_key(&id), "wut {}", id); - for export in self.exp_map2[id].iter() { + assert!(self.export_map.contains_key(&id), "wut {}", id); + for export in self.export_map[id].iter() { if is_local(export.def_id) { self.reexports.insert(export.def_id.node); } @@ -362,8 +408,8 @@ struct PrivacyVisitor<'a, 'tcx: 'a> { curitem: ast::NodeId, in_foreign: bool, parents: NodeMap, - external_exports: resolve::ExternalExports, - last_private_map: resolve::LastPrivateMap, + external_exports: ExternalExports, + last_private_map: LastPrivateMap, } enum PrivacyResult { @@ -719,25 +765,25 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { }; match self.last_private_map[path_id] { - resolve::LastMod(resolve::AllPublic) => {}, - resolve::LastMod(resolve::DependsOn(def)) => { + LastMod(AllPublic) => {}, + LastMod(DependsOn(def)) => { self.report_error(ck_public(def)); }, - resolve::LastImport{value_priv, - value_used: check_value, - type_priv, - type_used: check_type} => { + LastImport { value_priv, + value_used: check_value, + type_priv, + type_used: check_type } => { // This dance with found_error is because we don't want to report // a privacy error twice for the same directive. let found_error = match (type_priv, check_type) { - (Some(resolve::DependsOn(def)), resolve::Used) => { + (Some(DependsOn(def)), Used) => { !self.report_error(ck_public(def)) }, _ => false, }; if !found_error { match (value_priv, check_value) { - (Some(resolve::DependsOn(def)), resolve::Used) => { + (Some(DependsOn(def)), Used) => { self.report_error(ck_public(def)); }, _ => {}, @@ -749,24 +795,24 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // be illegal. We only report one error, even if it is // illegal to import from both namespaces. match (value_priv, check_value, type_priv, check_type) { - (Some(p), resolve::Unused, None, _) | - (None, _, Some(p), resolve::Unused) => { + (Some(p), Unused, None, _) | + (None, _, Some(p), Unused) => { let p = match p { - resolve::AllPublic => None, - resolve::DependsOn(def) => ck_public(def), + AllPublic => None, + DependsOn(def) => ck_public(def), }; if p.is_some() { self.report_error(p); } }, - (Some(v), resolve::Unused, Some(t), resolve::Unused) => { + (Some(v), Unused, Some(t), Unused) => { let v = match v { - resolve::AllPublic => None, - resolve::DependsOn(def) => ck_public(def), + AllPublic => None, + DependsOn(def) => ck_public(def), }; let t = match t { - resolve::AllPublic => None, - resolve::DependsOn(def) => ck_public(def), + AllPublic => None, + DependsOn(def) => ck_public(def), }; if let (Some(_), Some(t)) = (v, t) { self.report_error(Some(t)); @@ -1520,9 +1566,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { } pub fn check_crate(tcx: &ty::ctxt, - exp_map2: &resolve::ExportMap2, - external_exports: resolve::ExternalExports, - last_private_map: resolve::LastPrivateMap) + export_map: &def::ExportMap, + external_exports: ExternalExports, + last_private_map: LastPrivateMap) -> (ExportedItems, PublicItems) { let krate = tcx.map.krate(); @@ -1561,7 +1607,7 @@ pub fn check_crate(tcx: &ty::ctxt, exported_items: NodeSet::new(), public_items: NodeSet::new(), reexports: NodeSet::new(), - exp_map2: exp_map2, + export_map: export_map, prev_exported: true, prev_public: true, }; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2202137d149..c8f53df6727 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -19,9 +19,8 @@ pub use self::DefRegion::*; use self::ScopeChain::*; use session::Session; -use middle::def; +use middle::def::{mod, DefMap}; use middle::region; -use middle::resolve::DefMap; use middle::subst; use middle::ty; use std::fmt; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index acf1fced72c..d5c97bd6aa6 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -46,13 +46,12 @@ use lint; use metadata::csearch; use middle; use middle::const_eval; -use middle::def; +use middle::def::{mod, DefMap, ExportMap}; use middle::dependency_format; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; use middle::lang_items::{FnOnceTraitLangItem, TyDescStructLangItem}; use middle::mem_categorization as mc; use middle::region; -use middle::resolve; use middle::resolve_lifetime; use middle::infer; use middle::stability; @@ -99,7 +98,7 @@ pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0; /// The complete set of all analyses described in this module. This is /// produced by the driver and fed to trans and later passes. pub struct CrateAnalysis<'tcx> { - pub exp_map2: middle::resolve::ExportMap2, + pub export_map: ExportMap, pub exported_items: middle::privacy::ExportedItems, pub public_items: middle::privacy::PublicItems, pub ty_cx: ty::ctxt<'tcx>, @@ -615,7 +614,7 @@ pub struct ctxt<'tcx> { // queried from a HashSet. interner: RefCell, Ty<'tcx>>>, pub sess: Session, - pub def_map: resolve::DefMap, + pub def_map: DefMap, pub named_region_map: resolve_lifetime::NamedRegionMap, @@ -1967,7 +1966,7 @@ impl UnboxedClosureKind { pub fn mk_ctxt<'tcx>(s: Session, type_arena: &'tcx TypedArena>, - dm: resolve::DefMap, + dm: DefMap, named_region_map: resolve_lifetime::NamedRegionMap, map: ast_map::Map<'tcx>, freevars: RefCell, @@ -6263,6 +6262,9 @@ pub type FreevarMap = NodeMap>; pub type CaptureModeMap = NodeMap; +// Trait method resolution +pub type TraitMap = NodeMap>; + pub fn with_freevars(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where F: FnOnce(&[Freevar]) -> T, { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9ed4f46c168..60b890b0370 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -20,6 +20,7 @@ use rustc::plugin::registry::Registry; use rustc::plugin; use rustc::util::common::time; use rustc_borrowck as borrowck; +use rustc_resolve as resolve; use rustc_trans::back::link; use rustc_trans::back::write; use rustc_trans::save; @@ -341,17 +342,17 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, let lang_items = time(time_passes, "language item collection", (), |_| middle::lang_items::collect_language_items(krate, &sess)); - let middle::resolve::CrateMap { + let resolve::CrateMap { def_map, freevars, capture_mode_map, - exp_map2, + export_map, trait_map, external_exports, last_private_map } = - time(time_passes, "resolution", (), |_| - middle::resolve::resolve_crate(&sess, &lang_items, krate)); + time(time_passes, "resolution", (), + |_| resolve::resolve_crate(&sess, &lang_items, krate)); // Discard MTWT tables that aren't required past resolution. syntax::ext::mtwt::clear_tables(); @@ -406,7 +407,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, let maps = (external_exports, last_private_map); let (exported_items, public_items) = time(time_passes, "privacy checking", maps, |(a, b)| - middle::privacy::check_crate(&ty_cx, &exp_map2, a, b)); + middle::privacy::check_crate(&ty_cx, &export_map, a, b)); time(time_passes, "intrinsic checking", (), |_| middle::intrinsicck::check_crate(&ty_cx)); @@ -447,7 +448,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, lint::check_crate(&ty_cx, &exported_items)); ty::CrateAnalysis { - exp_map2: exp_map2, + export_map: export_map, ty_cx: ty_cx, exported_items: exported_items, public_items: public_items, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 120654678e9..34d9fd6bcad 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,6 +35,7 @@ extern crate libc; extern crate rustc; extern crate rustc_back; extern crate rustc_borrowck; +extern crate rustc_resolve; extern crate rustc_trans; extern crate rustc_typeck; #[phase(plugin, link)] extern crate log; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index b2c661cc58a..090d6a7a3ca 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -13,9 +13,9 @@ use diagnostic; use diagnostic::Emitter; use driver; +use rustc_resolve as resolve; use rustc_typeck::middle::lang_items; use rustc_typeck::middle::region::{mod, CodeExtent}; -use rustc_typeck::middle::resolve; use rustc_typeck::middle::resolve_lifetime; use rustc_typeck::middle::stability; use rustc_typeck::middle::subst; diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs new file mode 100644 index 00000000000..39cdf6fc8f3 --- /dev/null +++ b/src/librustc_resolve/check_unused.rs @@ -0,0 +1,161 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// +// Unused import checking +// +// Although this is mostly a lint pass, it lives in here because it depends on +// resolve data structures and because it finalises the privacy information for +// `use` directives. +// + +use Resolver; +use Namespace::{TypeNS, ValueNS}; + +use rustc::lint; +use rustc::middle::privacy::{DependsOn, LastImport, Used, Unused}; +use syntax::ast; +use syntax::ast::{ViewItem, ViewItemExternCrate, ViewItemUse}; +use syntax::ast::{ViewPathGlob, ViewPathList, ViewPathSimple}; +use syntax::codemap::{Span, DUMMY_SP}; +use syntax::visit::{mod, Visitor}; + +struct UnusedImportCheckVisitor<'a, 'b:'a> { + resolver: &'a mut Resolver<'b> +} + +// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver. +impl<'a, 'b> Deref> for UnusedImportCheckVisitor<'a, 'b> { + fn deref<'c>(&'c self) -> &'c Resolver<'b> { + &*self.resolver + } +} + +impl<'a, 'b> DerefMut> for UnusedImportCheckVisitor<'a, 'b> { + fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> { + &mut *self.resolver + } +} + +impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { + // We have information about whether `use` (import) directives are actually used now. + // If an import is not used at all, we signal a lint error. If an import is only used + // for a single namespace, we remove the other namespace from the recorded privacy + // information. That means in privacy.rs, we will only check imports and namespaces + // which are used. In particular, this means that if an import could name either a + // public or private item, we will check the correct thing, dependent on how the import + // is used. + fn finalize_import(&mut self, id: ast::NodeId, span: Span) { + debug!("finalizing import uses for {}", + self.session.codemap().span_to_snippet(span)); + + if !self.used_imports.contains(&(id, TypeNS)) && + !self.used_imports.contains(&(id, ValueNS)) { + self.session.add_lint(lint::builtin::UNUSED_IMPORTS, + id, + span, + "unused import".to_string()); + } + + let (v_priv, t_priv) = match self.last_private.get(&id) { + Some(&LastImport { + value_priv: v, + value_used: _, + type_priv: t, + type_used: _ + }) => (v, t), + Some(_) => { + panic!("we should only have LastImport for `use` directives") + } + _ => return, + }; + + let mut v_used = if self.used_imports.contains(&(id, ValueNS)) { + Used + } else { + Unused + }; + let t_used = if self.used_imports.contains(&(id, TypeNS)) { + Used + } else { + Unused + }; + + match (v_priv, t_priv) { + // Since some items may be both in the value _and_ type namespaces (e.g., structs) + // we might have two LastPrivates pointing at the same thing. There is no point + // checking both, so lets not check the value one. + (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused, + _ => {}, + } + + self.last_private.insert(id, LastImport{value_priv: v_priv, + value_used: v_used, + type_priv: t_priv, + type_used: t_used}); + } +} + +impl<'a, 'b, 'v> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b> { + fn visit_view_item(&mut self, vi: &ViewItem) { + // Ignore is_public import statements because there's no way to be sure + // whether they're used or not. Also ignore imports with a dummy span + // because this means that they were generated in some fashion by the + // compiler and we don't need to consider them. + if vi.vis == ast::Public || vi.span == DUMMY_SP { + visit::walk_view_item(self, vi); + return; + } + + match vi.node { + ViewItemExternCrate(_, _, id) => { + if let Some(crate_num) = self.session.cstore.find_extern_mod_stmt_cnum(id) { + if !self.used_crates.contains(&crate_num) { + self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES, + id, + vi.span, + "unused extern crate".to_string()); + } + } + }, + ViewItemUse(ref p) => { + match p.node { + ViewPathSimple(_, _, id) => { + self.finalize_import(id, p.span) + } + + ViewPathList(_, ref list, _) => { + for i in list.iter() { + self.finalize_import(i.node.id(), i.span); + } + } + ViewPathGlob(_, id) => { + if !self.used_imports.contains(&(id, TypeNS)) && + !self.used_imports.contains(&(id, ValueNS)) { + self.session + .add_lint(lint::builtin::UNUSED_IMPORTS, + id, + p.span, + "unused import".to_string()); + } + } + } + } + } + + visit::walk_view_item(self, vi); + } +} + +pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { + let mut visitor = UnusedImportCheckVisitor { resolver: resolver }; + visit::walk_crate(&mut visitor, krate); +} diff --git a/src/librustc/middle/resolve.rs b/src/librustc_resolve/lib.rs similarity index 94% rename from src/librustc/middle/resolve.rs rename to src/librustc_resolve/lib.rs index e1e376c537c..e1708be30d9 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc_resolve/lib.rs @@ -8,12 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_camel_case_types)] +#![crate_name = "rustc_resolve"] +#![experimental] +#![crate_type = "dylib"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/nightly/")] + +#![feature(globs, phase, slicing_syntax)] +#![feature(rustc_diagnostic_macros)] + +#[phase(plugin, link)] extern crate log; +#[phase(plugin, link)] extern crate syntax; + +extern crate rustc; -pub use self::PrivateDep::*; -pub use self::ImportUse::*; -pub use self::TraitItemKind::*; -pub use self::LastPrivate::*; use self::PatternBindingMode::*; use self::Namespace::*; use self::NamespaceError::*; @@ -36,26 +46,26 @@ use self::ModuleKind::*; use self::TraitReferenceType::*; use self::FallbackChecks::*; -use session::Session; -use lint; -use metadata::csearch; -use metadata::decoder::{DefLike, DlDef, DlField, DlImpl}; -use middle::def::*; -use middle::lang_items::LanguageItems; -use middle::pat_util::pat_bindings; -use middle::subst::{ParamSpace, FnSpace, TypeSpace}; -use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory}; -use middle::ty::{CaptureModeMap, Freevar, FreevarMap}; -use util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap}; +use rustc::session::Session; +use rustc::lint; +use rustc::metadata::csearch; +use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl}; +use rustc::middle::def::*; +use rustc::middle::lang_items::LanguageItems; +use rustc::middle::pat_util::pat_bindings; +use rustc::middle::privacy::*; +use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace}; +use rustc::middle::ty::{CaptureModeMap, Freevar, FreevarMap, TraitMap}; +use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap}; use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum}; use syntax::ast::{DeclItem, DefId, Expr, ExprAgain, ExprBreak, ExprField}; use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall}; use syntax::ast::{ExprPath, ExprStruct, FnDecl}; use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic, Generics}; -use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod}; -use syntax::ast::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct}; -use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, ItemConst}; +use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemFn}; +use syntax::ast::{ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic}; +use syntax::ast::{ItemStruct, ItemTrait, ItemTy, Local}; use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId}; use syntax::ast::{Pat, PatEnum, PatIdent, PatLit}; use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod}; @@ -86,72 +96,17 @@ use std::mem::replace; use std::rc::{Rc, Weak}; use std::uint; -// Definition mapping -pub type DefMap = RefCell>; +mod check_unused; +mod record_exports; #[deriving(Copy)] -struct binding_info { +struct BindingInfo { span: Span, binding_mode: BindingMode, } // Map from the name in a pattern to its binding mode. -type BindingMap = HashMap; - -// Trait method resolution -pub type TraitMap = NodeMap >; - -// This is the replacement export map. It maps a module to all of the exports -// within. -pub type ExportMap2 = NodeMap>; - -pub struct Export2 { - pub name: String, // The name of the target. - pub def_id: DefId, // The definition of the target. -} - -// This set contains all exported definitions from external crates. The set does -// not contain any entries from local crates. -pub type ExternalExports = DefIdSet; - -// FIXME: dox -pub type LastPrivateMap = NodeMap; - -#[deriving(Copy, Show)] -pub enum LastPrivate { - LastMod(PrivateDep), - // `use` directives (imports) can refer to two separate definitions in the - // type and value namespaces. We record here the last private node for each - // and whether the import is in fact used for each. - // If the Option fields are None, it means there is no definition - // in that namespace. - LastImport{value_priv: Option, - value_used: ImportUse, - type_priv: Option, - type_used: ImportUse}, -} - -#[deriving(Copy, Show)] -pub enum PrivateDep { - AllPublic, - DependsOn(DefId), -} - -// How an import is used. -#[deriving(Copy, PartialEq, Show)] -pub enum ImportUse { - Unused, // The import is not used. - Used, // The import is used. -} - -impl LastPrivate { - fn or(self, other: LastPrivate) -> LastPrivate { - match (self, other) { - (me, LastMod(AllPublic)) => me, - (_, other) => other, - } - } -} +type BindingMap = HashMap; #[deriving(Copy, PartialEq)] enum PatternBindingMode { @@ -340,25 +295,6 @@ enum ModulePrefixResult { PrefixFound(Rc, uint) } -#[deriving(Clone, Copy, Eq, PartialEq)] -pub enum TraitItemKind { - NonstaticMethodTraitItemKind, - StaticMethodTraitItemKind, - TypeTraitItemKind, -} - -impl TraitItemKind { - pub fn from_explicit_self_category(explicit_self_category: - ExplicitSelfCategory) - -> TraitItemKind { - if explicit_self_category == StaticExplicitSelfCategory { - StaticMethodTraitItemKind - } else { - NonstaticMethodTraitItemKind - } - } -} - #[deriving(Copy, PartialEq)] enum NameSearchType { /// We're doing a name search in order to resolve a `use` directive. @@ -948,7 +884,7 @@ struct Resolver<'a> { freevars: RefCell, freevars_seen: RefCell>, capture_mode_map: CaptureModeMap, - export_map2: ExportMap2, + export_map: ExportMap, trait_map: TraitMap, external_exports: ExternalExports, last_private: LastPrivateMap, @@ -1002,17 +938,6 @@ impl<'a, 'b, 'v> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b> { } -struct UnusedImportCheckVisitor<'a, 'b:'a> { - resolver: &'a mut Resolver<'b> -} - -impl<'a, 'b, 'v> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b> { - fn visit_view_item(&mut self, vi: &ViewItem) { - self.resolver.check_for_item_unused_imports(vi); - visit::walk_view_item(self, vi); - } -} - #[deriving(PartialEq)] enum FallbackChecks { Everything, @@ -1063,7 +988,7 @@ impl<'a> Resolver<'a> { freevars: RefCell::new(NodeMap::new()), freevars_seen: RefCell::new(NodeMap::new()), capture_mode_map: NodeMap::new(), - export_map2: NodeMap::new(), + export_map: NodeMap::new(), trait_map: NodeMap::new(), used_imports: HashSet::new(), used_crates: HashSet::new(), @@ -1073,22 +998,6 @@ impl<'a> Resolver<'a> { emit_errors: true, } } - /// The main name resolution procedure. - fn resolve(&mut self, krate: &ast::Crate) { - self.build_reduced_graph(krate); - self.session.abort_if_errors(); - - self.resolve_imports(); - self.session.abort_if_errors(); - - self.record_exports(); - self.session.abort_if_errors(); - - self.resolve_crate(krate); - self.session.abort_if_errors(); - - self.check_for_unused_imports(krate); - } // // Reduced graph building @@ -3800,125 +3709,6 @@ impl<'a> Resolver<'a> { } } - // Export recording - // - // This pass simply determines what all "export" keywords refer to and - // writes the results into the export map. - // - // FIXME #4953 This pass will be removed once exports change to per-item. - // Then this operation can simply be performed as part of item (or import) - // processing. - - fn record_exports(&mut self) { - let root_module = self.graph_root.get_module(); - self.record_exports_for_module_subtree(root_module); - } - - fn record_exports_for_module_subtree(&mut self, - module_: Rc) { - // If this isn't a local krate, then bail out. We don't need to record - // exports for nonlocal crates. - - match module_.def_id.get() { - Some(def_id) if def_id.krate == LOCAL_CRATE => { - // OK. Continue. - debug!("(recording exports for module subtree) recording \ - exports for local module `{}`", - self.module_to_string(&*module_)); - } - None => { - // Record exports for the root module. - debug!("(recording exports for module subtree) recording \ - exports for root module `{}`", - self.module_to_string(&*module_)); - } - Some(_) => { - // Bail out. - debug!("(recording exports for module subtree) not recording \ - exports for `{}`", - self.module_to_string(&*module_)); - return; - } - } - - self.record_exports_for_module(&*module_); - self.populate_module_if_necessary(&module_); - - for (_, child_name_bindings) in module_.children.borrow().iter() { - match child_name_bindings.get_module_if_available() { - None => { - // Nothing to do. - } - Some(child_module) => { - self.record_exports_for_module_subtree(child_module); - } - } - } - - for (_, child_module) in module_.anonymous_children.borrow().iter() { - self.record_exports_for_module_subtree(child_module.clone()); - } - } - - fn record_exports_for_module(&mut self, module_: &Module) { - let mut exports2 = Vec::new(); - - self.add_exports_for_module(&mut exports2, module_); - match module_.def_id.get() { - Some(def_id) => { - self.export_map2.insert(def_id.node, exports2); - debug!("(computing exports) writing exports for {} (some)", - def_id.node); - } - None => {} - } - } - - fn add_exports_of_namebindings(&mut self, - exports2: &mut Vec , - name: Name, - namebindings: &NameBindings, - ns: Namespace) { - match namebindings.def_for_namespace(ns) { - Some(d) => { - let name = token::get_name(name); - debug!("(computing exports) YES: export '{}' => {}", - name, d.def_id()); - exports2.push(Export2 { - name: name.get().to_string(), - def_id: d.def_id() - }); - } - d_opt => { - debug!("(computing exports) NO: {}", d_opt); - } - } - } - - fn add_exports_for_module(&mut self, - exports2: &mut Vec , - module_: &Module) { - for (name, importresolution) in module_.import_resolutions.borrow().iter() { - if !importresolution.is_public { - continue - } - let xs = [TypeNS, ValueNS]; - for &ns in xs.iter() { - match importresolution.target_for_namespace(ns) { - Some(target) => { - debug!("(computing exports) maybe export '{}'", - token::get_name(*name)); - self.add_exports_of_namebindings(exports2, - *name, - &*target.bindings, - ns) - } - _ => () - } - } - } - } - // AST resolution // // We maintain a list of value ribs and type ribs. @@ -4809,9 +4599,10 @@ impl<'a> Resolver<'a> { let mut result = HashMap::new(); pat_bindings(&self.def_map, pat, |binding_mode, _id, sp, path1| { let name = mtwt::resolve(path1.node); - result.insert(name, - binding_info {span: sp, - binding_mode: binding_mode}); + result.insert(name, BindingInfo { + span: sp, + binding_mode: binding_mode + }); }); return result; } @@ -6135,119 +5926,6 @@ impl<'a> Resolver<'a> { } } - // - // Unused import checking - // - // Although this is mostly a lint pass, it lives in here because it depends on - // resolve data structures and because it finalises the privacy information for - // `use` directives. - // - - fn check_for_unused_imports(&mut self, krate: &ast::Crate) { - let mut visitor = UnusedImportCheckVisitor{ resolver: self }; - visit::walk_crate(&mut visitor, krate); - } - - fn check_for_item_unused_imports(&mut self, vi: &ViewItem) { - // Ignore is_public import statements because there's no way to be sure - // whether they're used or not. Also ignore imports with a dummy span - // because this means that they were generated in some fashion by the - // compiler and we don't need to consider them. - if vi.vis == Public { return } - if vi.span == DUMMY_SP { return } - - match vi.node { - ViewItemExternCrate(_, _, id) => { - if let Some(crate_num) = self.session.cstore.find_extern_mod_stmt_cnum(id) { - if !self.used_crates.contains(&crate_num) { - self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES, - id, - vi.span, - "unused extern crate".to_string()); - } - } - }, - ViewItemUse(ref p) => { - match p.node { - ViewPathSimple(_, _, id) => self.finalize_import(id, p.span), - - ViewPathList(_, ref list, _) => { - for i in list.iter() { - self.finalize_import(i.node.id(), i.span); - } - }, - ViewPathGlob(_, id) => { - if !self.used_imports.contains(&(id, TypeNS)) && - !self.used_imports.contains(&(id, ValueNS)) { - self.session - .add_lint(lint::builtin::UNUSED_IMPORTS, - id, - p.span, - "unused import".to_string()); - } - }, - } - } - } - } - - // We have information about whether `use` (import) directives are actually used now. - // If an import is not used at all, we signal a lint error. If an import is only used - // for a single namespace, we remove the other namespace from the recorded privacy - // information. That means in privacy.rs, we will only check imports and namespaces - // which are used. In particular, this means that if an import could name either a - // public or private item, we will check the correct thing, dependent on how the import - // is used. - fn finalize_import(&mut self, id: NodeId, span: Span) { - debug!("finalizing import uses for {}", - self.session.codemap().span_to_snippet(span)); - - if !self.used_imports.contains(&(id, TypeNS)) && - !self.used_imports.contains(&(id, ValueNS)) { - self.session.add_lint(lint::builtin::UNUSED_IMPORTS, - id, - span, - "unused import".to_string()); - } - - let (v_priv, t_priv) = match self.last_private.get(&id) { - Some(&LastImport { - value_priv: v, - value_used: _, - type_priv: t, - type_used: _ - }) => (v, t), - Some(_) => { - panic!("we should only have LastImport for `use` directives") - } - _ => return, - }; - - let mut v_used = if self.used_imports.contains(&(id, ValueNS)) { - Used - } else { - Unused - }; - let t_used = if self.used_imports.contains(&(id, TypeNS)) { - Used - } else { - Unused - }; - - match (v_priv, t_priv) { - // Since some items may be both in the value _and_ type namespaces (e.g., structs) - // we might have two LastPrivates pointing at the same thing. There is no point - // checking both, so lets not check the value one. - (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused, - _ => {}, - } - - self.last_private.insert(id, LastImport{value_priv: v_priv, - value_used: v_used, - type_priv: t_priv, - type_used: t_used}); - } - // // Diagnostics // @@ -6323,7 +6001,7 @@ pub struct CrateMap { pub def_map: DefMap, pub freevars: RefCell, pub capture_mode_map: RefCell, - pub exp_map2: ExportMap2, + pub export_map: ExportMap, pub trait_map: TraitMap, pub external_exports: ExternalExports, pub last_private_map: LastPrivateMap, @@ -6335,12 +6013,26 @@ pub fn resolve_crate(session: &Session, krate: &Crate) -> CrateMap { let mut resolver = Resolver::new(session, krate.span); - resolver.resolve(krate); + + resolver.build_reduced_graph(krate); + session.abort_if_errors(); + + resolver.resolve_imports(); + session.abort_if_errors(); + + record_exports::record(&mut resolver); + session.abort_if_errors(); + + resolver.resolve_crate(krate); + session.abort_if_errors(); + + check_unused::check_crate(&mut resolver, krate); + CrateMap { def_map: resolver.def_map, freevars: resolver.freevars, capture_mode_map: RefCell::new(resolver.capture_mode_map), - exp_map2: resolver.export_map2, + export_map: resolver.export_map, trait_map: resolver.trait_map, external_exports: resolver.external_exports, last_private_map: resolver.last_private, diff --git a/src/librustc_resolve/record_exports.rs b/src/librustc_resolve/record_exports.rs new file mode 100644 index 00000000000..41882a94b34 --- /dev/null +++ b/src/librustc_resolve/record_exports.rs @@ -0,0 +1,157 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// Export recording +// +// This pass simply determines what all "export" keywords refer to and +// writes the results into the export map. +// +// FIXME #4953 This pass will be removed once exports change to per-item. +// Then this operation can simply be performed as part of item (or import) +// processing. + +use {Module, NameBindings, Resolver}; +use Namespace::{mod, TypeNS, ValueNS}; + +use rustc::middle::def::Export; +use syntax::ast; +use syntax::parse::token; + +use std::rc::Rc; + +struct ExportRecorder<'a, 'b:'a> { + resolver: &'a mut Resolver<'b> +} + +// Deref and DerefMut impls allow treating ExportRecorder as Resolver. +impl<'a, 'b> Deref> for ExportRecorder<'a, 'b> { + fn deref<'c>(&'c self) -> &'c Resolver<'b> { + &*self.resolver + } +} + +impl<'a, 'b> DerefMut> for ExportRecorder<'a, 'b> { + fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> { + &mut *self.resolver + } +} + +impl<'a, 'b> ExportRecorder<'a, 'b> { + fn record_exports_for_module_subtree(&mut self, + module_: Rc) { + // If this isn't a local krate, then bail out. We don't need to record + // exports for nonlocal crates. + + match module_.def_id.get() { + Some(def_id) if def_id.krate == ast::LOCAL_CRATE => { + // OK. Continue. + debug!("(recording exports for module subtree) recording \ + exports for local module `{}`", + self.module_to_string(&*module_)); + } + None => { + // Record exports for the root module. + debug!("(recording exports for module subtree) recording \ + exports for root module `{}`", + self.module_to_string(&*module_)); + } + Some(_) => { + // Bail out. + debug!("(recording exports for module subtree) not recording \ + exports for `{}`", + self.module_to_string(&*module_)); + return; + } + } + + self.record_exports_for_module(&*module_); + self.populate_module_if_necessary(&module_); + + for (_, child_name_bindings) in module_.children.borrow().iter() { + match child_name_bindings.get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.record_exports_for_module_subtree(child_module); + } + } + } + + for (_, child_module) in module_.anonymous_children.borrow().iter() { + self.record_exports_for_module_subtree(child_module.clone()); + } + } + + fn record_exports_for_module(&mut self, module_: &Module) { + let mut exports = Vec::new(); + + self.add_exports_for_module(&mut exports, module_); + match module_.def_id.get() { + Some(def_id) => { + self.export_map.insert(def_id.node, exports); + debug!("(computing exports) writing exports for {} (some)", + def_id.node); + } + None => {} + } + } + + fn add_exports_of_namebindings(&mut self, + exports: &mut Vec, + name: ast::Name, + namebindings: &NameBindings, + ns: Namespace) { + match namebindings.def_for_namespace(ns) { + Some(d) => { + debug!("(computing exports) YES: export '{}' => {}", + name, d.def_id()); + exports.push(Export { + name: name, + def_id: d.def_id() + }); + } + d_opt => { + debug!("(computing exports) NO: {}", d_opt); + } + } + } + + fn add_exports_for_module(&mut self, + exports: &mut Vec, + module_: &Module) { + for (name, importresolution) in module_.import_resolutions.borrow().iter() { + if !importresolution.is_public { + continue + } + let xs = [TypeNS, ValueNS]; + for &ns in xs.iter() { + match importresolution.target_for_namespace(ns) { + Some(target) => { + debug!("(computing exports) maybe export '{}'", + token::get_name(*name)); + self.add_exports_of_namebindings(exports, + *name, + &*target.bindings, + ns) + } + _ => () + } + } + } + } +} + +pub fn record(resolver: &mut Resolver) { + let mut recorder = ExportRecorder { resolver: resolver }; + let root_module = recorder.graph_root.get_module(); + recorder.record_exports_for_module_subtree(root_module); +} diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 1401f1ad1f5..2bcd723fc83 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -193,12 +193,11 @@ use llvm::{ValueRef, BasicBlockRef}; use middle::check_match::StaticInliner; use middle::check_match; use middle::const_eval; -use middle::def; +use middle::def::{mod, DefMap}; use middle::expr_use_visitor as euv; use middle::lang_items::StrEqFnLangItem; use middle::mem_categorization as mc; use middle::pat_util::*; -use middle::resolve::DefMap; use trans::adt; use trans::base::*; use trans::build::{AddCase, And, BitCast, Br, CondBr, GEPi, InBoundsGEP, Load}; diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 25fbaa66776..b0ef2257a0a 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2938,7 +2938,7 @@ pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'tcx>, encoder::EncodeParams { diag: cx.sess().diagnostic(), tcx: cx.tcx(), - reexports2: cx.exp_map2(), + reexports: cx.export_map(), item_symbols: cx.item_symbols(), link_meta: cx.link_meta(), cstore: &cx.sess().cstore, @@ -3071,7 +3071,7 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet) { pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>) -> (ty::ctxt<'tcx>, CrateTranslation) { - let ty::CrateAnalysis { ty_cx: tcx, exp_map2, reachable, name, .. } = analysis; + let ty::CrateAnalysis { ty_cx: tcx, export_map, reachable, name, .. } = analysis; let krate = tcx.map.krate(); // Before we touch LLVM, make sure that multithreading is enabled. @@ -3098,7 +3098,7 @@ pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>) let shared_ccx = SharedCrateContext::new(link_meta.crate_name.as_slice(), codegen_units, tcx, - exp_map2, + export_map, Sha256::new(), link_meta.clone(), reachable); diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index af003b01157..7b962a93990 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -13,7 +13,7 @@ use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef}; use llvm::{TargetData}; use llvm::mk_target_data; use metadata::common::LinkMeta; -use middle::resolve; +use middle::def::ExportMap; use middle::traits; use trans::adt; use trans::base; @@ -61,7 +61,7 @@ pub struct SharedCrateContext<'tcx> { metadata_llmod: ModuleRef, metadata_llcx: ContextRef, - exp_map2: resolve::ExportMap2, + export_map: ExportMap, reachable: NodeSet, item_symbols: RefCell>, link_meta: LinkMeta, @@ -238,7 +238,7 @@ impl<'tcx> SharedCrateContext<'tcx> { pub fn new(crate_name: &str, local_count: uint, tcx: ty::ctxt<'tcx>, - emap2: resolve::ExportMap2, + export_map: ExportMap, symbol_hasher: Sha256, link_meta: LinkMeta, reachable: NodeSet) @@ -251,7 +251,7 @@ impl<'tcx> SharedCrateContext<'tcx> { local_ccxs: Vec::with_capacity(local_count), metadata_llmod: metadata_llmod, metadata_llcx: metadata_llcx, - exp_map2: emap2, + export_map: export_map, reachable: reachable, item_symbols: RefCell::new(NodeMap::new()), link_meta: link_meta, @@ -329,8 +329,8 @@ impl<'tcx> SharedCrateContext<'tcx> { self.metadata_llcx } - pub fn exp_map2<'a>(&'a self) -> &'a resolve::ExportMap2 { - &self.exp_map2 + pub fn export_map<'a>(&'a self) -> &'a ExportMap { + &self.export_map } pub fn reachable<'a>(&'a self) -> &'a NodeSet { @@ -553,8 +553,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.item_vals } - pub fn exp_map2<'a>(&'a self) -> &'a resolve::ExportMap2 { - &self.shared.exp_map2 + pub fn export_map<'a>(&'a self) -> &'a ExportMap { + &self.shared.export_map } pub fn reachable<'a>(&'a self) -> &'a NodeSet { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 5fc2466674e..ec0313d4d8f 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -90,7 +90,6 @@ pub use rustc::session; pub use rustc::util; use middle::def; -use middle::resolve; use middle::infer; use middle::subst; use middle::subst::VecPerParamSpace; @@ -121,7 +120,7 @@ struct TypeAndSubsts<'tcx> { struct CrateCtxt<'a, 'tcx: 'a> { // A mapping from method call sites to traits that have that method. - trait_map: resolve::TraitMap, + trait_map: ty::TraitMap, tcx: &'a ty::ctxt<'tcx> } @@ -316,7 +315,7 @@ fn check_for_entry_fn(ccx: &CrateCtxt) { } } -pub fn check_crate(tcx: &ty::ctxt, trait_map: resolve::TraitMap) { +pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { let time_passes = tcx.sess.time_passes(); let ccx = CrateCtxt { trait_map: trait_map, diff --git a/src/test/run-pass/issue-14254.rs b/src/test/run-pass/issue-14254.rs index 160828d42fc..ad4ed03e6e2 100644 --- a/src/test/run-pass/issue-14254.rs +++ b/src/test/run-pass/issue-14254.rs @@ -24,7 +24,7 @@ impl BarTy { fn b(&self) {} } -// If these fail, it's necessary to update middle::resolve and the cfail tests. +// If these fail, it's necessary to update rustc_resolve and the cfail tests. impl Foo for *const BarTy { fn bar(&self) { self.baz(); @@ -33,7 +33,7 @@ impl Foo for *const BarTy { } } -// If these fail, it's necessary to update middle::resolve and the cfail tests. +// If these fail, it's necessary to update rustc_resolve and the cfail tests. impl<'a> Foo for &'a BarTy { fn bar(&self) { self.baz(); @@ -45,7 +45,7 @@ impl<'a> Foo for &'a BarTy { } } -// If these fail, it's necessary to update middle::resolve and the cfail tests. +// If these fail, it's necessary to update rustc_resolve and the cfail tests. impl<'a> Foo for &'a mut BarTy { fn bar(&self) { self.baz(); @@ -57,7 +57,7 @@ impl<'a> Foo for &'a mut BarTy { } } -// If these fail, it's necessary to update middle::resolve and the cfail tests. +// If these fail, it's necessary to update rustc_resolve and the cfail tests. impl Foo for Box { fn bar(&self) { self.baz(); @@ -65,7 +65,7 @@ impl Foo for Box { } } -// If these fail, it's necessary to update middle::resolve and the cfail tests. +// If these fail, it's necessary to update rustc_resolve and the cfail tests. impl Foo for *const int { fn bar(&self) { self.baz(); @@ -73,7 +73,7 @@ impl Foo for *const int { } } -// If these fail, it's necessary to update middle::resolve and the cfail tests. +// If these fail, it's necessary to update rustc_resolve and the cfail tests. impl<'a> Foo for &'a int { fn bar(&self) { self.baz(); @@ -81,7 +81,7 @@ impl<'a> Foo for &'a int { } } -// If these fail, it's necessary to update middle::resolve and the cfail tests. +// If these fail, it's necessary to update rustc_resolve and the cfail tests. impl<'a> Foo for &'a mut int { fn bar(&self) { self.baz(); @@ -89,7 +89,7 @@ impl<'a> Foo for &'a mut int { } } -// If these fail, it's necessary to update middle::resolve and the cfail tests. +// If these fail, it's necessary to update rustc_resolve and the cfail tests. impl Foo for Box { fn bar(&self) { self.baz();