} else {
let (closure_span, found) = found_did
.and_then(|did| self.tcx.hir.get_if_local(did))
- .map(|node| self.get_fn_like_arguments(node))
- .unwrap_or((found_span.unwrap(), found));
+ .map(|node| {
+ let (found_span, found) = self.get_fn_like_arguments(node);
+ (Some(found_span), found)
+ }).unwrap_or((found_span, found));
self.report_arg_count_mismatch(span,
closure_span,
fn report_arg_count_mismatch(
&self,
span: Span,
- found_span: Span,
+ found_span: Option<Span>,
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
);
err.span_label(span, format!( "expected {} that takes {}", kind, expected_str));
- err.span_label(found_span, format!("takes {}", found_str));
-
- if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
- if fields.len() == expected_args.len() {
- let sugg = fields.iter()
- .map(|(name, _)| name.to_owned())
- .collect::<Vec<String>>().join(", ");
- err.span_suggestion(found_span,
- "change the closure to take multiple arguments instead of \
- a single tuple",
- format!("|{}|", sugg));
+
+ if let Some(found_span) = found_span {
+ err.span_label(found_span, format!("takes {}", found_str));
+
+ if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
+ if fields.len() == expected_args.len() {
+ let sugg = fields.iter()
+ .map(|(name, _)| name.to_owned())
+ .collect::<Vec<String>>().join(", ");
+ err.span_suggestion(found_span,
+ "change the closure to take multiple arguments instead of \
+ a single tuple",
+ format!("|{}|", sugg));
+ }
}
- }
- if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
- if fields.len() == found_args.len() && is_closure {
- let sugg = format!(
- "|({}){}|",
- found_args.iter()
- .map(|arg| match arg {
- ArgKind::Arg(name, _) => name.to_owned(),
- _ => "_".to_owned(),
- })
- .collect::<Vec<String>>()
- .join(", "),
- // add type annotations if available
- if found_args.iter().any(|arg| match arg {
- ArgKind::Arg(_, ty) => ty != "_",
- _ => false,
- }) {
- format!(": ({})",
- fields.iter()
- .map(|(_, ty)| ty.to_owned())
- .collect::<Vec<String>>()
- .join(", "))
- } else {
- "".to_owned()
- },
- );
- err.span_suggestion(found_span,
- "change the closure to accept a tuple instead of individual \
- arguments",
- sugg);
+ if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
+ if fields.len() == found_args.len() && is_closure {
+ let sugg = format!(
+ "|({}){}|",
+ found_args.iter()
+ .map(|arg| match arg {
+ ArgKind::Arg(name, _) => name.to_owned(),
+ _ => "_".to_owned(),
+ })
+ .collect::<Vec<String>>()
+ .join(", "),
+ // add type annotations if available
+ if found_args.iter().any(|arg| match arg {
+ ArgKind::Arg(_, ty) => ty != "_",
+ _ => false,
+ }) {
+ format!(": ({})",
+ fields.iter()
+ .map(|(_, ty)| ty.to_owned())
+ .collect::<Vec<String>>()
+ .join(", "))
+ } else {
+ "".to_owned()
+ },
+ );
+ err.span_suggestion(found_span,
+ "change the closure to accept a tuple instead of \
+ individual arguments",
+ sugg);
+ }
}
}
{
self.note_obligation_cause_code(err,
&obligation.predicate,
- &obligation.cause.code);
+ &obligation.cause.code,
+ &mut vec![]);
}
fn note_obligation_cause_code<T>(&self,
err: &mut DiagnosticBuilder,
predicate: &T,
- cause_code: &ObligationCauseCode<'tcx>)
+ cause_code: &ObligationCauseCode<'tcx>,
+ obligated_types: &mut Vec<&ty::TyS<'tcx>>)
where T: fmt::Display
{
let tcx = self.tcx;
}
ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
- err.note(&format!("required because it appears within the type `{}`",
- parent_trait_ref.0.self_ty()));
+ let ty = parent_trait_ref.0.self_ty();
+ err.note(&format!("required because it appears within the type `{}`", ty));
+ obligated_types.push(ty);
+
let parent_predicate = parent_trait_ref.to_predicate();
- self.note_obligation_cause_code(err,
- &parent_predicate,
- &data.parent_code);
+ if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
+ self.note_obligation_cause_code(err,
+ &parent_predicate,
+ &data.parent_code,
+ obligated_types);
+ }
}
ObligationCauseCode::ImplDerivedObligation(ref data) => {
let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
parent_trait_ref.0.self_ty()));
let parent_predicate = parent_trait_ref.to_predicate();
self.note_obligation_cause_code(err,
- &parent_predicate,
- &data.parent_code);
+ &parent_predicate,
+ &data.parent_code,
+ obligated_types);
}
ObligationCauseCode::CompareImplMethodObligation { .. } => {
err.note(
err.help(&format!("consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit));
}
+
+ fn is_recursive_obligation(&self,
+ obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+ cause_code: &ObligationCauseCode<'tcx>) -> bool {
+ if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
+ let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
+ for obligated_type in obligated_types {
+ if obligated_type == &parent_trait_ref.0.self_ty() {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
enum ArgKind {