SelectionContext,
SelectionError,
ObjectSafetyViolation,
- MethodViolationCode,
};
+use errors::DiagnosticBuilder;
use fmt_macros::{Parser, Piece, Position};
+use hir::{intravisit, Local, Pat};
+use hir::intravisit::{Visitor, NestedVisitorMap};
+use hir::map::NodeExpr;
use hir::def_id::DefId;
use infer::{self, InferCtxt};
use infer::type_variable::TypeVariableOrigin;
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
+use std::fmt;
+use syntax::ast;
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::error::ExpectedFound;
use ty::fast_reject;
use ty::subst::Subst;
use util::nodemap::{FxHashMap, FxHashSet};
-use std::cmp;
-use std::fmt;
-use syntax::ast;
use syntax_pos::{DUMMY_SP, Span};
-use errors::DiagnosticBuilder;
+
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct TraitErrorKey<'tcx> {
}
}
+struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+ infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+ target_ty: &'a Ty<'tcx>,
+ found_pattern: Option<&'a Pat>,
+}
+
+impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_local(&mut self, local: &'a Local) {
+ if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) {
+ let ty = self.infcx.resolve_type_vars_if_possible(&ty);
+ let is_match = ty.walk().any(|t| t == *self.target_ty);
+
+ if is_match && self.found_pattern.is_none() {
+ self.found_pattern = Some(&*local.pat);
+ }
+ }
+ intravisit::walk_local(self, local);
+ }
+}
+
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn report_fulfillment_errors(&self, errors: &Vec<FulfillmentError<'tcx>>) {
for error in errors {
let span = obligation.cause.span;
let mut report = None;
- for item in self.tcx.get_attrs(def_id).iter() {
- if item.check_name("rustc_on_unimplemented") {
- let err_sp = item.meta().span.substitute_dummy(span);
- let trait_str = self.tcx.item_path_str(trait_ref.def_id);
- if let Some(istring) = item.value_str() {
- let istring = &*istring.as_str();
- let generics = self.tcx.item_generics(trait_ref.def_id);
- let generic_map = generics.types.iter().map(|param| {
- (param.name.as_str().to_string(),
- trait_ref.substs.type_for_def(param).to_string())
- }).collect::<FxHashMap<String, String>>();
- let parser = Parser::new(istring);
- let mut errored = false;
- let err: String = parser.filter_map(|p| {
- match p {
- Piece::String(s) => Some(s),
- Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(s) => match generic_map.get(s) {
- Some(val) => Some(val),
- None => {
- span_err!(self.tcx.sess, err_sp, E0272,
- "the #[rustc_on_unimplemented] \
- attribute on \
- trait definition for {} refers to \
- non-existent type parameter {}",
- trait_str, s);
- errored = true;
- None
- }
- },
- _ => {
- span_err!(self.tcx.sess, err_sp, E0273,
- "the #[rustc_on_unimplemented] attribute \
- on trait definition for {} must have \
- named format arguments, eg \
- `#[rustc_on_unimplemented = \
- \"foo {{T}}\"]`", trait_str);
+ if let Some(item) = self.tcx
+ .get_attrs(def_id)
+ .into_iter()
+ .filter(|a| a.check_name("rustc_on_unimplemented"))
+ .next()
+ {
+ let err_sp = item.meta().span.substitute_dummy(span);
+ let trait_str = self.tcx.item_path_str(trait_ref.def_id);
+ if let Some(istring) = item.value_str() {
+ let istring = &*istring.as_str();
+ let generics = self.tcx.item_generics(trait_ref.def_id);
+ let generic_map = generics.types.iter().map(|param| {
+ (param.name.as_str().to_string(),
+ trait_ref.substs.type_for_def(param).to_string())
+ }).collect::<FxHashMap<String, String>>();
+ let parser = Parser::new(istring);
+ let mut errored = false;
+ let err: String = parser.filter_map(|p| {
+ match p {
+ Piece::String(s) => Some(s),
+ Piece::NextArgument(a) => match a.position {
+ Position::ArgumentNamed(s) => match generic_map.get(s) {
+ Some(val) => Some(val),
+ None => {
+ span_err!(self.tcx.sess, err_sp, E0272,
+ "the #[rustc_on_unimplemented] \
+ attribute on \
+ trait definition for {} refers to \
+ non-existent type parameter {}",
+ trait_str, s);
errored = true;
None
}
+ },
+ _ => {
+ span_err!(self.tcx.sess, err_sp, E0273,
+ "the #[rustc_on_unimplemented] attribute \
+ on trait definition for {} must have \
+ named format arguments, eg \
+ `#[rustc_on_unimplemented = \
+ \"foo {{T}}\"]`", trait_str);
+ errored = true;
+ None
}
}
- }).collect();
- // Report only if the format string checks out
- if !errored {
- report = Some(err);
}
- } else {
- span_err!(self.tcx.sess, err_sp, E0274,
- "the #[rustc_on_unimplemented] attribute on \
- trait definition for {} must have a value, \
- eg `#[rustc_on_unimplemented = \"foo\"]`",
- trait_str);
+ }).collect();
+ // Report only if the format string checks out
+ if !errored {
+ report = Some(err);
}
- break;
+ } else {
+ span_err!(self.tcx.sess, err_sp, E0274,
+ "the #[rustc_on_unimplemented] attribute on \
+ trait definition for {} must have a value, \
+ eg `#[rustc_on_unimplemented = \"foo\"]`",
+ trait_str);
}
}
report
}
fn report_similar_impl_candidates(&self,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ impl_candidates: Vec<ty::TraitRef<'tcx>>,
err: &mut DiagnosticBuilder)
{
- let simp = fast_reject::simplify_type(self.tcx,
- trait_ref.skip_binder().self_ty(),
- true);
- let mut impl_candidates = Vec::new();
- let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id());
-
- match simp {
- Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| {
- let imp = self.tcx.impl_trait_ref(def_id).unwrap();
- let imp_simp = fast_reject::simplify_type(self.tcx,
- imp.self_ty(),
- true);
- if let Some(imp_simp) = imp_simp {
- if simp != imp_simp {
- return;
- }
- }
- impl_candidates.push(imp);
- }),
- None => trait_def.for_each_impl(self.tcx, |def_id| {
- impl_candidates.push(
- self.tcx.impl_trait_ref(def_id).unwrap());
- })
- };
-
if impl_candidates.is_empty() {
return;
}
- let end = cmp::min(4, impl_candidates.len());
+ let end = if impl_candidates.len() <= 5 {
+ impl_candidates.len()
+ } else {
+ 4
+ };
err.help(&format!("the following implementations were found:{}{}",
&impl_candidates[0..end].iter().map(|candidate| {
format!("\n {:?}", candidate)
}).collect::<String>(),
- if impl_candidates.len() > 4 {
+ if impl_candidates.len() > 5 {
format!("\nand {} others", impl_candidates.len() - 4)
} else {
"".to_owned()
lint_id)
.emit();
return;
- } else {
- match obligation.predicate {
- ty::Predicate::Trait(ref trait_predicate) => {
- let trait_predicate =
- self.resolve_type_vars_if_possible(trait_predicate);
-
- if self.tcx.sess.has_errors() && trait_predicate.references_error() {
- return;
- } else {
- let trait_ref = trait_predicate.to_poly_trait_ref();
- let (post_message, pre_message) = match self.get_parent_trait_ref(
- &obligation.cause.code)
- {
- Some(t) => {
- (format!(" in `{}`", t), format!("within `{}`, ", t))
- }
- None => (String::new(), String::new()),
- };
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0277,
- "the trait bound `{}` is not satisfied{}",
- trait_ref.to_predicate(),
- post_message);
- err.span_label(span,
- &format!("{}the trait `{}` is not \
- implemented for `{}`",
- pre_message,
- trait_ref,
- trait_ref.self_ty()));
-
- // Try to report a help message
-
- if !trait_ref.has_infer_types() &&
- self.predicate_can_apply(trait_ref) {
- // If a where-clause may be useful, remind the
- // user that they can add it.
- //
- // don't display an on-unimplemented note, as
- // these notes will often be of the form
- // "the type `T` can't be frobnicated"
- // which is somewhat confusing.
- err.help(&format!("consider adding a `where {}` bound",
- trait_ref.to_predicate()));
- } else if let Some(s) = self.on_unimplemented_note(trait_ref,
- obligation) {
- // If it has a custom "#[rustc_on_unimplemented]"
- // error message, let's display it!
- err.note(&s);
- } else {
- // If we can't show anything useful, try to find
- // similar impls.
- let impl_candidates =
- self.find_similar_impl_candidates(trait_ref);
- if impl_candidates.len() > 0 {
- self.report_similar_impl_candidates(trait_ref, &mut err);
- }
- }
- err
- }
- }
+ }
+ match obligation.predicate {
+ ty::Predicate::Trait(ref trait_predicate) => {
+ let trait_predicate =
+ self.resolve_type_vars_if_possible(trait_predicate);
- ty::Predicate::Equate(ref predicate) => {
- let predicate = self.resolve_type_vars_if_possible(predicate);
- let err = self.equality_predicate(&obligation.cause,
- &predicate).err().unwrap();
- struct_span_err!(self.tcx.sess, span, E0278,
- "the requirement `{}` is not satisfied (`{}`)",
- predicate, err)
+ if self.tcx.sess.has_errors() && trait_predicate.references_error() {
+ return;
}
-
- ty::Predicate::RegionOutlives(ref predicate) => {
- let predicate = self.resolve_type_vars_if_possible(predicate);
- let err = self.region_outlives_predicate(&obligation.cause,
- &predicate).err().unwrap();
- struct_span_err!(self.tcx.sess, span, E0279,
- "the requirement `{}` is not satisfied (`{}`)",
- predicate, err)
+ let trait_ref = trait_predicate.to_poly_trait_ref();
+ let (post_message, pre_message) =
+ self.get_parent_trait_ref(&obligation.cause.code)
+ .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
+ .unwrap_or((String::new(), String::new()));
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0277,
+ "the trait bound `{}` is not satisfied{}",
+ trait_ref.to_predicate(),
+ post_message);
+ err.span_label(span,
+ &format!("{}the trait `{}` is not \
+ implemented for `{}`",
+ pre_message,
+ trait_ref,
+ trait_ref.self_ty()));
+
+ // Try to report a help message
+
+ if !trait_ref.has_infer_types() &&
+ self.predicate_can_apply(trait_ref) {
+ // If a where-clause may be useful, remind the
+ // user that they can add it.
+ //
+ // don't display an on-unimplemented note, as
+ // these notes will often be of the form
+ // "the type `T` can't be frobnicated"
+ // which is somewhat confusing.
+ err.help(&format!("consider adding a `where {}` bound",
+ trait_ref.to_predicate()));
+ } else if let Some(s) = self.on_unimplemented_note(trait_ref,
+ obligation) {
+ // If it has a custom "#[rustc_on_unimplemented]"
+ // error message, let's display it!
+ err.note(&s);
+ } else {
+ // If we can't show anything useful, try to find
+ // similar impls.
+ let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+ self.report_similar_impl_candidates(impl_candidates, &mut err);
}
+ err
+ }
- ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
- let predicate =
- self.resolve_type_vars_if_possible(&obligation.predicate);
- struct_span_err!(self.tcx.sess, span, E0280,
- "the requirement `{}` is not satisfied",
- predicate)
- }
+ ty::Predicate::Equate(ref predicate) => {
+ let predicate = self.resolve_type_vars_if_possible(predicate);
+ let err = self.equality_predicate(&obligation.cause,
+ &predicate).err().unwrap();
+ struct_span_err!(self.tcx.sess, span, E0278,
+ "the requirement `{}` is not satisfied (`{}`)",
+ predicate, err)
+ }
- ty::Predicate::ObjectSafe(trait_def_id) => {
- let violations = self.tcx.object_safety_violations(trait_def_id);
- self.tcx.report_object_safety_error(span,
- trait_def_id,
- violations)
- }
+ ty::Predicate::RegionOutlives(ref predicate) => {
+ let predicate = self.resolve_type_vars_if_possible(predicate);
+ let err = self.region_outlives_predicate(&obligation.cause,
+ &predicate).err().unwrap();
+ struct_span_err!(self.tcx.sess, span, E0279,
+ "the requirement `{}` is not satisfied (`{}`)",
+ predicate, err)
+ }
- ty::Predicate::ClosureKind(closure_def_id, kind) => {
- let found_kind = self.closure_kind(closure_def_id).unwrap();
- let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
- let mut err = struct_span_err!(
- self.tcx.sess, closure_span, E0525,
- "expected a closure that implements the `{}` trait, \
- but this closure only implements `{}`",
- kind,
- found_kind);
- err.span_note(
- obligation.cause.span,
- &format!("the requirement to implement \
- `{}` derives from here", kind));
- err.emit();
- return;
- }
+ ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
+ let predicate =
+ self.resolve_type_vars_if_possible(&obligation.predicate);
+ struct_span_err!(self.tcx.sess, span, E0280,
+ "the requirement `{}` is not satisfied",
+ predicate)
+ }
- ty::Predicate::WellFormed(ty) => {
- // WF predicates cannot themselves make
- // errors. They can only block due to
- // ambiguity; otherwise, they always
- // degenerate into other obligations
- // (which may fail).
- span_bug!(span, "WF predicate not satisfied for {:?}", ty);
- }
+ ty::Predicate::ObjectSafe(trait_def_id) => {
+ let violations = self.tcx.object_safety_violations(trait_def_id);
+ self.tcx.report_object_safety_error(span,
+ trait_def_id,
+ violations)
+ }
+
+ ty::Predicate::ClosureKind(closure_def_id, kind) => {
+ let found_kind = self.closure_kind(closure_def_id).unwrap();
+ let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
+ let mut err = struct_span_err!(
+ self.tcx.sess, closure_span, E0525,
+ "expected a closure that implements the `{}` trait, \
+ but this closure only implements `{}`",
+ kind,
+ found_kind);
+ err.span_note(
+ obligation.cause.span,
+ &format!("the requirement to implement \
+ `{}` derives from here", kind));
+ err.emit();
+ return;
+ }
+
+ ty::Predicate::WellFormed(ty) => {
+ // WF predicates cannot themselves make
+ // errors. They can only block due to
+ // ambiguity; otherwise, they always
+ // degenerate into other obligations
+ // (which may fail).
+ span_bug!(span, "WF predicate not satisfied for {:?}", ty);
}
}
}
if !reported_violations.insert(violation.clone()) {
continue;
}
- let buf;
- let note = match violation {
- ObjectSafetyViolation::SizedSelf => {
- "the trait cannot require that `Self : Sized`"
- }
-
- ObjectSafetyViolation::SupertraitSelf => {
- "the trait cannot use `Self` as a type parameter \
- in the supertrait listing"
- }
-
- ObjectSafetyViolation::Method(name,
- MethodViolationCode::StaticMethod) => {
- buf = format!("method `{}` has no receiver", name);
- &buf
- }
-
- ObjectSafetyViolation::Method(name,
- MethodViolationCode::ReferencesSelf) => {
- buf = format!("method `{}` references the `Self` type \
- in its arguments or return type",
- name);
- &buf
- }
-
- ObjectSafetyViolation::Method(name,
- MethodViolationCode::Generic) => {
- buf = format!("method `{}` has generic type parameters", name);
- &buf
- }
- };
- err.note(note);
+ err.note(&violation.error_msg());
}
err
}
let trait_ref = data.to_poly_trait_ref();
let self_ty = trait_ref.self_ty();
if predicate.references_error() {
- } else {
- // Typically, this ambiguity should only happen if
- // there are unresolved type inference variables
- // (otherwise it would suggest a coherence
- // failure). But given #21974 that is not necessarily
- // the case -- we can have multiple where clauses that
- // are only distinguished by a region, which results
- // in an ambiguity even when all types are fully
- // known, since we don't dispatch based on region
- // relationships.
-
- // This is kind of a hack: it frequently happens that some earlier
- // error prevents types from being fully inferred, and then we get
- // a bunch of uninteresting errors saying something like "<generic
- // #0> doesn't implement Sized". It may even be true that we
- // could just skip over all checks where the self-ty is an
- // inference variable, but I was afraid that there might be an
- // inference variable created, registered as an obligation, and
- // then never forced by writeback, and hence by skipping here we'd
- // be ignoring the fact that we don't KNOW the type works
- // out. Though even that would probably be harmless, given that
- // we're only talking about builtin traits, which are known to be
- // inhabited. But in any case I just threw in this check for
- // has_errors() to be sure that compilation isn't happening
- // anyway. In that case, why inundate the user.
- if !self.tcx.sess.has_errors() {
- if
- self.tcx.lang_items.sized_trait()
- .map_or(false, |sized_id| sized_id == trait_ref.def_id())
- {
- self.need_type_info(obligation.cause.span, self_ty);
- } else {
- let mut err = struct_span_err!(self.tcx.sess,
- obligation.cause.span, E0283,
- "type annotations required: \
- cannot resolve `{}`",
- predicate);
- self.note_obligation_cause(&mut err, obligation);
- err.emit();
- }
+ return;
+ }
+ // Typically, this ambiguity should only happen if
+ // there are unresolved type inference variables
+ // (otherwise it would suggest a coherence
+ // failure). But given #21974 that is not necessarily
+ // the case -- we can have multiple where clauses that
+ // are only distinguished by a region, which results
+ // in an ambiguity even when all types are fully
+ // known, since we don't dispatch based on region
+ // relationships.
+
+ // This is kind of a hack: it frequently happens that some earlier
+ // error prevents types from being fully inferred, and then we get
+ // a bunch of uninteresting errors saying something like "<generic
+ // #0> doesn't implement Sized". It may even be true that we
+ // could just skip over all checks where the self-ty is an
+ // inference variable, but I was afraid that there might be an
+ // inference variable created, registered as an obligation, and
+ // then never forced by writeback, and hence by skipping here we'd
+ // be ignoring the fact that we don't KNOW the type works
+ // out. Though even that would probably be harmless, given that
+ // we're only talking about builtin traits, which are known to be
+ // inhabited. But in any case I just threw in this check for
+ // has_errors() to be sure that compilation isn't happening
+ // anyway. In that case, why inundate the user.
+ if !self.tcx.sess.has_errors() {
+ if
+ self.tcx.lang_items.sized_trait()
+ .map_or(false, |sized_id| sized_id == trait_ref.def_id())
+ {
+ self.need_type_info(obligation, self_ty);
+ } else {
+ let mut err = struct_span_err!(self.tcx.sess,
+ obligation.cause.span, E0283,
+ "type annotations required: \
+ cannot resolve `{}`",
+ predicate);
+ self.note_obligation_cause(&mut err, obligation);
+ err.emit();
}
}
}
// Same hacky approach as above to avoid deluging user
// with error messages.
if !ty.references_error() && !self.tcx.sess.has_errors() {
- self.need_type_info(obligation.cause.span, ty);
+ self.need_type_info(obligation, ty);
}
}
})
}
-
- fn need_type_info(&self, span: Span, ty: Ty<'tcx>) {
- let ty = self.resolve_type_vars_if_possible(&ty);
- let name = if let ty::TyInfer(ty::TyVar(ty_vid)) = ty.sty {
+ fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String {
+ if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty {
let ty_vars = self.type_variables.borrow();
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
- *ty_vars.var_origin(ty_vid)
- {
+ *ty_vars.var_origin(ty_vid) {
name.to_string()
} else {
ty.to_string()
}
} else {
ty.to_string()
+ }
+ }
+
+ fn need_type_info(&self, obligation: &PredicateObligation<'tcx>, ty: Ty<'tcx>) {
+ let ty = self.resolve_type_vars_if_possible(&ty);
+ let name = self.extract_type_name(&ty);
+ let ref cause = obligation.cause;
+
+ let mut err = struct_span_err!(self.tcx.sess,
+ cause.span,
+ E0282,
+ "type annotations needed");
+
+ err.span_label(cause.span, &format!("cannot infer type for `{}`", name));
+
+ let mut local_visitor = FindLocalByTypeVisitor {
+ infcx: &self,
+ target_ty: &ty,
+ found_pattern: None,
};
- let mut err = struct_span_err!(self.tcx.sess, span, E0282,
- "unable to infer enough type information about `{}`",
- name);
- err.note("type annotations or generic parameter binding required");
- err.span_label(span, &format!("cannot infer type for `{}`", name));
+ // #40294: cause.body_id can also be a fn declaration.
+ // Currently, if it's anything other than NodeExpr, we just ignore it
+ match self.tcx.hir.find(cause.body_id) {
+ Some(NodeExpr(expr)) => local_visitor.visit_expr(expr),
+ _ => ()
+ }
+
+ if let Some(pattern) = local_visitor.found_pattern {
+ let pattern_span = pattern.span;
+ if let Some(simple_name) = pattern.simple_name() {
+ err.span_label(pattern_span,
+ &format!("consider giving `{}` a type",
+ simple_name));
+ } else {
+ err.span_label(pattern_span, &format!("consider giving a type to pattern"));
+ }
+ }
+
err.emit();
}
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) {
let current_limit = self.tcx.sess.recursion_limit.get();
let suggested_limit = current_limit * 2;
- err.note(&format!(
+ err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit));
}