use crate::ty::SubtypePredicate;
use crate::util::nodemap::{FxHashMap, FxHashSet};
-use errors::{Applicability, DiagnosticBuilder, pluralize};
+use errors::{Applicability, DiagnosticBuilder, pluralize, Style};
use std::fmt;
use syntax::ast;
use syntax::symbol::{sym, kw};
use syntax_pos::{DUMMY_SP, Span, ExpnKind, MultiSpan};
+use rustc_error_codes::*;
+
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn report_fulfillment_errors(
&self,
let hir = &self.tcx.hir();
let node = hir.find(hir_id)?;
if let hir::Node::Item(
- hir::Item{kind: hir::ItemKind::Fn(_ ,fn_header ,_ , body_id), .. }) = &node {
+ hir::Item{kind: hir::ItemKind::Fn(sig, _, body_id), .. }) = &node {
self.describe_generator(*body_id).or_else(||
- Some(if let hir::FnHeader{ asyncness: hir::IsAsync::Async, .. } = fn_header {
+ Some(if let hir::FnHeader{ asyncness: hir::IsAsync::Async, .. } = sig.header {
"an async function"
} else {
"a function"
}
match obligation.predicate {
ty::Predicate::Trait(ref trait_predicate) => {
- let trait_predicate =
- self.resolve_vars_if_possible(trait_predicate);
+ let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
if self.tcx.sess.has_errors() && trait_predicate.references_error() {
return;
}
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)))
+ let (
+ post_message,
+ pre_message,
+ ) = self.get_parent_trait_ref(&obligation.cause.code)
+ .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
.unwrap_or_default();
- let OnUnimplementedNote { message, label, note }
- = self.on_unimplemented_note(trait_ref, obligation);
+ let OnUnimplementedNote {
+ message,
+ label,
+ note,
+ } = self.on_unimplemented_note(trait_ref, obligation);
let have_alt_message = message.is_some() || label.is_some();
let is_try = self.tcx.sess.source_map().span_to_snippet(span)
.map(|s| &s == "?")
)
};
+ if self.suggest_add_reference_to_arg(
+ &obligation,
+ &mut err,
+ &trait_ref,
+ points_at_arg,
+ have_alt_message,
+ ) {
+ self.note_obligation_cause(&mut err, obligation);
+ err.emit();
+ return;
+ }
if let Some(ref s) = label {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
}
hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(_, _, generics, _), ..
+ kind: hir::ItemKind::Fn(_, generics, _), ..
}) |
hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::ItemKind::Impl(_, _, _, generics, ..), span, ..
}) |
hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(_, _, generics, _), span, ..
+ kind: hir::ItemKind::Fn(_, generics, _), span, ..
}) |
hir::Node::Item(hir::Item {
kind: hir::ItemKind::TyAlias(_, generics), span, ..
}
}
+ fn suggest_add_reference_to_arg(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut DiagnosticBuilder<'tcx>,
+ trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
+ points_at_arg: bool,
+ has_custom_message: bool,
+ ) -> bool {
+ if !points_at_arg {
+ return false;
+ }
+
+ let span = obligation.cause.span;
+ let param_env = obligation.param_env;
+ let trait_ref = trait_ref.skip_binder();
+
+ if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code {
+ // Try to apply the original trait binding obligation by borrowing.
+ let self_ty = trait_ref.self_ty();
+ let found = self_ty.to_string();
+ let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty);
+ let substs = self.tcx.mk_substs_trait(new_self_ty, &[]);
+ let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs);
+ let new_obligation = Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ new_trait_ref.to_predicate(),
+ );
+ if self.predicate_must_hold_modulo_regions(&new_obligation) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ // We have a very specific type of error, where just borrowing this argument
+ // might solve the problem. In cases like this, the important part is the
+ // original type obligation, not the last one that failed, which is arbitrary.
+ // Because of this, we modify the error to refer to the original obligation and
+ // return early in the caller.
+ let msg = format!(
+ "the trait bound `{}: {}` is not satisfied",
+ found,
+ obligation.parent_trait_ref.skip_binder(),
+ );
+ if has_custom_message {
+ err.note(&msg);
+ } else {
+ err.message = vec![(msg, Style::NoStyle)];
+ }
+ if snippet.starts_with('&') {
+ // This is already a literal borrow and the obligation is failing
+ // somewhere else in the obligation chain. Do not suggest non-sense.
+ return false;
+ }
+ err.span_label(span, &format!(
+ "expected an implementor of trait `{}`",
+ obligation.parent_trait_ref.skip_binder(),
+ ));
+ err.span_suggestion(
+ span,
+ "consider borrowing here",
+ format!("&{}", snippet),
+ Applicability::MaybeIncorrect,
+ );
+ return true;
+ }
+ }
+ }
+ false
+ }
+
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
/// suggest removing these references until we reach a type that implements the trait.
fn suggest_remove_reference(
if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind {
let trait_type = match mutability {
- hir::Mutability::MutMutable => self.tcx.mk_imm_ref(region, t_type),
- hir::Mutability::MutImmutable => self.tcx.mk_mut_ref(region, t_type),
+ hir::Mutability::Mutable => self.tcx.mk_imm_ref(region, t_type),
+ hir::Mutability::Immutable => self.tcx.mk_mut_ref(region, t_type),
};
let substs = self.tcx.mk_substs_trait(&trait_type, &[]);
let sp = self.tcx.sess.source_map()
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
if points_at_arg &&
- mutability == hir::Mutability::MutImmutable &&
+ mutability == hir::Mutability::Immutable &&
refs_number > 0
{
err.span_suggestion(
let parent_node = hir.get_parent_node(obligation.cause.body_id);
let node = hir.find(parent_node);
if let Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(decl, _, _, body_id),
+ kind: hir::ItemKind::Fn(sig, _, body_id),
..
})) = node {
let body = hir.body(*body_id);
if let hir::ExprKind::Block(blk, _) = &body.value.kind {
- if decl.output.span().overlaps(span) && blk.expr.is_none() &&
+ if sig.decl.output.span().overlaps(span) && blk.expr.is_none() &&
"()" == &trait_ref.self_ty().to_string()
{
// FIXME(estebank): When encountering a method with a trait
}
Node::Item(&hir::Item {
span,
- kind: hir::ItemKind::Fn(ref decl, ..),
+ kind: hir::ItemKind::Fn(ref sig, ..),
..
}) |
Node::ImplItem(&hir::ImplItem {
span,
- kind: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _),
+ kind: hir::ImplItemKind::Method(ref sig, _),
..
}) |
Node::TraitItem(&hir::TraitItem {
span,
- kind: hir::TraitItemKind::Method(hir::MethodSig { ref decl, .. }, _),
+ kind: hir::TraitItemKind::Method(ref sig, _),
..
}) => {
- (self.tcx.sess.source_map().def_span(span), decl.inputs.iter()
+ (self.tcx.sess.source_map().def_span(span), sig.decl.inputs.iter()
.map(|arg| match arg.clone().kind {
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
Some(arg.span),
.and_then(|parent_did| self.tcx.hir().get_if_local(parent_did));
debug!("note_obligation_cause_for_async_await: parent_node={:?}", parent_node);
if let Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(_, header, _, _),
+ kind: hir::ItemKind::Fn(sig, _, _),
..
})) = parent_node {
- debug!("note_obligation_cause_for_async_await: header={:?}", header);
- if header.asyncness != hir::IsAsync::Async {
+ debug!("note_obligation_cause_for_async_await: header={:?}", sig.header);
+ if sig.header.asyncness != hir::IsAsync::Async {
return false;
}
}
err.note(&format!("required by cast to type `{}`",
self.ty_to_string(target)));
}
- ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expression) => {
+ ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => {
err.note("the `Copy` trait is required because the \
repeated element will be copied");
- if suggest_const_in_array_repeat_expression {
+ if suggest_const_in_array_repeat_expressions {
err.note("this array initializer can be evaluated at compile-time, for more \
information, see issue \
https://github.com/rust-lang/rust/issues/49147");
if tcx.sess.opts.unstable_features.is_nightly_build() {
- err.help("add `#![feature(const_in_array_repeat_expression)]` to the \
+ err.help("add `#![feature(const_in_array_repeat_expressions)]` to the \
crate attributes to enable");
}
}
);
}
}
- ObligationCauseCode::AssocTypeBound(impl_span, orig) => {
- err.span_label(orig, "associated type defined here");
- if let Some(sp) = impl_span {
+ ObligationCauseCode::AssocTypeBound(ref data) => {
+ err.span_label(data.original, "associated type defined here");
+ if let Some(sp) = data.impl_span {
err.span_label(sp, "in this `impl` item");
}
+ for sp in &data.bounds {
+ err.span_label(*sp, "restricted in this bound");
+ }
}
}
}