diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4f3c12567095e..33d53892c55b2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -16,7 +16,7 @@ use self::wrapping::OverflowingOps; use char::CharExt; -use cmp::{Eq, PartialOrd}; +use cmp::PartialOrd; use convert::From; use fmt; use intrinsics; diff --git a/src/libcore/option.rs b/src/libcore/option.rs index aca36d856266b..60b3ed0f6ddf3 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -146,7 +146,6 @@ use self::Option::*; use clone::Clone; -use cmp::{Eq, Ord}; use default::Default; use iter::ExactSizeIterator; use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator}; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7aacdbeb76879..101afa21d2742 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -19,7 +19,6 @@ use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char::{self, CharExt}; use clone::Clone; -use cmp::Eq; use convert::AsRef; use default::Default; use fmt; @@ -1180,7 +1179,6 @@ Section: Trait implementations mod traits { use cmp::{self, Ordering, Ord, PartialEq, PartialOrd, Eq}; use cmp::Ordering::{Less, Greater}; - use iter::Iterator; use option::Option; use option::Option::Some; use ops; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 1ed873f0508d5..56baf9ab6d956 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -29,7 +29,7 @@ use middle::privacy::AccessLevels; use middle::ty::{self, Ty}; use session::{early_error, Session}; use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass}; -use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject}; +use lint::{EarlyLintPassObject, LateLintPass, LateLintPassObject}; use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; use lint::builtin; use util::nodemap::FnvHashMap; diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index ec1b447d7111b..4afa0e301465f 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -22,7 +22,7 @@ use lint; use std::collections::HashSet; use syntax::{ast, codemap}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; // Any local node that may call something in its body block should be // explored. For example, if it's a live NodeItem that is a diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index 9f33c4df03d41..6c24134f5a558 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -15,7 +15,7 @@ use middle::infer::{InferCtxt, GenericKind}; use middle::subst::Substs; use middle::traits; use middle::ty::{self, RegionEscape, ToPredicate, Ty}; -use middle::ty::fold::{TypeFoldable, TypeFolder}; +use middle::ty::fold::TypeFoldable; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 03554a59655b1..d455b1a4fa6f6 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -46,7 +46,7 @@ use middle::ty::{IntType, UintType}; use middle::ty::{self, Ty}; use middle::ty::error::TypeError; use middle::ty::fold::{TypeFolder, TypeFoldable}; -use middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use middle::ty::relate::{RelateResult, TypeRelation}; use syntax::ast; use syntax::codemap::Span; diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b39ddfe95c83a..25dde6739c1e9 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -33,7 +33,7 @@ use middle::ty::adjustment; use middle::ty::{TyVid, IntVid, FloatVid, RegionVid}; use middle::ty::{self, Ty, HasTypeFlags}; use middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::fold::TypeFoldable; use middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{RefCell, Ref}; diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index cee651743ca86..5e0cc5131bcc0 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -271,6 +271,7 @@ pub struct ctxt<'tcx> { pub map: ast_map::Map<'tcx>, pub freevars: RefCell, + pub maybe_unused_trait_imports: NodeSet, pub tcache: RefCell>>, pub rcache: RefCell>>, pub tc_cache: RefCell, ty::contents::TypeContents>>, @@ -306,6 +307,10 @@ pub struct ctxt<'tcx> { /// about. pub used_mut_nodes: RefCell, + /// Set of trait imports actually used in method resolution. + /// This is used for warning unused imports. + pub used_trait_imports: RefCell, + /// The set of external nominal types whose implementations have been read. /// This is used for lazy resolution of methods. pub populated_external_types: RefCell, @@ -475,6 +480,7 @@ impl<'tcx> ctxt<'tcx> { named_region_map: resolve_lifetime::NamedRegionMap, map: ast_map::Map<'tcx>, freevars: FreevarMap, + maybe_unused_trait_imports: NodeSet, region_maps: RegionMaps, lang_items: middle::lang_items::LanguageItems, stability: stability::Index<'tcx>, @@ -508,6 +514,7 @@ impl<'tcx> ctxt<'tcx> { fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()), map: map, freevars: RefCell::new(freevars), + maybe_unused_trait_imports: maybe_unused_trait_imports, tcache: RefCell::new(DefIdMap()), rcache: RefCell::new(FnvHashMap()), tc_cache: RefCell::new(FnvHashMap()), @@ -522,6 +529,7 @@ impl<'tcx> ctxt<'tcx> { impl_items: RefCell::new(DefIdMap()), used_unsafe: RefCell::new(NodeSet()), used_mut_nodes: RefCell::new(NodeSet()), + used_trait_imports: RefCell::new(NodeSet()), populated_external_types: RefCell::new(DefIdSet()), populated_external_primitive_impls: RefCell::new(DefIdSet()), extern_const_statics: RefCell::new(DefIdMap()), diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 7477c4dead031..5dc539ea882c7 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -29,14 +29,13 @@ use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangIte use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; -use middle::ty::fold::TypeFolder; use middle::ty::walk::TypeWalker; use util::common::memoized; use util::nodemap::{NodeMap, NodeSet, DefIdMap}; use util::nodemap::FnvHashMap; use serialize::{Encodable, Encoder, Decodable, Decoder}; -use std::borrow::{Borrow, Cow}; +use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::hash::{Hash, Hasher}; use std::iter; @@ -2752,8 +2751,13 @@ pub type FreevarMap = NodeMap>; pub type CaptureModeMap = NodeMap; +pub struct TraitCandidate { + pub def_id: DefId, + pub import_id: Option, +} + // Trait method resolution -pub type TraitMap = NodeMap>; +pub type TraitMap = NodeMap>; // Map from the NodeId of a glob import to a list of items which are actually // imported. diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs index 0517769356f75..f183f3a0b6076 100644 --- a/src/librustc/middle/ty/util.rs +++ b/src/librustc/middle/ty/util.rs @@ -28,7 +28,7 @@ use std::cmp; use std::hash::{Hash, SipHasher, Hasher}; use std::rc::Rc; use syntax::ast::{self, Name}; -use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt}; +use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax::codemap::Span; use rustc_front::hir; diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs index 09c6b54d99cf8..7749cbd238599 100644 --- a/src/librustc/session/filesearch.rs +++ b/src/librustc/session/filesearch.rs @@ -15,7 +15,6 @@ pub use self::FileMatch::*; use std::collections::HashSet; use std::env; use std::fs; -use std::io::prelude::*; use std::path::{Path, PathBuf}; use session::search_paths::{SearchPaths, PathKind}; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 69e065b3e8f97..7541e752fbbaa 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -703,6 +703,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let resolve::CrateMap { def_map, freevars, + maybe_unused_trait_imports, export_map, trait_map, external_exports, @@ -741,6 +742,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, named_region_map, ast_map, freevars, + maybe_unused_trait_imports, region_map, lang_items, stability::Index::new(krate), diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 2fb23c943c76a..124b3192d9b19 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -128,7 +128,7 @@ fn test_env(source_string: &str, // run just enough stuff to build a tcx: let lang_items = lang_items::collect_language_items(&sess, &ast_map); - let resolve::CrateMap { def_map, freevars, .. } = + let resolve::CrateMap { def_map, freevars, maybe_unused_trait_imports, .. } = resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No); let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map.borrow()); let region_map = region::resolve_crate(&sess, krate); @@ -138,6 +138,7 @@ fn test_env(source_string: &str, named_region_map, ast_map, freevars, + maybe_unused_trait_imports, region_map, lang_items, stability::Index::new(krate), diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a1d029025b2fa..b963329049d9e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -22,7 +22,7 @@ use std::cmp; use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; use syntax::{abi, ast}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::codemap::{self, Span}; use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64}; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a627eeb688075..c9ce36ae2122b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -43,7 +43,6 @@ use std::u32; use syntax::abi; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::diagnostic::SpanHandler; use syntax::parse::token::special_idents; use syntax; diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 7f740f9c03335..ceed90059628a 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -16,6 +16,8 @@ // resolve data structures and because it finalises the privacy information for // `use` directives. // +// Unused trait imports can't be checked until the method resolution. We save +// candidates here, and do the actual check in librustc_typeck/check_unused.rs. use std::ops::{Deref, DerefMut}; @@ -62,13 +64,7 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { 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()); - } + self.check_import(id, span); let mut def_map = self.def_map.borrow_mut(); let path_res = if let Some(r) = def_map.get_mut(&id) { @@ -109,6 +105,24 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { type_used: t_used, }; } + + fn check_import(&mut self, id: ast::NodeId, span: Span) { + if !self.used_imports.contains(&(id, TypeNS)) && + !self.used_imports.contains(&(id, ValueNS)) { + if self.maybe_unused_trait_imports.contains(&id) { + // Check later. + return; + } + self.session.add_lint(lint::builtin::UNUSED_IMPORTS, + id, + span, + "unused import".to_string()); + } else { + // This trait import is definitely used, in a way other than + // method resolution. + self.maybe_unused_trait_imports.remove(&id); + } + } } impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { @@ -144,14 +158,7 @@ impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { } } ViewPathGlob(_) => { - if !self.used_imports.contains(&(item.id, TypeNS)) && - !self.used_imports.contains(&(item.id, ValueNS)) { - self.session - .add_lint(lint::builtin::UNUSED_IMPORTS, - item.id, - p.span, - "unused import".to_string()); - } + self.check_import(item.id, p.span); } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c32acb7bb269f..15ca1d51ab504 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -60,13 +60,12 @@ use rustc::middle::def_id::DefId; use rustc::middle::pat_util::pat_bindings; use rustc::middle::privacy::*; use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace}; -use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap}; -use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap}; +use rustc::middle::ty::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; +use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap}; use syntax::ast; use syntax::ast::{CRATE_NODE_ID, Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64}; use syntax::ast::{TyUs, TyU8, TyU16, TyU32, TyU64, TyF64, TyF32}; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::{self, special_names, special_idents}; use syntax::codemap::{self, Span, Pos}; use syntax::util::lev_distance::{lev_distance, max_suggestion_distance}; @@ -1142,6 +1141,7 @@ pub struct Resolver<'a, 'tcx: 'a> { used_imports: HashSet<(NodeId, Namespace)>, used_crates: HashSet, + maybe_unused_trait_imports: NodeSet, // Callback function for intercepting walks callback: Option bool>>, @@ -1193,14 +1193,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { freevars_seen: NodeMap(), export_map: NodeMap(), trait_map: NodeMap(), - used_imports: HashSet::new(), - used_crates: HashSet::new(), external_exports: DefIdSet(), emit_errors: true, make_glob_map: make_glob_map == MakeGlobMap::Yes, glob_map: HashMap::new(), + used_imports: HashSet::new(), + used_crates: HashSet::new(), + maybe_unused_trait_imports: NodeSet(), + callback: None, resolved: false, } @@ -3609,14 +3611,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn get_traits_containing_item(&mut self, name: Name) -> Vec { + fn get_traits_containing_item(&mut self, name: Name) -> Vec { debug!("(getting traits containing item) looking for '{}'", name); - fn add_trait_info(found_traits: &mut Vec, trait_def_id: DefId, name: Name) { + fn add_trait_info(found_traits: &mut Vec, + trait_def_id: DefId, + import_id: Option, + name: Name) { debug!("(adding trait info) found trait {:?} for method '{}'", trait_def_id, name); - found_traits.push(trait_def_id); + found_traits.push(TraitCandidate { + def_id: trait_def_id, + import_id: import_id, + }); } let mut found_traits = Vec::new(); @@ -3626,7 +3634,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match self.current_trait_ref { Some((trait_def_id, _)) => { if self.trait_item_map.contains_key(&(name, trait_def_id)) { - add_trait_info(&mut found_traits, trait_def_id, name); + add_trait_info(&mut found_traits, trait_def_id, None, name); } } None => {} // Nothing to do. @@ -3646,7 +3654,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => continue, }; if self.trait_item_map.contains_key(&(name, trait_def_id)) { - add_trait_info(&mut found_traits, trait_def_id, name); + add_trait_info(&mut found_traits, trait_def_id, None, name); } } } @@ -3662,9 +3670,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(..) | None => continue, }; if self.trait_item_map.contains_key(&(name, did)) { - add_trait_info(&mut found_traits, did, name); let id = import.type_ns.id; - self.used_imports.insert((id, TypeNS)); + add_trait_info(&mut found_traits, did, Some(id), name); + self.maybe_unused_trait_imports.insert(id); let trait_name = self.get_trait_name(did); self.record_import_use(id, trait_name); if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() { @@ -3815,6 +3823,7 @@ fn module_to_string(module: &Module) -> String { pub struct CrateMap { pub def_map: RefCell, pub freevars: FreevarMap, + pub maybe_unused_trait_imports: NodeSet, pub export_map: ExportMap, pub trait_map: TraitMap, pub external_exports: ExternalExports, @@ -3843,6 +3852,7 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session, CrateMap { def_map: resolver.def_map, freevars: resolver.freevars, + maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, export_map: resolver.export_map, trait_map: resolver.trait_map, external_exports: resolver.external_exports, diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index fd471893acd53..4f9a70626665b 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -30,7 +30,6 @@ use rustc::middle::def_id::DefId; use rustc::middle::privacy::*; use syntax::ast::{NodeId, Name}; -use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; use std::mem::replace; diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index fa500ab93552c..69b21a161766b 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -38,7 +38,7 @@ use trans::type_::Type; use trans::type_of; use middle::traits; use middle::ty::{self, HasTypeFlags, Ty}; -use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::fold::TypeFoldable; use rustc_front::hir; use rustc::mir::repr::Mir; use util::nodemap::{FnvHashMap, NodeMap}; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 9c1fcaff7c895..214a6aa612420 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -16,7 +16,7 @@ use middle::def_id::DefId; use middle::infer::normalize_associated_type; use middle::subst; use middle::subst::{Subst, Substs}; -use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::fold::TypeFoldable; use trans::attributes; use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; use trans::base::trans_fn; diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index b9fec44ec4030..18f1ad3d4d3dd 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -11,18 +11,15 @@ //! Type-checking for the rust-intrinsic and platform-intrinsic //! intrinsics that the compiler exposes. -use astconv::AstConv; use intrinsics; use middle::subst; use middle::ty::FnSig; use middle::ty::{self, Ty}; -use middle::ty::fold::TypeFolder; use {CrateCtxt, require_same_types}; use std::collections::{HashMap}; use syntax::abi; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::codemap::Span; use syntax::parse::token; diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e0ad51b4ea1b5..e74b013152f28 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -10,7 +10,6 @@ //! Method lookup: the secret sauce of Rust. See `README.md`. -use astconv::AstConv; use check::FnCtxt; use middle::def; use middle::def_id::DefId; @@ -126,6 +125,11 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let mode = probe::Mode::MethodCall; let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty); let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id)); + + if let Some(import_id) = pick.import_id { + fcx.tcx().used_trait_imports.borrow_mut().insert(import_id); + } + Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } @@ -338,6 +342,11 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, { let mode = probe::Mode::Path; let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id)); + + if let Some(import_id) = pick.import_id { + fcx.tcx().used_trait_imports.borrow_mut().insert(import_id); + } + let def_id = pick.item.def_id(); let mut lp = LastMod(AllPublic); if let probe::InherentImplPick = pick.kind { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index ed819d46041e6..1ee7c0bf97c53 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -44,6 +44,7 @@ struct ProbeContext<'a, 'tcx:'a> { inherent_candidates: Vec>, extension_candidates: Vec>, impl_dups: HashSet, + import_id: Option, /// Collects near misses when the candidate functions are missing a `self` keyword and is only /// used for error reporting @@ -66,6 +67,7 @@ struct Candidate<'tcx> { xform_self_ty: Ty<'tcx>, item: ty::ImplOrTraitItem<'tcx>, kind: CandidateKind<'tcx>, + import_id: Option, } #[derive(Debug)] @@ -83,6 +85,7 @@ enum CandidateKind<'tcx> { pub struct Pick<'tcx> { pub item: ty::ImplOrTraitItem<'tcx>, pub kind: PickKind<'tcx>, + pub import_id: Option, // Indicates that the source expression should be autoderef'd N times // @@ -246,6 +249,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { inherent_candidates: Vec::new(), extension_candidates: Vec::new(), impl_dups: HashSet::new(), + import_id: None, steps: Rc::new(steps), opt_simplified_steps: opt_simplified_steps, static_candidates: Vec::new(), @@ -427,7 +431,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: InherentImplCandidate(impl_substs, obligations) + kind: InherentImplCandidate(impl_substs, obligations), + import_id: self.import_id, }); } @@ -455,7 +460,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: ObjectCandidate + kind: ObjectCandidate, + import_id: this.import_id, }); }); } @@ -524,7 +530,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { this.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: WhereClauseCandidate(poly_trait_ref) + kind: WhereClauseCandidate(poly_trait_ref), + import_id: this.import_id, }); }); } @@ -568,9 +575,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let mut duplicates = HashSet::new(); let opt_applicable_traits = self.fcx.ccx.trait_map.get(&expr_id); if let Some(applicable_traits) = opt_applicable_traits { - for &trait_did in applicable_traits { + for trait_candidate in applicable_traits { + let trait_did = trait_candidate.def_id; if duplicates.insert(trait_did) { - try!(self.assemble_extension_candidates_for_trait(trait_did)); + self.import_id = trait_candidate.import_id; + let result = self.assemble_extension_candidates_for_trait(trait_did); + self.import_id = None; + try!(result); } } } @@ -670,7 +681,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations) + kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations), + import_id: self.import_id, }); }); } @@ -745,7 +757,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: TraitCandidate + kind: TraitCandidate, + import_id: self.import_id, }); } @@ -802,7 +815,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: TraitCandidate + kind: TraitCandidate, + import_id: self.import_id, }); } } @@ -833,7 +847,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: WhereClauseCandidate(poly_bound) + kind: WhereClauseCandidate(poly_bound), + import_id: self.import_id, }); } } @@ -1126,6 +1141,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { Some(Pick { item: probes[0].item.clone(), kind: TraitPick, + import_id: probes[0].import_id, autoderefs: 0, autoref: None, unsize: None @@ -1329,6 +1345,7 @@ impl<'tcx> Candidate<'tcx> { WhereClausePick(trait_ref.clone()) } }, + import_id: self.import_id, autoderefs: 0, autoref: None, unsize: None diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 955bc92a8f31e..039257d72b2ff 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -13,7 +13,6 @@ use CrateCtxt; -use astconv::AstConv; use check::{self, FnCtxt}; use front::map as hir_map; use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, HasTypeFlags}; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a50213202b82c..91549ccd1310d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -100,7 +100,7 @@ use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty}; use middle::ty::{MethodCall, MethodCallee}; use middle::ty::adjustment; use middle::ty::error::TypeError; -use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::fold::TypeFoldable; use middle::ty::util::Representability; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index f980945dbf220..d2fe174f3915e 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -82,7 +82,6 @@ //! relation, except that a borrowed pointer never owns its //! contents. -use astconv::AstConv; use check::dropck; use check::FnCtxt; use middle::free_region::FreeRegionMap; diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 3daf5003b97e0..8606f9f81c929 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use astconv::AstConv; use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck, wfcheck}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index a9bd0e3926811..dfc4ddee48758 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use astconv::AstConv; use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; @@ -16,7 +15,6 @@ use middle::def_id::DefId; use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use middle::traits; use middle::ty::{self, Ty}; -use middle::ty::fold::{TypeFolder}; use std::cell::RefCell; use std::collections::HashSet; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 984f227cebe79..c1d4d49512c68 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -13,7 +13,6 @@ // substitutions. use self::ResolveReason::*; -use astconv::AstConv; use check::FnCtxt; use middle::def_id::DefId; use middle::pat_util; diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs new file mode 100644 index 0000000000000..7a66bb05090c2 --- /dev/null +++ b/src/librustc_typeck/check_unused.rs @@ -0,0 +1,62 @@ +// Copyright 2015 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. + +use lint; +use middle::ty; + +use syntax::ast; +use syntax::codemap::{Span, DUMMY_SP}; + +use rustc_front::hir; +use rustc_front::intravisit::Visitor; + +struct UnusedTraitImportVisitor<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx>, +} + +impl<'a, 'tcx> UnusedTraitImportVisitor<'a, 'tcx> { + fn check_import(&self, id: ast::NodeId, span: Span) { + if !self.tcx.maybe_unused_trait_imports.contains(&id) { + return; + } + if self.tcx.used_trait_imports.borrow().contains(&id) { + return; + } + self.tcx.sess.add_lint(lint::builtin::UNUSED_IMPORTS, + id, + span, + "unused import".to_string()); + } +} + +impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + if item.vis == hir::Public || item.span == DUMMY_SP { + return; + } + if let hir::ItemUse(ref path) = item.node { + match path.node { + hir::ViewPathSimple(..) | hir::ViewPathGlob(..) => { + self.check_import(item.id, path.span); + } + hir::ViewPathList(_, ref path_list) => { + for path_item in path_list { + self.check_import(path_item.node.id(), path_item.span); + } + } + } + } + } +} + +pub fn check_crate(tcx: &ty::ctxt) { + let mut visitor = UnusedTraitImportVisitor { tcx: tcx }; + tcx.map.krate().visit_all_items(&mut visitor); +} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 86a56e718b5cf..860cbf7da1f0d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -78,7 +78,7 @@ use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerPar use middle::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty, TypeScheme}; use middle::ty::{VariantKind}; -use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::fold::TypeFoldable; use middle::ty::util::IntTypeExt; use middle::infer; use rscope::*; diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 495b8995ceea2..39e650b308264 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -120,6 +120,7 @@ use std::cell::RefCell; pub mod diagnostics; pub mod check; +pub mod check_unused; mod rscope; mod astconv; pub mod collect; @@ -361,6 +362,7 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { time(time_passes, "wf checking (new)", || check::check_wf_new(&ccx)); + check_unused::check_crate(tcx); check_for_entry_fn(&ccx); tcx.sess.abort_if_errors(); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 40e7146670907..ff00643923a74 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -13,7 +13,6 @@ use std::collections::HashSet; use syntax::ast; -use syntax::attr::AttrMetaMethods; use rustc_front::hir; use rustc::middle::cstore::{self, CrateStore}; diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 8ea8f0c6c771b..07e49e2da97b0 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use io::prelude::*; use os::unix::prelude::*; use ffi::{CString, CStr, OsString, OsStr}; diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index b854a2f2a0a17..3b7b5d854adac 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -289,8 +289,6 @@ pub enum Level { impl fmt::Display for Level { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use std::fmt::Display; - match *self { Bug => "error: internal compiler error".fmt(f), Fatal | Error => "error".fmt(f), diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index e9c8173a4d980..1b6f963f5751c 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -19,7 +19,6 @@ use ptr::P; use str::char_at; use std::cell::RefCell; -use std::io::Read; use std::iter; use std::path::{Path, PathBuf}; use std::rc::Rc; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7502a8cbc3546..566794a13612f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -78,7 +78,6 @@ use parse::PResult; use diagnostic::FatalError; use std::collections::HashSet; -use std::io::prelude::*; use std::mem; use std::path::{Path, PathBuf}; use std::rc::Rc; diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 6e9c161293de2..8e20358027b22 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -115,14 +115,12 @@ impl Ord for RcStr { impl fmt::Debug for RcStr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use std::fmt::Debug; self[..].fmt(f) } } impl fmt::Display for RcStr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use std::fmt::Display; self[..].fmt(f) } } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 7ffe567ac83c1..c41ac49b03474 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -58,9 +58,7 @@ use self::TestEvent::*; use self::NamePadding::*; use self::OutputLocation::*; -use stats::Stats; use getopts::{OptGroup, optflag, optopt}; -use serialize::Encodable; use std::boxed::FnBox; use term::Terminal; use term::color::{Color, RED, YELLOW, GREEN, CYAN}; diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs index d23e868eeadd1..2e03ad512b5a8 100644 --- a/src/rustbook/main.rs +++ b/src/rustbook/main.rs @@ -19,10 +19,8 @@ extern crate rustdoc; extern crate rustc_back; use std::env; -use std::error::Error; use std::process; use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering}; -use subcommand::Subcommand; use term::Term; mod term; diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 1468ae64d9418..3eb0d48956b16 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -24,6 +24,8 @@ use test::A; //~ ERROR unused import // Be sure that if we just bring some methods into scope that they're also // counted as being used. use test::B; +// But only when actually used: do not get confused by the method with the same name. +use test::B2; //~ ERROR unused import // Make sure this import is warned about when at least one of its imported names // is unused @@ -37,6 +39,7 @@ mod test2 { mod test { pub trait A { fn a(&self) {} } pub trait B { fn b(&self) {} } + pub trait B2 { fn b(&self) {} } pub struct C; impl A for C {} impl B for C {}