mod ambiguity;
+pub mod method_chain;
pub mod on_unimplemented;
pub mod suggestions;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::print::{FmtPrinter, Print};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable,
};
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;
/// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)>;
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>;
/// Reports an error when the number of arguments needed by a
/// trait match doesn't match the number that the expression
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
+ closure_pipe_span: Option<Span>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
/// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
}
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,
/// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Vec<ArgKind>)> {
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)> {
let sm = self.tcx.sess.source_map();
let hir = self.tcx.hir();
Some(match node {
Node::Expr(&hir::Expr {
- kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }),
+ kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }),
..
}) => (
fn_decl_span,
+ fn_arg_span,
hir.body(body)
.params
.iter()
kind: hir::TraitItemKind::Fn(ref sig, _), ..
}) => (
sig.span,
+ None,
sig.decl
.inputs
.iter()
),
Node::Ctor(ref variant_data) => {
let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
- (span, vec![ArgKind::empty(); variant_data.fields().len()])
+ (span, None, vec![ArgKind::empty(); variant_data.fields().len()])
}
_ => panic!("non-FnLike node found: {:?}", node),
})
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
+ closure_arg_span: Option<Span>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let kind = if is_closure { "closure" } else { "function" };
if let Some(found_span) = found_span {
err.span_label(found_span, format!("takes {}", found_str));
- // move |_| { ... }
- // ^^^^^^^^-- def_span
- //
- // move |_| { ... }
- // ^^^^^-- prefix
- let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
- // move |_| { ... }
- // ^^^-- pipe_span
- let pipe_span =
- if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
-
// Suggest to take and ignore the arguments with expected_args_length `_`s if
// found arguments is empty (assume the user just wants to ignore args in this case).
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
if found_args.is_empty() && is_closure {
let underscores = vec!["_"; expected_args.len()].join(", ");
err.span_suggestion_verbose(
- pipe_span,
+ closure_arg_span.unwrap_or(found_span),
&format!(
"consider changing the closure to take and ignore the expected argument{}",
pluralize!(expected_args.len())
/// 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,
);
}
}
&& self.fallback_has_occurred
{
let predicate = trait_predicate.map_bound(|trait_pred| {
- trait_pred.with_self_type(self.tcx, self.tcx.mk_unit())
+ trait_pred.with_self_ty(self.tcx, self.tcx.mk_unit())
});
let unit_obligation = obligation.with(tcx, predicate);
if self.predicate_may_hold(&unit_obligation) {
_ => 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, found) = found_did
+ let (closure_span, closure_arg_span, found) = found_did
.and_then(|did| {
let node = self.tcx.hir().get_if_local(did)?;
- let (found_span, found) = self.get_fn_like_arguments(node)?;
- Some((Some(found_span), found))
+ let (found_span, closure_arg_span, found) =
+ self.get_fn_like_arguments(node)?;
+ Some((Some(found_span), closure_arg_span, found))
})
- .unwrap_or((found_span, found));
+ .unwrap_or((found_span, None, found));
self.report_arg_count_mismatch(
span,
expected,
found,
found_trait_ty.is_closure(),
+ closure_arg_span,
)
}
}
trait_ref: ty::PolyTraitRef<'tcx>,
body_id: hir::HirId,
err: &mut Diagnostic,
+ other: bool,
) -> bool;
/// Gets the parent trait chain start
fn annotate_source_of_ambiguity(
&self,
err: &mut Diagnostic,
- impls: &[DefId],
+ impls: &[ambiguity::Ambiguity],
predicate: ty::Predicate<'tcx>,
);
{
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);
}
}
}
}
self.probe(|_| {
- let mut err = error.err;
- let mut values = None;
+ let ocx = ObligationCtxt::new_in_snapshot(self);
// try to find the mismatched types to report the error with.
//
// this can fail if the problem was higher-ranked, in which
// cause I have no idea for a good error message.
let bound_predicate = predicate.kind();
- if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
+ let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
bound_predicate.skip_binder()
{
- let mut selcx = SelectionContext::new(self);
let data = self.replace_bound_vars_with_fresh_vars(
obligation.cause.span,
infer::LateBoundRegionConversionTime::HigherRankedType,
bound_predicate.rebind(data),
);
- let mut obligations = vec![];
- // FIXME(normalization): Change this to use `At::normalize`
- let normalized_ty = super::normalize_projection_type(
- &mut selcx,
- obligation.param_env,
- data.projection_ty,
- obligation.cause.clone(),
- 0,
- &mut obligations,
- );
+ let unnormalized_term = match data.term.unpack() {
+ ty::TermKind::Ty(_) => self
+ .tcx
+ .mk_projection(data.projection_ty.def_id, data.projection_ty.substs)
+ .into(),
+ ty::TermKind::Const(ct) => self
+ .tcx
+ .mk_const(
+ ty::UnevaluatedConst {
+ def: ty::WithOptConstParam::unknown(data.projection_ty.def_id),
+ substs: data.projection_ty.substs,
+ },
+ ct.ty(),
+ )
+ .into(),
+ };
+ let normalized_term =
+ ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
debug!(?obligation.cause, ?obligation.param_env);
- debug!(?normalized_ty, data.ty = ?data.term);
+ debug!(?normalized_term, data.ty = ?data.term);
- let is_normalized_ty_expected = !matches!(
+ let is_normalized_term_expected = !matches!(
obligation.cause.code().peel_derives(),
ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ObjectCastObligation(..)
| ObligationCauseCode::OpaqueType
);
- if let Err(new_err) = self.at(&obligation.cause, obligation.param_env).eq_exp(
- is_normalized_ty_expected,
- normalized_ty,
+
+ // constrain inference variables a bit more to nested obligations from normalize so
+ // we can have more helpful errors.
+ ocx.select_where_possible();
+
+ if let Err(new_err) = ocx.eq_exp(
+ &obligation.cause,
+ obligation.param_env,
+ is_normalized_term_expected,
+ normalized_term,
data.term,
) {
- values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
- err = new_err;
+ (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
+ } else {
+ (None, error.err)
}
- }
+ } else {
+ (None, error.err)
+ };
let msg = values
- .and_then(|(predicate, _, normalized_ty, expected_ty)| {
- self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
+ .and_then(|(predicate, _, normalized_term, expected_term)| {
+ self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
})
.unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
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)| {
&mut diag,
&obligation.cause,
secondary_span,
- values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
+ values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
infer::ValuePairs::Terms(ExpectedFound::new(
is_normalized_ty_expected,
- normalized_ty,
- term,
+ normalized_ty.into(),
+ expected_ty.into(),
))
}),
err,
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() {
- 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)
- ))
- } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
- Some(format!(
- "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
- ))
- } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
- Some(format!(
- "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
- ))
- } else {
- None
+ with_forced_trimmed_paths! {
+ 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)
+ ))
+ } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
+ Some(format!(
+ "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
+ resolves to `{normalized_ty}`"
+ ))
+ } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
+ Some(format!(
+ "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
+ yields `{normalized_ty}`"
+ ))
+ } else {
+ None
+ }
}
}
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),
&self,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Vec<ImplCandidate<'tcx>> {
- self.tcx
+ let mut candidates: Vec<_> = self
+ .tcx
.all_impls(trait_pred.def_id())
.filter_map(|def_id| {
if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
.map(|similarity| ImplCandidate { trait_ref: imp, similarity })
})
- .collect()
+ .collect();
+ if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
+ // If any of the candidates is a perfect match, we don't want to show all of them.
+ // This is particularly relevant for the case of numeric types (as they all have the
+ // same cathegory).
+ candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
+ }
+ candidates
}
fn report_similar_impl_candidates(
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() }
param_env: ty::ParamEnv<'tcx>,
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
) -> PredicateObligation<'tcx> {
- let trait_pred = trait_ref_and_ty
- .map_bound(|(tr, new_self_ty)| tr.with_self_type(self.tcx, new_self_ty));
+ let trait_pred =
+ trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty));
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
}
let mut selcx = SelectionContext::new(&self);
match selcx.select_from_obligation(&obligation) {
Ok(None) => {
- let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
+ let ambiguities =
+ ambiguity::recompute_applicable_impls(self.infcx, &obligation);
let has_non_region_infer =
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 {
- self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
+ if self.tainted_by_errors().is_some() && subst.is_none() {
+ // If `subst.is_none()`, then this is probably two param-env
+ // candidates or impl candidates that are equal modulo lifetimes.
+ // Therefore, if we've already emitted an error, just skip this
+ // one, since it's not particularly actionable.
+ err.cancel();
+ return;
+ }
+ self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
} else {
if self.tainted_by_errors().is_some() {
err.cancel();
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(_))) =
fn annotate_source_of_ambiguity(
&self,
err: &mut Diagnostic,
- impls: &[DefId],
+ ambiguities: &[ambiguity::Ambiguity],
predicate: ty::Predicate<'tcx>,
) {
let mut spans = vec![];
let mut crates = vec![];
let mut post = vec![];
- for def_id in impls {
- match self.tcx.span_of_impl(*def_id) {
- Ok(span) => spans.push(span),
- Err(name) => {
- crates.push(name);
- if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
- post.push(header);
+ let mut has_param_env = false;
+ for ambiguity in ambiguities {
+ match ambiguity {
+ ambiguity::Ambiguity::DefId(impl_def_id) => {
+ match self.tcx.span_of_impl(*impl_def_id) {
+ Ok(span) => spans.push(span),
+ Err(name) => {
+ crates.push(name);
+ if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
+ post.push(header);
+ }
+ }
}
}
+ ambiguity::Ambiguity::ParamEnv(span) => {
+ has_param_env = true;
+ spans.push(*span);
+ }
}
}
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
return;
}
- let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+ let msg = format!(
+ "multiple `impl`s{} satisfying `{}` found",
+ if has_param_env { " or `where` clauses" } else { "" },
+ predicate
+ );
let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
} else if post.len() == 1 {
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![],