use astconv::AstConv;
use check::{self, FnCtxt};
-use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, HasTypeFlags};
+use front::map as hir_map;
+use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
+use middle::cstore::{self, CrateStore, DefLike};
use middle::def;
use middle::def_id::DefId;
use middle::lang_items::FnOnceTraitLangItem;
use middle::subst::Substs;
use middle::traits::{Obligation, SelectionContext};
-use metadata::{csearch, cstore, decoder};
+use util::nodemap::{FnvHashSet};
use syntax::ast;
use syntax::codemap::Span;
+use syntax::errors::DiagnosticBuilder;
use rustc_front::print::pprust;
use rustc_front::hir;
mode }) => {
let cx = fcx.tcx();
- fcx.type_error_message(
+ let mut err = fcx.type_error_struct(
span,
|actual| {
format!("no {} named `{}` found for type `{}` \
// snippet
};
- let span_stored_function = || {
- cx.sess.span_note(span,
+ macro_rules! span_stored_function {
+ () => {
+ err.span_note(span,
&format!("use `({0}.{1})(...)` if you meant to call \
the function stored in the `{1}` field",
expr_string, item_name));
- };
+ }
+ }
- let span_did_you_mean = || {
- cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?",
+ macro_rules! span_did_you_mean {
+ () => {
+ err.span_note(span, &format!("did you mean to write `{0}.{1}`?",
expr_string, item_name));
- };
+ }
+ }
// Determine if the field can be used as a function in some way
let field_ty = field.ty(cx, substs);
- if let Ok(fn_once_trait_did) = cx.lang_items.require(FnOnceTraitLangItem) {
- let infcx = fcx.infcx();
- infcx.probe(|_| {
- let fn_once_substs = Substs::new_trait(vec![infcx.next_ty_var()],
- Vec::new(),
- field_ty);
- let trait_ref = ty::TraitRef::new(fn_once_trait_did,
- cx.mk_substs(fn_once_substs));
- let poly_trait_ref = trait_ref.to_poly_trait_ref();
- let obligation = Obligation::misc(span,
- fcx.body_id,
- poly_trait_ref.to_predicate());
- let mut selcx = SelectionContext::new(infcx);
-
- if selcx.evaluate_obligation(&obligation) {
- span_stored_function();
+
+ match field_ty.sty {
+ // Not all of these (e.g. unsafe fns) implement FnOnce
+ // so we look for these beforehand
+ ty::TyClosure(..) | ty::TyBareFn(..) => {
+ span_stored_function!();
+ }
+ // If it's not a simple function, look for things which implement FnOnce
+ _ => {
+ if let Ok(fn_once_trait_did) =
+ cx.lang_items.require(FnOnceTraitLangItem) {
+ let infcx = fcx.infcx();
+ infcx.probe(|_| {
+ let fn_once_substs =
+ Substs::new_trait(vec![infcx.next_ty_var()],
+ Vec::new(),
+ field_ty);
+ let trait_ref =
+ ty::TraitRef::new(fn_once_trait_did,
+ cx.mk_substs(fn_once_substs));
+ let poly_trait_ref = trait_ref.to_poly_trait_ref();
+ let obligation = Obligation::misc(span,
+ fcx.body_id,
+ poly_trait_ref
+ .to_predicate());
+ let mut selcx = SelectionContext::new(infcx);
+
+ if selcx.evaluate_obligation(&obligation) {
+ span_stored_function!();
+ } else {
+ span_did_you_mean!();
+ }
+ });
} else {
- span_did_you_mean();
+ span_did_you_mean!();
}
- });
- } else {
- match field_ty.sty {
- // fallback to matching a closure or function pointer
- ty::TyClosure(..) | ty::TyBareFn(..) => span_stored_function(),
- _ => span_did_you_mean(),
}
}
}
}
if !static_sources.is_empty() {
- cx.sess.fileline_note(
+ err.fileline_note(
span,
"found defined static methods, maybe a `self` is missing?");
- report_candidates(fcx, span, item_name, static_sources);
+ report_candidates(fcx, &mut err, span, item_name, static_sources);
}
if !unsatisfied_predicates.is_empty() {
p))
.collect::<Vec<_>>()
.join(", ");
- cx.sess.fileline_note(
+ err.fileline_note(
span,
&format!("the method `{}` exists but the \
following trait bounds were not satisfied: {}",
bound_list));
}
- suggest_traits_to_import(fcx, span, rcvr_ty, item_name,
- rcvr_expr, out_of_scope_traits)
+ suggest_traits_to_import(fcx, &mut err, span, rcvr_ty, item_name,
+ rcvr_expr, out_of_scope_traits);
+ err.emit();
}
MethodError::Ambiguity(sources) => {
- span_err!(fcx.sess(), span, E0034,
- "multiple applicable items in scope");
+ let mut err = struct_span_err!(fcx.sess(), span, E0034,
+ "multiple applicable items in scope");
- report_candidates(fcx, span, item_name, sources);
+ report_candidates(fcx, &mut err, span, item_name, sources);
+ err.emit();
}
MethodError::ClosureAmbiguity(trait_def_id) => {
}
fn report_candidates(fcx: &FnCtxt,
+ err: &mut DiagnosticBuilder,
span: Span,
item_name: ast::Name,
mut sources: Vec<CandidateSource>) {
CandidateSource::ImplSource(impl_did) => {
// Provide the best span we can. Use the item, if local to crate, else
// the impl, if local to crate (item may be defaulted), else the call site.
- let item = impl_item(fcx.tcx(), impl_did, item_name).unwrap();
+ let item = impl_item(fcx.tcx(), impl_did, item_name)
+ .or_else(|| {
+ trait_item(
+ fcx.tcx(),
+ fcx.tcx().impl_trait_ref(impl_did).unwrap().def_id,
+ item_name
+ )
+ }).unwrap();
let impl_span = fcx.tcx().map.def_id_span(impl_did, span);
let item_span = fcx.tcx().map.def_id_span(item.def_id(), impl_span);
}
};
- span_note!(fcx.sess(), item_span,
+ span_note!(err, item_span,
"candidate #{} is defined in an impl{} for the type `{}`",
idx + 1,
insertion,
CandidateSource::TraitSource(trait_did) => {
let item = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
let item_span = fcx.tcx().map.def_id_span(item.def_id(), span);
- span_note!(fcx.sess(), item_span,
+ span_note!(err, item_span,
"candidate #{} is defined in the trait `{}`",
idx + 1,
fcx.tcx().item_path_str(trait_did));
pub type AllTraitsVec = Vec<TraitInfo>;
fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ err: &mut DiagnosticBuilder,
span: Span,
rcvr_ty: Ty<'tcx>,
item_name: ast::Name,
traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"},
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"});
- fcx.sess().fileline_help(span, &msg[..]);
+ err.fileline_help(span, &msg[..]);
for (i, trait_did) in candidates.iter().enumerate() {
- fcx.sess().fileline_help(span,
- &*format!("candidate #{}: use `{}`",
- i + 1,
- fcx.tcx().item_path_str(*trait_did)))
-
+ err.fileline_help(span,
+ &*format!("candidate #{}: use `{}`",
+ i + 1,
+ fcx.tcx().item_path_str(*trait_did)));
}
return
}
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"},
name = item_name);
- fcx.sess().fileline_help(span, &msg[..]);
+ err.fileline_help(span, &msg[..]);
for (i, trait_info) in candidates.iter().enumerate() {
- fcx.sess().fileline_help(span,
- &*format!("candidate #{}: `{}`",
- i + 1,
- fcx.tcx().item_path_str(trait_info.def_id)))
+ err.fileline_help(span,
+ &*format!("candidate #{}: `{}`",
+ i + 1,
+ fcx.tcx().item_path_str(trait_info.def_id)));
}
}
}
}
impl Ord for TraitInfo {
fn cmp(&self, other: &TraitInfo) -> Ordering {
- // accessible traits are more important/relevant than
- // inaccessible ones, local crates are more important than
- // remote ones (local: cnum == 0), and NodeIds just for
- // totality.
+ // local crates are more important than remote ones (local:
+ // cnum == 0), and otherwise we throw in the defid for totality
- let lhs = (other.def_id.krate, other.def_id.node);
- let rhs = (self.def_id.krate, self.def_id.node);
+ let lhs = (other.def_id.krate, other.def_id);
+ let rhs = (self.def_id.krate, self.def_id);
lhs.cmp(&rhs)
}
}
/// Retrieve all traits in this crate and any dependent crates.
pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
if ccx.all_traits.borrow().is_none() {
- use rustc_front::visit;
+ use rustc_front::intravisit;
let mut traits = vec![];
// Crate-local:
//
// meh.
- struct Visitor<'a> {
+ struct Visitor<'a, 'tcx:'a> {
+ map: &'a hir_map::Map<'tcx>,
traits: &'a mut AllTraitsVec,
}
- impl<'v, 'a> visit::Visitor<'v> for Visitor<'a> {
+ impl<'v, 'a, 'tcx> intravisit::Visitor<'v> for Visitor<'a, 'tcx> {
fn visit_item(&mut self, i: &'v hir::Item) {
match i.node {
hir::ItemTrait(..) => {
- self.traits.push(TraitInfo::new(DefId::local(i.id)));
+ let def_id = self.map.local_def_id(i.id);
+ self.traits.push(TraitInfo::new(def_id));
}
_ => {}
}
- visit::walk_item(self, i)
}
}
- visit::walk_crate(&mut Visitor {
+ ccx.tcx.map.krate().visit_all_items(&mut Visitor {
+ map: &ccx.tcx.map,
traits: &mut traits
- }, ccx.tcx.map.krate());
+ });
// Cross-crate:
+ let mut external_mods = FnvHashSet();
fn handle_external_def(traits: &mut AllTraitsVec,
+ external_mods: &mut FnvHashSet<DefId>,
ccx: &CrateCtxt,
- cstore: &cstore::CStore,
- dl: decoder::DefLike) {
+ cstore: &for<'a> cstore::CrateStore<'a>,
+ dl: cstore::DefLike) {
match dl {
- decoder::DlDef(def::DefTrait(did)) => {
+ cstore::DlDef(def::DefTrait(did)) => {
traits.push(TraitInfo::new(did));
}
- decoder::DlDef(def::DefMod(did)) => {
- csearch::each_child_of_item(cstore, did, |dl, _, _| {
- handle_external_def(traits, ccx, cstore, dl)
- })
+ cstore::DlDef(def::DefMod(did)) => {
+ if !external_mods.insert(did) {
+ return;
+ }
+ for child in cstore.item_children(did) {
+ handle_external_def(traits, external_mods,
+ ccx, cstore, child.def)
+ }
}
_ => {}
}
}
- let cstore = &ccx.tcx.sess.cstore;
- cstore.iter_crate_data(|cnum, _| {
- csearch::each_top_level_item_of_crate(cstore, cnum, |dl, _, _| {
- handle_external_def(&mut traits, ccx, cstore, dl)
- })
- });
+ let cstore = &*ccx.tcx.sess.cstore;
+
+ for cnum in ccx.tcx.sess.cstore.crates() {
+ for child in cstore.crate_top_level_items(cnum) {
+ handle_external_def(&mut traits, &mut external_mods,
+ ccx, cstore, child.def)
+ }
+ }
*ccx.all_traits.borrow_mut() = Some(traits);
}