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,
infer::LateBoundRegionConversionTime::HigherRankedType,
bound_predicate.rebind(data),
);
- let normalized_ty = ocx.normalize(
- &obligation.cause,
- obligation.param_env,
- self.tcx.mk_projection(data.projection_ty.def_id, data.projection_ty.substs),
- );
+ 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
);
- 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.
if let Err(new_err) = ocx.eq_exp(
&obligation.cause,
obligation.param_env,
- is_normalized_ty_expected,
- normalized_ty,
- expected_ty,
+ is_normalized_term_expected,
+ normalized_term,
+ data.term,
) {
- (Some((data, is_normalized_ty_expected, normalized_ty, expected_ty)), new_err)
+ (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
} else {
(None, error.err)
}
};
let msg = values
- .and_then(|(predicate, _, normalized_ty, expected_ty)| {
- self.maybe_detailed_projection_msg(
- predicate,
- normalized_ty.into(),
- expected_ty.into(),
- )
+ .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 trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
let self_ty = pred.projection_ty.self_ty();
- 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
+ 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
+ }
}
}
let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
if trait_impls.blanket_impls().is_empty()
- && let Some((impl_ty, _)) = trait_impls.non_blanket_impls().iter().next()
- && let Some(impl_def_id) = impl_ty.def() {
- let message = if trait_impls.non_blanket_impls().len() == 1 {
+ && let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next()
+ {
+ let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count();
+ let message = if non_blanket_impl_count == 1 {
"use the fully-qualified path to the only available implementation".to_string()
} else {
format!(
"use a fully-qualified path to a specific available implementation ({} found)",
- trait_impls.non_blanket_impls().len()
+ non_blanket_impl_count
)
};
let mut suggestions = vec![(
- trait_path_segment.ident.span.shrink_to_lo(),
+ path.span.shrink_to_lo(),
format!("<{} as ", self.tcx.type_of(impl_def_id))
)];
if let Some(generic_arg) = trait_path_segment.args {