mod ambiguity;
+pub mod method_chain;
pub mod on_unimplemented;
pub mod suggestions;
};
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::sym;
use rustc_span::{ExpnKind, Span, DUMMY_SP};
use std::fmt;
use std::iter;
}
pub trait TypeErrCtxtExt<'tcx> {
+ fn report_overflow_error<T>(
+ &self,
+ predicate: &T,
+ span: Span,
+ suggest_increasing_limit: bool,
+ mutate: impl FnOnce(&mut Diagnostic),
+ ) -> !
+ where
+ T: fmt::Display
+ + TypeFoldable<'tcx>
+ + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
+ <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
+
fn report_fulfillment_errors(
&self,
errors: &[FulfillmentError<'tcx>],
body_id: Option<hir::BodyId>,
) -> ErrorGuaranteed;
- fn report_overflow_error<T>(
+ fn report_overflow_obligation<T>(
&self,
obligation: &Obligation<'tcx, T>,
suggest_increasing_limit: bool,
) -> !
where
- T: fmt::Display
- + TypeFoldable<'tcx>
- + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
- <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
+ T: ToPredicate<'tcx> + Clone;
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
- fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
+ fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
/// The `root_obligation` parameter should be the `root_obligation` field
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
/// occurrences in any case.
fn report_overflow_error<T>(
&self,
- obligation: &Obligation<'tcx, T>,
+ predicate: &T,
+ span: Span,
suggest_increasing_limit: bool,
+ mutate: impl FnOnce(&mut Diagnostic),
) -> !
where
T: fmt::Display
+ Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
<T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
{
- let predicate = self.resolve_vars_if_possible(obligation.predicate.clone());
+ let predicate = self.resolve_vars_if_possible(predicate.clone());
let mut pred_str = predicate.to_string();
+
if pred_str.len() > 50 {
// We don't need to save the type to a file, we will be talking about this type already
// in a separate note when we explain the obligation, so it will be available that way.
}
let mut err = struct_span_err!(
self.tcx.sess,
- obligation.cause.span,
+ span,
E0275,
"overflow evaluating the requirement `{}`",
pred_str,
self.suggest_new_overflow_limit(&mut err);
}
- self.note_obligation_cause_code(
- &mut err,
- &obligation.predicate,
- obligation.param_env,
- obligation.cause.code(),
- &mut vec![],
- &mut Default::default(),
- );
+ mutate(&mut err);
err.emit();
self.tcx.sess.abort_if_errors();
bug!();
}
+ /// Reports that an overflow has occurred and halts compilation. We
+ /// halt compilation unconditionally because it is important that
+ /// overflows never be masked -- they basically represent computations
+ /// whose result could not be truly determined and thus we can't say
+ /// if the program type checks or not -- and they are unusual
+ /// occurrences in any case.
+ fn report_overflow_obligation<T>(
+ &self,
+ obligation: &Obligation<'tcx, T>,
+ suggest_increasing_limit: bool,
+ ) -> !
+ where
+ T: ToPredicate<'tcx> + Clone,
+ {
+ let predicate = obligation.predicate.clone().to_predicate(self.tcx);
+ let predicate = self.resolve_vars_if_possible(predicate);
+ self.report_overflow_error(
+ &predicate,
+ obligation.cause.span,
+ suggest_increasing_limit,
+ |err| {
+ self.note_obligation_cause_code(
+ err,
+ predicate,
+ obligation.param_env,
+ obligation.cause.code(),
+ &mut vec![],
+ &mut Default::default(),
+ );
+ },
+ );
+ }
+
fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
let suggested_limit = match self.tcx.recursion_limit() {
Limit(0) => Limit(2),
}
/// Reports that a cycle was detected which led to overflow and halts
- /// compilation. This is equivalent to `report_overflow_error` except
+ /// compilation. This is equivalent to `report_overflow_obligation` except
/// that we can give a more helpful error message (and, in particular,
/// we do not suggest increasing the overflow limit, which is not
/// going to help).
- fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
+ fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
let cycle = self.resolve_vars_if_possible(cycle.to_owned());
assert!(!cycle.is_empty());
// The 'deepest' obligation is most likely to have a useful
// cause 'backtrace'
- self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false);
+ self.report_overflow_obligation(
+ cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
+ false,
+ );
}
fn report_selection_error(
// can get a better error message by performing HIR-based well-formedness checking.
if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
root_obligation.cause.code().peel_derives()
+ && !obligation.predicate.has_non_region_infer()
{
if let Some(cause) = self
.tcx
trait_ref,
obligation.cause.body_id,
&mut err,
+ true,
) {
// This is *almost* equivalent to
// `obligation.cause.code().peel_derives()`, but it gives us the
trait_ref,
obligation.cause.body_id,
&mut err,
+ true,
);
}
}
_ => None,
};
+ let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
found_trait_ref,
expected_trait_ref,
obligation.cause.code(),
+ found_node,
)
} else {
let (closure_span, closure_arg_span, found) = found_did
trait_ref: ty::PolyTraitRef<'tcx>,
body_id: hir::HirId,
err: &mut Diagnostic,
+ other: bool,
) -> bool;
/// Gets the parent trait chain start
{
self.note_obligation_cause_code(
&mut diag,
- &error.obligation.predicate,
+ error.obligation.predicate,
error.obligation.param_env,
code,
&mut vec![],
diag.emit();
}
FulfillmentErrorCode::CodeCycle(ref cycle) => {
- self.report_overflow_error_cycle(cycle);
+ self.report_overflow_obligation_cycle(cycle);
}
}
}
let normalized_ty = ocx.normalize(
&obligation.cause,
obligation.param_env,
- self.tcx
- .mk_projection(data.projection_ty.item_def_id, data.projection_ty.substs),
+ self.tcx.mk_projection(data.projection_ty.def_id, data.projection_ty.substs),
);
debug!(?obligation.cause, ?obligation.param_env);
| ObligationCauseCode::ObjectCastObligation(..)
| ObligationCauseCode::OpaqueType
);
- let expected_ty = data.term.ty().unwrap();
+ let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error());
// constrain inference variables a bit more to nested obligations from normalize so
// we can have more helpful errors.
let secondary_span = match predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self
.tcx
- .opt_associated_item(proj.projection_ty.item_def_id)
+ .opt_associated_item(proj.projection_ty.def_id)
.and_then(|trait_assoc_item| {
self.tcx
- .trait_of_item(proj.projection_ty.item_def_id)
+ .trait_of_item(proj.projection_ty.def_id)
.map(|id| (trait_assoc_item, id))
})
.and_then(|(trait_assoc_item, id)| {
let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
let self_ty = pred.projection_ty.self_ty();
- if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() {
+ if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
Some(format!(
"expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
fn_kind = self_ty.prefix_string(self.tcx)
ty::Closure(..) => Some(9),
ty::Tuple(..) => Some(10),
ty::Param(..) => Some(11),
- ty::Projection(..) => Some(12),
- ty::Opaque(..) => Some(13),
+ ty::Alias(ty::Projection, ..) => Some(12),
+ ty::Alias(ty::Opaque, ..) => Some(13),
ty::Never => Some(14),
ty::Adt(..) => Some(15),
ty::Generator(..) => Some(16),
trait_ref: ty::PolyTraitRef<'tcx>,
body_id: hir::HirId,
err: &mut Diagnostic,
+ other: bool,
) -> bool {
+ let other = if other { "other " } else { "" };
let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
candidates.sort();
candidates.dedup();
candidates.dedup();
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
err.help(&format!(
- "the following other types implement trait `{}`:{}{}",
+ "the following {other}types implement trait `{}`:{}{}",
trait_ref.print_only_trait_path(),
candidates[..end].join(""),
if len > 9 { format!("\nand {} others", len - 8) } else { String::new() }
trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
// It doesn't make sense to talk about applicable impls if there are more
// than a handful of them.
- if impls.len() > 1 && impls.len() < 5 && has_non_region_infer {
+ if impls.len() > 1 && impls.len() < 10 && has_non_region_infer {
self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
} else {
if self.tainted_by_errors().is_some() {
return;
}
err.note(&format!("cannot satisfy `{}`", predicate));
+ let impl_candidates = self.find_similar_impl_candidates(
+ predicate.to_opt_poly_trait_pred().unwrap(),
+ );
+ if impl_candidates.len() < 10 {
+ self.report_similar_impl_candidates(
+ impl_candidates,
+ trait_ref,
+ body_id.map(|id| id.hir_id).unwrap_or(obligation.cause.body_id),
+ &mut err,
+ false,
+ );
+ }
}
}
_ => {
}
}
- if let ObligationCauseCode::ItemObligation(def_id) | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() {
- self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
- } else if let Ok(snippet) = &self.tcx.sess.source_map().span_to_snippet(span)
- && let ObligationCauseCode::BindingObligation(def_id, _) | ObligationCauseCode::ExprBindingObligation(def_id, ..)
- = *obligation.cause.code()
+ if let ObligationCauseCode::ItemObligation(def_id)
+ | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code()
{
- let generics = self.tcx.generics_of(def_id);
- if generics.params.iter().any(|p| p.name != kw::SelfUpper)
- && !snippet.ends_with('>')
- && !generics.has_impl_trait()
- && !self.tcx.is_fn_trait(def_id)
- {
- // FIXME: To avoid spurious suggestions in functions where type arguments
- // where already supplied, we check the snippet to make sure it doesn't
- // end with a turbofish. Ideally we would have access to a `PathSegment`
- // instead. Otherwise we would produce the following output:
- //
- // error[E0283]: type annotations needed
- // --> $DIR/issue-54954.rs:3:24
- // |
- // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
- // | ^^^^^^^^^^^^^^^^^^^^^^^^^^
- // | |
- // | cannot infer type
- // | help: consider specifying the type argument
- // | in the function call:
- // | `Tt::const_val::<[i8; 123]>::<T>`
- // ...
- // LL | const fn const_val<T: Sized>() -> usize {
- // | - required by this bound in `Tt::const_val`
- // |
- // = note: cannot satisfy `_: Tt`
-
- // Clear any more general suggestions in favor of our specific one
- err.clear_suggestions();
-
- err.span_suggestion_verbose(
- span.shrink_to_hi(),
- &format!(
- "consider specifying the type argument{} in the function call",
- pluralize!(generics.params.len()),
- ),
- format!(
- "::<{}>",
- generics
- .params
- .iter()
- .map(|p| p.name.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- ),
- Applicability::HasPlaceholders,
- );
- }
+ self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
}
if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) =
if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
self.note_obligation_cause_code(
err,
- &obligation.predicate,
+ obligation.predicate,
obligation.param_env,
obligation.cause.code(),
&mut vec![],