blob: e50cb2af4b857618553d595e2af612823a978b7d [file] [log] [blame]
// ignore-tidy-filelength :(
use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
use crate::errors::{
AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
};
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::TypeVariableOrigin;
use crate::infer::InferCtxtExt as _;
use crate::infer::{self, InferCtxt};
use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt;
use crate::traits::error_reporting::{ambiguity, ambiguity::CandidateSource::*};
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::specialize::to_pretty_impl_header;
use crate::traits::NormalizeExt;
use crate::traits::{
elaborate, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation,
ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation,
SelectionError, SignatureMismatch, TraitNotObjectSafe,
};
use core::ops::ControlFlow;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::unord::UnordSet;
use rustc_errors::codes::*;
use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{GenericParam, Item, Node};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_macros::extension;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::traits::SignatureMismatchData;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
TypeVisitable, TypeVisitableExt,
};
use rustc_session::config::DumpSolverProofTree;
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::symbol::sym;
use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP};
use std::borrow::Cow;
use std::fmt;
use std::iter;
use super::{
dump_proof_tree, ArgKind, CandidateSimilarity, FindExprBySpan, FindTypeParam,
GetSafeTransmuteErrorAndReason, HasNumericInferVisitor, ImplCandidate, UnsatisfiedConst,
};
pub use rustc_infer::traits::error_reporting::*;
pub enum OverflowCause<'tcx> {
DeeplyNormalize(ty::AliasTy<'tcx>),
TraitSolver(ty::Predicate<'tcx>),
}
pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
tcx: TyCtxt<'tcx>,
err: &mut Diag<'_, G>,
) {
let suggested_limit = match tcx.recursion_limit() {
Limit(0) => Limit(2),
limit => limit * 2,
};
err.help(format!(
"consider increasing the recursion limit by adding a \
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
suggested_limit,
tcx.crate_name(LOCAL_CRATE),
));
}
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn report_fulfillment_errors(
&self,
mut errors: Vec<FulfillmentError<'tcx>>,
) -> ErrorGuaranteed {
self.sub_relations
.borrow_mut()
.add_constraints(self, errors.iter().map(|e| e.obligation.predicate));
#[derive(Debug)]
struct ErrorDescriptor<'tcx> {
predicate: ty::Predicate<'tcx>,
index: Option<usize>, // None if this is an old error
}
let mut error_map: FxIndexMap<_, Vec<_>> = self
.reported_trait_errors
.borrow()
.iter()
.map(|(&span, predicates)| {
(
span,
predicates
.0
.iter()
.map(|&predicate| ErrorDescriptor { predicate, index: None })
.collect(),
)
})
.collect();
// Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
// with more relevant type information and hide redundant E0282 errors.
errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() =>
{
1
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
ty::PredicateKind::Coerce(_) => 2,
_ => 0,
});
for (index, error) in errors.iter().enumerate() {
// We want to ignore desugarings here: spans are equivalent even
// if one is the result of a desugaring and the other is not.
let mut span = error.obligation.cause.span;
let expn_data = span.ctxt().outer_expn_data();
if let ExpnKind::Desugaring(_) = expn_data.kind {
span = expn_data.call_site;
}
error_map.entry(span).or_default().push(ErrorDescriptor {
predicate: error.obligation.predicate,
index: Some(index),
});
}
// We do this in 2 passes because we want to display errors in order, though
// maybe it *is* better to sort errors by span or something.
let mut is_suppressed = vec![false; errors.len()];
for (_, error_set) in error_map.iter() {
// We want to suppress "duplicate" errors with the same span.
for error in error_set {
if let Some(index) = error.index {
// Suppress errors that are either:
// 1) strictly implied by another error.
// 2) implied by an error with a smaller index.
for error2 in error_set {
if error2.index.is_some_and(|index2| is_suppressed[index2]) {
// Avoid errors being suppressed by already-suppressed
// errors, to prevent all errors from being suppressed
// at once.
continue;
}
if self.error_implies(error2.predicate, error.predicate)
&& !(error2.index >= error.index
&& self.error_implies(error.predicate, error2.predicate))
{
info!("skipping {:?} (implied by {:?})", error, error2);
is_suppressed[index] = true;
break;
}
}
}
}
}
let mut reported = None;
for from_expansion in [false, true] {
for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
let guar = self.report_fulfillment_error(error);
reported = Some(guar);
// We want to ignore desugarings here: spans are equivalent even
// if one is the result of a desugaring and the other is not.
let mut span = error.obligation.cause.span;
let expn_data = span.ctxt().outer_expn_data();
if let ExpnKind::Desugaring(_) = expn_data.kind {
span = expn_data.call_site;
}
self.reported_trait_errors
.borrow_mut()
.entry(span)
.or_insert_with(|| (vec![], guar))
.0
.push(error.obligation.predicate);
}
}
}
// It could be that we don't report an error because we have seen an `ErrorReported` from
// another source. We should probably be able to fix most of these, but some are delayed
// bugs that get a proper error after this function.
reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
}
/// 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_error(
&self,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
mutate: impl FnOnce(&mut Diag<'_>),
) -> ! {
let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
mutate(&mut err);
err.emit();
FatalError.raise();
}
fn build_overflow_error(
&self,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
) -> Diag<'tcx> {
fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
where
T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
{
let s = value.to_string();
if s.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 cx: FmtPrinter<'_, '_> =
FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6));
value.print(&mut cx).unwrap();
cx.into_buffer()
} else {
s
}
}
let mut err = match cause {
OverflowCause::DeeplyNormalize(alias_ty) => {
let alias_ty = self.resolve_vars_if_possible(alias_ty);
let kind = alias_ty.opt_kind(self.tcx).map_or("alias", |k| k.descr());
let alias_str = with_short_path(self.tcx, alias_ty);
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow normalizing the {kind} `{alias_str}`",
)
}
OverflowCause::TraitSolver(predicate) => {
let predicate = self.resolve_vars_if_possible(predicate);
match predicate.kind().skip_binder() {
ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
| ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow assigning `{a}` to `{b}`",
)
}
_ => {
let pred_str = with_short_path(self.tcx, predicate);
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow evaluating the requirement `{pred_str}`",
)
}
}
}
};
if suggest_increasing_limit {
suggest_new_overflow_limit(self.tcx, &mut err);
}
err
}
/// 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(
OverflowCause::TraitSolver(predicate),
obligation.cause.span,
suggest_increasing_limit,
|err| {
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
predicate,
obligation.param_env,
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
);
},
);
}
/// Reports that a cycle was detected which led to overflow and halts
/// 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_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
let cycle = self.resolve_vars_if_possible(cycle.to_owned());
assert!(!cycle.is_empty());
debug!(?cycle, "report_overflow_error_cycle");
// The 'deepest' obligation is most likely to have a useful
// cause 'backtrace'
self.report_overflow_obligation(
cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
false,
);
}
fn report_overflow_no_abort(
&self,
obligation: PredicateObligation<'tcx>,
suggest_increasing_limit: bool,
) -> ErrorGuaranteed {
let obligation = self.resolve_vars_if_possible(obligation);
let mut err = self.build_overflow_error(
OverflowCause::TraitSolver(obligation.predicate),
obligation.cause.span,
suggest_increasing_limit,
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit()
}
/// The `root_obligation` parameter should be the `root_obligation` field
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
/// then it should be the same as `obligation`.
fn report_selection_error(
&self,
mut obligation: PredicateObligation<'tcx>,
root_obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>,
) -> ErrorGuaranteed {
let tcx = self.tcx;
if tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default()
== DumpSolverProofTree::OnError
{
dump_proof_tree(root_obligation, self.infcx);
}
let mut span = obligation.cause.span;
let mut err = match *error {
SelectionError::Unimplemented => {
// If this obligation was generated as a result of well-formedness checking, see if we
// 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
.diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc))
{
obligation.cause = cause.clone();
span = obligation.cause.span;
}
}
if let ObligationCauseCode::CompareImplItemObligation {
impl_item_def_id,
trait_item_def_id,
kind: _,
} = *obligation.cause.code()
{
debug!("ObligationCauseCode::CompareImplItemObligation");
return self.report_extra_impl_obligation(
span,
impl_item_def_id,
trait_item_def_id,
&format!("`{}`", obligation.predicate),
)
.emit()
}
// Report a const-param specific error
if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()
{
return self.report_const_param_not_wf(ty, &obligation).emit();
}
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
let trait_predicate = bound_predicate.rebind(trait_predicate);
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
// Let's use the root obligation as the main message, when we care about the
// most general case ("X doesn't implement Pattern<'_>") over the case that
// happened to fail ("char doesn't implement Fn(&mut char)").
//
// We rely on a few heuristics to identify cases where this root
// obligation is more important than the leaf obligation:
let (main_trait_predicate, o) = if let ty::PredicateKind::Clause(
ty::ClauseKind::Trait(root_pred)
) = root_obligation.predicate.kind().skip_binder()
&& !trait_predicate.self_ty().skip_binder().has_escaping_bound_vars()
&& !root_pred.self_ty().has_escaping_bound_vars()
// The type of the leaf predicate is (roughly) the same as the type
// from the root predicate, as a proxy for "we care about the root"
// FIXME: this doesn't account for trivial derefs, but works as a first
// approximation.
&& (
// `T: Trait` && `&&T: OtherTrait`, we want `OtherTrait`
self.can_eq(
obligation.param_env,
trait_predicate.self_ty().skip_binder(),
root_pred.self_ty().peel_refs(),
)
// `&str: Iterator` && `&str: IntoIterator`, we want `IntoIterator`
|| self.can_eq(
obligation.param_env,
trait_predicate.self_ty().skip_binder(),
root_pred.self_ty(),
)
)
// The leaf trait and the root trait are different, so as to avoid
// talking about `&mut T: Trait` and instead remain talking about
// `T: Trait` instead
&& trait_predicate.def_id() != root_pred.def_id()
// The root trait is not `Unsize`, as to avoid talking about it in
// `tests/ui/coercion/coerce-issue-49593-box-never.rs`.
&& Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait()
{
(
self.resolve_vars_if_possible(
root_obligation.predicate.kind().rebind(root_pred),
),
root_obligation,
)
} else {
(trait_predicate, &obligation)
};
let trait_ref = main_trait_predicate.to_poly_trait_ref();
if let Some(guar) = self.emit_specialized_closure_kind_error(
&obligation,
trait_ref,
) {
return guar;
}
// FIXME(effects)
let predicate_is_const = false;
if let Err(guar) = trait_predicate.error_reported()
{
return guar;
}
// Silence redundant errors on binding acccess that are already
// reported on the binding definition (#56607).
if let Err(guar) = self.fn_arg_obligation(&obligation) {
return guar;
}
let mut file = None;
let (post_message, pre_message, type_def) = self
.get_parent_trait_ref(obligation.cause.code())
.map(|(t, s)| {
let t = self.tcx.short_ty_string(t, &mut file);
(
format!(" in `{t}`"),
format!("within `{t}`, "),
s.map(|s| (format!("within this `{t}`"), s)),
)
})
.unwrap_or_default();
let file_note = file.as_ref().map(|file| format!(
"the full trait has been written to '{}'",
file.display(),
));
let mut long_ty_file = None;
let OnUnimplementedNote {
message,
label,
notes,
parent_label,
append_const_msg,
} = self.on_unimplemented_note(trait_ref, o, &mut long_ty_file);
let have_alt_message = message.is_some() || label.is_some();
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
let is_unsize =
Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
let (message, notes, append_const_msg) = if is_try_conversion {
(
Some(format!(
"`?` couldn't convert the error to `{}`",
trait_ref.skip_binder().self_ty(),
)),
vec![
"the question mark operation (`?`) implicitly performs a \
conversion on the error value using the `From` trait"
.to_owned(),
],
Some(AppendConstMessage::Default),
)
} else {
(message, notes, append_const_msg)
};
let err_msg = self.get_standard_error_message(
&main_trait_predicate,
message,
predicate_is_const,
append_const_msg,
post_message,
);
let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id())
== self.tcx.lang_items().transmute_trait()
{
// Recompute the safe transmute reason and use that for the error reporting
match self.get_safe_transmute_error_and_reason(
obligation.clone(),
trait_ref,
span,
) {
GetSafeTransmuteErrorAndReason::Silent => {
return self.dcx().span_delayed_bug(
span, "silent safe transmute error"
);
}
GetSafeTransmuteErrorAndReason::Error {
err_msg,
safe_transmute_explanation,
} => (err_msg, safe_transmute_explanation),
}
} else {
(err_msg, None)
};
let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);
if let Some(long_ty_file) = long_ty_file {
err.note(format!(
"the full name for the type has been written to '{}'",
long_ty_file.display(),
));
err.note("consider using `--verbose` to print the full type name to the console");
}
let mut suggested = false;
if is_try_conversion {
suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err);
}
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
err.span_label(
ret_span,
format!(
"expected `{}` because of this",
trait_ref.skip_binder().self_ty()
),
);
}
if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
self.add_tuple_trait_message(
obligation.cause.code().peel_derives(),
&mut err,
);
}
if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
&& predicate_is_const
{
err.note("`~const Drop` was renamed to `~const Destruct`");
err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
}
let explanation = get_explanation_based_on_obligation(
self.tcx,
&obligation,
trait_ref,
&trait_predicate,
pre_message,
);
self.check_for_binding_assigned_block_without_tail_expression(
&obligation,
&mut err,
trait_predicate,
);
if self.suggest_add_reference_to_arg(
&obligation,
&mut err,
trait_predicate,
have_alt_message,
) {
self.note_obligation_cause(&mut err, &obligation);
return err.emit();
}
file_note.map(|note| err.note(note));
if let Some(s) = label {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
err.span_label(span, s);
if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
// When the self type is a type param We don't need to "the trait
// `std::marker::Sized` is not implemented for `T`" as we will point
// at the type param with a label to suggest constraining it.
err.help(explanation);
}
} else if let Some(custom_explanation) = safe_transmute_explanation {
err.span_label(span, custom_explanation);
} else {
err.span_label(span, explanation);
}
if let ObligationCauseCode::Coercion { source, target } =
*obligation.cause.code().peel_derives()
{
if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
self.suggest_borrowing_for_object_cast(
&mut err,
root_obligation,
source,
target,
);
}
}
let UnsatisfiedConst(unsatisfied_const) = self
.maybe_add_note_for_unsatisfied_const(
&trait_predicate,
&mut err,
span,
);
if let Some((msg, span)) = type_def {
err.span_label(span, msg);
}
for note in notes {
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
err.note(note);
}
if let Some(s) = parent_label {
let body = obligation.cause.body_id;
err.span_label(tcx.def_span(body), s);
}
self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate);
suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate);
suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
suggested = if let &[cand] = &impl_candidates[..] {
let cand = cand.trait_ref;
if let (ty::FnPtr(_), ty::FnDef(..)) =
(cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
{
err.span_suggestion(
span.shrink_to_hi(),
format!(
"the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
cand.print_trait_sugared(),
cand.self_ty(),
),
format!(" as {}", cand.self_ty()),
Applicability::MaybeIncorrect,
);
true
} else {
false
}
} else {
false
} || suggested;
suggested |=
self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
suggested |= self.suggest_semicolon_removal(
&obligation,
&mut err,
span,
trait_predicate,
);
self.note_version_mismatch(&mut err, &trait_ref);
self.suggest_remove_await(&obligation, &mut err);
self.suggest_derive(&obligation, &mut err, trait_predicate);
if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
self.suggest_await_before_try(
&mut err,
&obligation,
trait_predicate,
span,
);
}
if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
return err.emit();
}
if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
return err.emit();
}
if is_unsize {
// If the obligation failed due to a missing implementation of the
// `Unsize` trait, give a pointer to why that might be the case
err.note(
"all implementations of `Unsize` are provided \
automatically by the compiler, see \
<https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> \
for more information",
);
}
let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id());
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
*trait_ref.skip_binder().self_ty().kind()
{
!self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
} else {
false
};
if is_fn_trait && is_target_feature_fn {
err.note(
"`#[target_feature]` functions do not implement the `Fn` traits",
);
}
self.try_to_add_help_message(
&obligation,
trait_ref,
&trait_predicate,
&mut err,
span,
is_fn_trait,
suggested,
unsatisfied_const,
);
// Changing mutability doesn't make a difference to whether we have
// an `Unsize` impl (Fixes ICE in #71036)
if !is_unsize {
self.suggest_change_mut(&obligation, &mut err, trait_predicate);
}
// If this error is due to `!: Trait` not implemented but `(): Trait` is
// implemented, and fallback has occurred, then it could be due to a
// variable that used to fallback to `()` now falling back to `!`. Issue a
// note informing about the change in behaviour.
if trait_predicate.skip_binder().self_ty().is_never()
&& self.fallback_has_occurred
{
let predicate = trait_predicate.map_bound(|trait_pred| {
trait_pred.with_self_ty(self.tcx, tcx.types.unit)
});
let unit_obligation = obligation.with(tcx, predicate);
if self.predicate_may_hold(&unit_obligation) {
err.note(
"this error might have been caused by changes to \
Rust's type-inference algorithm (see issue #48950 \
<https://github.com/rust-lang/rust/issues/48950> \
for more information)",
);
err.help("did you intend to use the type `()` here instead?");
}
}
self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause);
self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref);
// Return early if the trait is Debug or Display and the invocation
// originates within a standard library macro, because the output
// is otherwise overwhelming and unhelpful (see #85844 for an
// example).
let in_std_macro =
match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {
Some(macro_def_id) => {
let crate_name = tcx.crate_name(macro_def_id.krate);
crate_name == sym::std || crate_name == sym::core
}
None => false,
};
if in_std_macro
&& matches!(
self.tcx.get_diagnostic_name(trait_ref.def_id()),
Some(sym::Debug | sym::Display)
)
{
return err.emit();
}
err
}
ty::PredicateKind::Subtype(predicate) => {
// Errors for Subtype predicates show up as
// `FulfillmentErrorCode::SubtypeError`,
// not selection error.
span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
}
ty::PredicateKind::Coerce(predicate) => {
// Errors for Coerce predicates show up as
// `FulfillmentErrorCode::SubtypeError`,
// not selection error.
span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
}
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
| ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => {
span_bug!(
span,
"outlives clauses should not error outside borrowck. obligation: `{:?}`",
obligation
)
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {
span_bug!(
span,
"projection clauses should be implied from elsewhere. obligation: `{:?}`",
obligation
)
}
ty::PredicateKind::ObjectSafe(trait_def_id) => {
let violations = self.tcx.object_safety_violations(trait_def_id);
report_object_safety_error(self.tcx, span, None, trait_def_id, violations)
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
let ty = self.resolve_vars_if_possible(ty);
if self.next_trait_solver() {
// FIXME: we'll need a better message which takes into account
// which bounds actually failed to hold.
self.dcx().struct_span_err(
span,
format!("the type `{ty}` is not well-formed"),
)
} else {
// WF predicates cannot themselves make
// errors. They can only block due to
// ambiguity; otherwise, they always
// degenerate into other obligations
// (which may fail).
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
}
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => {
// Errors for `ConstEvaluatable` predicates show up as
// `SelectionError::ConstEvalFailure`,
// not `Unimplemented`.
span_bug!(
span,
"const-evaluatable requirement gave wrong error: `{:?}`",
obligation
)
}
ty::PredicateKind::ConstEquate(..) => {
// Errors for `ConstEquate` predicates show up as
// `SelectionError::ConstEvalFailure`,
// not `Unimplemented`.
span_bug!(
span,
"const-equate requirement gave wrong error: `{:?}`",
obligation
)
}
ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
ty::PredicateKind::NormalizesTo(..) => span_bug!(
span,
"NormalizesTo predicate should never be the predicate cause of a SelectionError"
),
ty::PredicateKind::AliasRelate(..) => span_bug!(
span,
"AliasRelate predicate should never be the predicate cause of a SelectionError"
),
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
let mut diag = self.dcx().struct_span_err(
span,
format!("the constant `{ct}` is not of type `{ty}`"),
);
self.note_type_err(
&mut diag,
&obligation.cause,
None,
None,
TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())),
false,
false,
);
diag
}
}
}
SignatureMismatch(box SignatureMismatchData {
found_trait_ref,
expected_trait_ref,
terr: terr @ TypeError::CyclicTy(_),
}) => self.report_cyclic_signature_error(
&obligation,
found_trait_ref,
expected_trait_ref,
terr,
),
SignatureMismatch(box SignatureMismatchData {
found_trait_ref,
expected_trait_ref,
terr: _,
}) => {
match self.report_signature_mismatch_error(
&obligation,
span,
found_trait_ref,
expected_trait_ref,
) {
Ok(err) => err,
Err(guar) => return guar,
}
}
SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => return self.report_opaque_type_auto_trait_leakage(
&obligation,
def_id,
),
TraitNotObjectSafe(did) => {
let violations = self.tcx.object_safety_violations(did);
report_object_safety_error(self.tcx, span, None, did, violations)
}
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {
bug!(
"MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`"
)
}
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
match self.report_not_const_evaluatable_error(&obligation, span) {
Ok(err) => err,
Err(guar) => return guar,
}
}
// Already reported in the query.
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) |
// Already reported.
Overflow(OverflowError::Error(guar)) => {
self.set_tainted_by_errors(guar);
return guar
},
Overflow(_) => {
bug!("overflow should be handled before the `report_selection_error` path");
}
};
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit()
}
fn emit_specialized_closure_kind_error(
&self,
obligation: &PredicateObligation<'tcx>,
mut trait_ref: ty::PolyTraitRef<'tcx>,
) -> Option<ErrorGuaranteed> {
// If `AsyncFnKindHelper` is not implemented, that means that the closure kind
// doesn't extend the goal kind. This is worth reporting, but we can only do so
// if we actually know which closure this goal comes from, so look at the cause
// to see if we can extract that information.
if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper()
&& let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind()
&& let Some(expected_kind) =
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
&& !found_kind.extends(expected_kind)
{
if let Some((_, Some(parent))) = obligation.cause.code().parent() {
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
trait_ref = parent.to_poly_trait_ref();
} else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
obligation.cause.code()
&& let Some(typeck_results) = &self.typeck_results
&& let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
*typeck_results.node_type(arg_hir_id).kind()
{
// Otherwise, extract the closure kind from the obligation.
let mut err = self.report_closure_error(
&obligation,
closure_def_id,
found_kind,
expected_kind,
"async ",
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}
}
let self_ty = trait_ref.self_ty().skip_binder();
if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) {
let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
ty::Closure(def_id, args) => {
(def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
}
ty::CoroutineClosure(def_id, args) => (
def_id,
args.as_coroutine_closure()
.coroutine_closure_sig()
.map_bound(|sig| sig.tupled_inputs_ty),
Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
),
_ => return None,
};
let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1));
// Verify that the arguments are compatible. If the signature is
// mismatched, then we have a totally different error to report.
if self.enter_forall(found_args, |found_args| {
self.enter_forall(expected_args, |expected_args| {
!self.can_sub(obligation.param_env, expected_args, found_args)
})
}) {
return None;
}
if let Some(found_kind) = self.closure_kind(self_ty)
&& !found_kind.extends(expected_kind)
{
let mut err = self.report_closure_error(
&obligation,
closure_def_id,
found_kind,
expected_kind,
"",
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}
// If the closure has captures, then perhaps the reason that the trait
// is unimplemented is because async closures don't implement `Fn`/`FnMut`
// if they have captures.
if let Some(by_ref_captures) = by_ref_captures
&& let ty::FnPtr(sig) = by_ref_captures.kind()
&& !sig.skip_binder().output().is_unit()
{
let mut err = self.tcx.dcx().create_err(AsyncClosureNotFn {
span: self.tcx.def_span(closure_def_id),
kind: expected_kind.as_str(),
});
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
return Some(err.emit());
}
}
None
}
fn fn_arg_obligation(
&self,
obligation: &PredicateObligation<'tcx>,
) -> Result<(), ErrorGuaranteed> {
if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
obligation.cause.code()
&& let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id)
&& let arg = arg.peel_borrows()
&& let hir::ExprKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::Local(hir_id), .. },
)) = arg.kind
&& let Node::Pat(pat) = self.tcx.hir_node(*hir_id)
&& let Some((preds, guar)) = self.reported_trait_errors.borrow().get(&pat.span)
&& preds.contains(&obligation.predicate)
{
return Err(*guar);
}
Ok(())
}
/// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,
/// identify thoe method chain sub-expressions that could or could not have been annotated
/// with `?`.
fn try_conversion_context(
&self,
obligation: &PredicateObligation<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
err: &mut Diag<'_>,
) -> bool {
let span = obligation.cause.span;
/// Look for the (direct) sub-expr of `?`, and return it if it's a `.` method call.
struct FindMethodSubexprOfTry {
search_span: Span,
}
impl<'v> Visitor<'v> for FindMethodSubexprOfTry {
type Result = ControlFlow<&'v hir::Expr<'v>>;
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {
if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind
&& ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span)
&& let hir::ExprKind::Call(_, [expr, ..]) = expr.kind
{
ControlFlow::Break(expr)
} else {
hir::intravisit::walk_expr(self, ex)
}
}
}
let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
let body_id = match self.tcx.hir_node(hir_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => body_id,
_ => return false,
};
let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span })
.visit_body(self.tcx.hir().body(*body_id))
else {
return false;
};
let Some(typeck) = &self.typeck_results else {
return false;
};
let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent()
else {
return false;
};
if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
return false;
}
let self_ty = trait_ref.self_ty();
let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type());
let mut prev_ty = self.resolve_vars_if_possible(
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
);
// We always look at the `E` type, because that's the only one affected by `?`. If the
// incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole
// expression, after the `?` has "unwrapped" the `T`.
let get_e_type = |prev_ty: Ty<'tcx>| -> Option<Ty<'tcx>> {
let ty::Adt(def, args) = prev_ty.kind() else {
return None;
};
let Some(arg) = args.get(1) else {
return None;
};
if !self.tcx.is_diagnostic_item(sym::Result, def.did()) {
return None;
}
arg.as_type()
};
let mut suggested = false;
let mut chain = vec![];
// The following logic is simlar to `point_at_chain`, but that's focused on associated types
let mut expr = expr;
while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {
// Point at every method call in the chain with the `Result` type.
// let foo = bar.iter().map(mapper)?;
// ------ -----------
expr = rcvr_expr;
chain.push((span, prev_ty));
let next_ty = self.resolve_vars_if_possible(
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
);
let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| {
let ty::Adt(def, _) = ty.kind() else {
return false;
};
self.tcx.is_diagnostic_item(symbol, def.did())
};
// For each method in the chain, see if this is `Result::map_err` or
// `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect
// trailing `;`.
if let Some(ty) = get_e_type(prev_ty)
&& let Some(found_ty) = found_ty
// Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100%
// accurate check, but we are in the wrong stage to do that and looking for
// `Result::map_err` by checking the Self type and the path segment is enough.
// sym::ok_or_else
&& (
( // Result::map_err
path_segment.ident.name == sym::map_err
&& is_diagnostic_item(sym::Result, next_ty)
) || ( // Option::ok_or_else
path_segment.ident.name == sym::ok_or_else
&& is_diagnostic_item(sym::Option, next_ty)
)
)
// Found `Result<_, ()>?`
&& let ty::Tuple(tys) = found_ty.kind()
&& tys.is_empty()
// The current method call returns `Result<_, ()>`
&& self.can_eq(obligation.param_env, ty, found_ty)
// There's a single argument in the method call and it is a closure
&& args.len() == 1
&& let Some(arg) = args.get(0)
&& let hir::ExprKind::Closure(closure) = arg.kind
// The closure has a block for its body with no tail expression
&& let body = self.tcx.hir().body(closure.body)
&& let hir::ExprKind::Block(block, _) = body.value.kind
&& let None = block.expr
// The last statement is of a type that can be converted to the return error type
&& let [.., stmt] = block.stmts
&& let hir::StmtKind::Semi(expr) = stmt.kind
&& let expr_ty = self.resolve_vars_if_possible(
typeck.expr_ty_adjusted_opt(expr)
.unwrap_or(Ty::new_misc_error(self.tcx)),
)
&& self
.infcx
.type_implements_trait(
self.tcx.get_diagnostic_item(sym::From).unwrap(),
[self_ty, expr_ty],
obligation.param_env,
)
.must_apply_modulo_regions()
{
suggested = true;
err.span_suggestion_short(
stmt.span.with_lo(expr.span.hi()),
"remove this semicolon",
String::new(),
Applicability::MachineApplicable,
);
}
prev_ty = next_ty;
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
&& let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
{
let parent = self.tcx.parent_hir_node(binding.hir_id);
// We've reached the root of the method call chain...
if let hir::Node::LetStmt(local) = parent
&& let Some(binding_expr) = local.init
{
// ...and it is a binding. Get the binding creation and continue the chain.
expr = binding_expr;
}
if let hir::Node::Param(_param) = parent {
// ...and it is a an fn argument.
break;
}
}
}
// `expr` is now the "root" expression of the method call chain, which can be any
// expression kind, like a method call or a path. If this expression is `Result<T, E>` as
// well, then we also point at it.
prev_ty = self.resolve_vars_if_possible(
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
);
chain.push((expr.span, prev_ty));
let mut prev = None;
for (span, err_ty) in chain.into_iter().rev() {
let err_ty = get_e_type(err_ty);
let err_ty = match (err_ty, prev) {
(Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => {
err_ty
}
(Some(err_ty), None) => err_ty,
_ => {
prev = err_ty;
continue;
}
};
if self
.infcx
.type_implements_trait(
self.tcx.get_diagnostic_item(sym::From).unwrap(),
[self_ty, err_ty],
obligation.param_env,
)
.must_apply_modulo_regions()
{
if !suggested {
err.span_label(span, format!("this has type `Result<_, {err_ty}>`"));
}
} else {
err.span_label(
span,
format!(
"this can't be annotated with `?` because it has type `Result<_, {err_ty}>`",
),
);
}
prev = Some(err_ty);
}
suggested
}
fn report_const_param_not_wf(
&self,
ty: Ty<'tcx>,
obligation: &PredicateObligation<'tcx>,
) -> Diag<'tcx> {
let span = obligation.cause.span;
let mut diag = match ty.kind() {
_ if ty.has_param() => {
span_bug!(span, "const param tys cannot mention other generic parameters");
}
ty::Float(_) => {
struct_span_code_err!(
self.dcx(),
span,
E0741,
"`{ty}` is forbidden as the type of a const generic parameter",
)
}
ty::FnPtr(_) => {
struct_span_code_err!(
self.dcx(),
span,
E0741,
"using function pointers as const generic parameters is forbidden",
)
}
ty::RawPtr(_, _) => {
struct_span_code_err!(
self.dcx(),
span,
E0741,
"using raw pointers as const generic parameters is forbidden",
)
}
ty::Adt(def, _) => {
// We should probably see if we're *allowed* to derive `ConstParamTy` on the type...
let mut diag = struct_span_code_err!(
self.dcx(),
span,
E0741,
"`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter",
);
// Only suggest derive if this isn't a derived obligation,
// and the struct is local.
if let Some(span) = self.tcx.hir().span_if_local(def.did())
&& obligation.cause.code().parent().is_none()
{
if ty.is_structural_eq_shallow(self.tcx) {
diag.span_suggestion(
span,
"add `#[derive(ConstParamTy)]` to the struct",
"#[derive(ConstParamTy)]\n",
Applicability::MachineApplicable,
);
} else {
// FIXME(adt_const_params): We should check there's not already an
// overlapping `Eq`/`PartialEq` impl.
diag.span_suggestion(
span,
"add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct",
"#[derive(ConstParamTy, PartialEq, Eq)]\n",
Applicability::MachineApplicable,
);
}
}
diag
}
_ => {
struct_span_code_err!(
self.dcx(),
span,
E0741,
"`{ty}` can't be used as a const parameter type",
)
}
};
let mut code = obligation.cause.code();
let mut pred = obligation.predicate.to_opt_poly_trait_pred();
while let Some((next_code, next_pred)) = code.parent() {
if let Some(pred) = pred {
self.enter_forall(pred, |pred| {
diag.note(format!(
"`{}` must implement `{}`, but it does not",
pred.self_ty(),
pred.print_modifiers_and_trait_path()
));
})
}
code = next_code;
pred = next_pred;
}
diag
}
}
#[extension(pub(super) trait InferCtxtPrivExt<'tcx>)]
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn can_match_trait(
&self,
goal: ty::TraitPredicate<'tcx>,
assumption: ty::PolyTraitPredicate<'tcx>,
) -> bool {
if goal.polarity != assumption.polarity() {
return false;
}
let trait_goal = goal.trait_ref;
let trait_assumption = self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
infer::BoundRegionConversionTime::HigherRankedType,
assumption.to_poly_trait_ref(),
);
self.can_eq(ty::ParamEnv::empty(), trait_goal, trait_assumption)
}
fn can_match_projection(
&self,
goal: ty::ProjectionPredicate<'tcx>,
assumption: ty::PolyProjectionPredicate<'tcx>,
) -> bool {
let assumption = self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
infer::BoundRegionConversionTime::HigherRankedType,
assumption,
);
let param_env = ty::ParamEnv::empty();
self.can_eq(param_env, goal.projection_ty, assumption.projection_ty)
&& self.can_eq(param_env, goal.term, assumption.term)
}
// returns if `cond` not occurring implies that `error` does not occur - i.e., that
// `error` occurring implies that `cond` occurs.
#[instrument(level = "debug", skip(self), ret)]
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
if cond == error {
return true;
}
if let Some(error) = error.to_opt_poly_trait_pred() {
self.enter_forall(error, |error| {
elaborate(self.tcx, std::iter::once(cond))
.filter_map(|implied| implied.to_opt_poly_trait_pred())
.any(|implied| self.can_match_trait(error, implied))
})
} else if let Some(error) = error.to_opt_poly_projection_pred() {
self.enter_forall(error, |error| {
elaborate(self.tcx, std::iter::once(cond))
.filter_map(|implied| implied.to_opt_poly_projection_pred())
.any(|implied| self.can_match_projection(error, implied))
})
} else {
false
}
}
#[instrument(skip(self), level = "debug")]
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
if self.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default()
== DumpSolverProofTree::OnError
{
dump_proof_tree(&error.root_obligation, self.infcx);
}
match error.code {
FulfillmentErrorCode::SelectionError(ref selection_error) => self
.report_selection_error(
error.obligation.clone(),
&error.root_obligation,
selection_error,
),
FulfillmentErrorCode::ProjectionError(ref e) => {
self.report_projection_error(&error.obligation, e)
}
FulfillmentErrorCode::Ambiguity { overflow: None } => {
self.maybe_report_ambiguity(&error.obligation)
}
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
}
FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self
.report_mismatched_types(
&error.obligation.cause,
expected_found.expected,
expected_found.found,
*err,
)
.emit(),
FulfillmentErrorCode::ConstEquateError(ref expected_found, ref err) => {
let mut diag = self.report_mismatched_consts(
&error.obligation.cause,
expected_found.expected,
expected_found.found,
*err,
);
let code = error.obligation.cause.code().peel_derives().peel_match_impls();
if let ObligationCauseCode::BindingObligation(..)
| ObligationCauseCode::ItemObligation(..)
| ObligationCauseCode::ExprBindingObligation(..)
| ObligationCauseCode::ExprItemObligation(..) = code
{
self.note_obligation_cause_code(
error.obligation.cause.body_id,
&mut diag,
error.obligation.predicate,
error.obligation.param_env,
code,
&mut vec![],
&mut Default::default(),
);
}
diag.emit()
}
FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
}
}
#[instrument(level = "debug", skip_all)]
fn report_projection_error(
&self,
obligation: &PredicateObligation<'tcx>,
error: &MismatchedProjectionTypes<'tcx>,
) -> ErrorGuaranteed {
let predicate = self.resolve_vars_if_possible(obligation.predicate);
if let Err(e) = predicate.error_reported() {
return e;
}
self.probe(|_| {
let ocx = ObligationCtxt::new(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();
let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) =
bound_predicate.skip_binder()
{
let data = self.instantiate_binder_with_fresh_vars(
obligation.cause.span,
infer::BoundRegionConversionTime::HigherRankedType,
bound_predicate.rebind(data),
);
let unnormalized_term = match data.term.unpack() {
ty::TermKind::Ty(_) => Ty::new_projection(
self.tcx,
data.projection_ty.def_id,
data.projection_ty.args,
)
.into(),
ty::TermKind::Const(ct) => ty::Const::new_unevaluated(
self.tcx,
ty::UnevaluatedConst {
def: data.projection_ty.def_id,
args: data.projection_ty.args,
},
ct.ty(),
)
.into(),
};
// FIXME(-Znext-solver): For diagnostic purposes, it would be nice
// to deeply normalize this type.
let normalized_term =
ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
debug!(?obligation.cause, ?obligation.param_env);
debug!(?normalized_term, data.ty = ?data.term);
let is_normalized_term_expected = !matches!(
obligation.cause.code().peel_derives(),
ObligationCauseCode::ItemObligation(_)
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ExprItemObligation(..)
| ObligationCauseCode::ExprBindingObligation(..)
| ObligationCauseCode::Coercion { .. }
);
let (expected, actual) = if is_normalized_term_expected {
(normalized_term, data.term)
} else {
(data.term, normalized_term)
};
// constrain inference variables a bit more to nested obligations from normalize so
// we can have more helpful errors.
//
// we intentionally drop errors from normalization here,
// since the normalization is just done to improve the error message.
let _ = ocx.select_where_possible();
if let Err(new_err) =
ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
{
(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_term, expected_term)| {
self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
})
.unwrap_or_else(|| {
let mut cx = FmtPrinter::new_with_limit(
self.tcx,
Namespace::TypeNS,
rustc_session::Limit(10),
);
with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", {
self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
cx.into_buffer()
}))
});
let mut diag = struct_span_code_err!(self.dcx(), obligation.cause.span, E0271, "{msg}");
let secondary_span = (|| {
let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
predicate.kind().skip_binder()
else {
return None;
};
let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_ty.def_id)?;
let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
let mut associated_items = vec![];
self.tcx.for_each_relevant_impl(
self.tcx.trait_of_item(proj.projection_ty.def_id)?,
proj.projection_ty.self_ty(),
|impl_def_id| {
associated_items.extend(
self.tcx
.associated_items(impl_def_id)
.in_definition_order()
.find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident),
);
},
);
let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
return None;
};
match self.tcx.hir().get_if_local(associated_item.def_id) {
Some(
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(_, Some(ty)),
..
})
| hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Type(ty),
..
}),
) => Some((
ty.span,
with_forced_trimmed_paths!(Cow::from(format!(
"type mismatch resolving `{}`",
{
let mut cx = FmtPrinter::new_with_limit(
self.tcx,
Namespace::TypeNS,
rustc_session::Limit(5),
);
self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
cx.into_buffer()
}
))),
)),
_ => None,
}
})();
self.note_type_err(
&mut diag,
&obligation.cause,
secondary_span,
values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
infer::ValuePairs::Terms(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ty,
expected_ty,
))
}),
err,
true,
false,
);
self.note_obligation_cause(&mut diag, obligation);
diag.emit()
})
}
fn maybe_detailed_projection_msg(
&self,
pred: ty::ProjectionPredicate<'tcx>,
normalized_ty: ty::Term<'tcx>,
expected_ty: ty::Term<'tcx>,
) -> Option<String> {
let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
let self_ty = pred.projection_ty.self_ty();
with_forced_trimmed_paths! {
if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
let fn_kind = self_ty.prefix_string(self.tcx);
let item = match self_ty.kind() {
ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
_ => self_ty.to_string(),
};
Some(format!(
"expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \
returns `{normalized_ty}`",
))
} 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
}
}
}
fn fuzzy_match_tys(
&self,
mut a: Ty<'tcx>,
mut b: Ty<'tcx>,
ignoring_lifetimes: bool,
) -> Option<CandidateSimilarity> {
/// returns the fuzzy category of a given type, or None
/// if the type can be equated to any type.
fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
match t.kind() {
ty::Bool => Some(0),
ty::Char => Some(1),
ty::Str => Some(2),
ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => Some(2),
ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4),
ty::Ref(..) | ty::RawPtr(..) => Some(5),
ty::Array(..) | ty::Slice(..) => Some(6),
ty::FnDef(..) | ty::FnPtr(..) => Some(7),
ty::Dynamic(..) => Some(8),
ty::Closure(..) => Some(9),
ty::Tuple(..) => Some(10),
ty::Param(..) => Some(11),
ty::Alias(ty::Projection, ..) => Some(12),
ty::Alias(ty::Inherent, ..) => Some(13),
ty::Alias(ty::Opaque, ..) => Some(14),
ty::Alias(ty::Weak, ..) => Some(15),
ty::Never => Some(16),
ty::Adt(..) => Some(17),
ty::Coroutine(..) => Some(18),
ty::Foreign(..) => Some(19),
ty::CoroutineWitness(..) => Some(20),
ty::CoroutineClosure(..) => Some(21),
ty::Pat(..) => Some(22),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}
let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {
loop {
match t.kind() {
ty::Ref(_, inner, _) | ty::RawPtr(inner, _) => t = *inner,
_ => break t,
}
}
};
if !ignoring_lifetimes {
a = strip_references(a);
b = strip_references(b);
}
let cat_a = type_category(self.tcx, a)?;
let cat_b = type_category(self.tcx, b)?;
if a == b {
Some(CandidateSimilarity::Exact { ignoring_lifetimes })
} else if cat_a == cat_b {
match (a.kind(), b.kind()) {
(ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,
(ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b,
// Matching on references results in a lot of unhelpful
// suggestions, so let's just not do that for now.
//
// We still upgrade successful matches to `ignoring_lifetimes: true`
// to prioritize that impl.
(ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => {
self.fuzzy_match_tys(a, b, true).is_some()
}
_ => true,
}
.then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes })
} else if ignoring_lifetimes {
None
} else {
self.fuzzy_match_tys(a, b, true)
}
}
fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str {
match kind {
hir::ClosureKind::Closure => "a closure",
hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine",
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Block,
)) => "an async block",
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Fn,
)) => "an async function",
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Closure,
))
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
"an async closure"
}
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::AsyncGen,
hir::CoroutineSource::Block,
)) => "an async gen block",
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::AsyncGen,
hir::CoroutineSource::Fn,
)) => "an async gen function",
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::AsyncGen,
hir::CoroutineSource::Closure,
))
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => {
"an async gen closure"
}
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Gen,
hir::CoroutineSource::Block,
)) => "a gen block",
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Gen,
hir::CoroutineSource::Fn,
)) => "a gen function",
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Gen,
hir::CoroutineSource::Closure,
))
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => "a gen closure",
}
}
fn find_similar_impl_candidates(
&self,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Vec<ImplCandidate<'tcx>> {
let mut candidates: Vec<_> = self
.tcx
.all_impls(trait_pred.def_id())
.filter_map(|def_id| {
let imp = self.tcx.impl_trait_header(def_id).unwrap();
if imp.polarity != ty::ImplPolarity::Positive
|| !self.tcx.is_user_visible_dep(def_id.krate)
{
return None;
}
let imp = imp.trait_ref.skip_binder();
self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false).map(
|similarity| ImplCandidate { trait_ref: imp, similarity, impl_def_id: def_id },
)
})
.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 category).
candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
}
candidates
}
fn report_similar_impl_candidates(
&self,
impl_candidates: &[ImplCandidate<'tcx>],
trait_ref: ty::PolyTraitRef<'tcx>,
body_def_id: LocalDefId,
err: &mut Diag<'_>,
other: bool,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
// If we have a single implementation, try to unify it with the trait ref
// that failed. This should uncover a better hint for what *is* implemented.
if let [single] = &impl_candidates {
if self.probe(|_| {
let ocx = ObligationCtxt::new(self);
self.enter_forall(trait_ref, |obligation_trait_ref| {
let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
let impl_trait_ref = ocx.normalize(
&ObligationCause::dummy(),
param_env,
ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args),
);
ocx.register_obligations(
self.tcx
.predicates_of(single.impl_def_id)
.instantiate(self.tcx, impl_args)
.into_iter()
.map(|(clause, _)| {
Obligation::new(
self.tcx,
ObligationCause::dummy(),
param_env,
clause,
)
}),
);
if !ocx.select_where_possible().is_empty() {
return false;
}
let mut terrs = vec![];
for (obligation_arg, impl_arg) in
std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
{
if (obligation_arg, impl_arg).references_error() {
return false;
}
if let Err(terr) =
ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg)
{
terrs.push(terr);
}
if !ocx.select_where_possible().is_empty() {
return false;
}
}
// Literally nothing unified, just give up.
if terrs.len() == impl_trait_ref.args.len() {
return false;
}
let cand = self.resolve_vars_if_possible(impl_trait_ref).fold_with(
&mut BottomUpFolder {
tcx: self.tcx,
ty_op: |ty| ty,
lt_op: |lt| lt,
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
},
);
if cand.references_error() {
return false;
}
err.highlighted_help(vec![
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
StringPart::highlighted("is"),
StringPart::normal(" implemented for `"),
StringPart::highlighted(cand.self_ty().to_string()),
StringPart::normal("`"),
]);
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
let exp_found = self.resolve_vars_if_possible(*exp_found);
err.help(format!(
"for that trait implementation, expected `{}`, found `{}`",
exp_found.expected, exp_found.found
));
}
true
})
}) {
return true;
}
}
let other = if other { "other " } else { "" };
let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diag<'_>| {
candidates.retain(|tr| !tr.references_error());
if candidates.is_empty() {
return false;
}
if let &[cand] = &candidates[..] {
let (desc, mention_castable) =
match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
(ty::FnPtr(_), ty::FnDef(..)) => {
(" implemented for fn pointer `", ", cast using `as`")
}
(ty::FnPtr(_), _) => (" implemented for fn pointer `", ""),
_ => (" implemented for `", ""),
};
err.highlighted_help(vec![
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
StringPart::highlighted("is"),
StringPart::normal(desc),
StringPart::highlighted(cand.self_ty().to_string()),
StringPart::normal("`"),
StringPart::normal(mention_castable),
]);
return true;
}
let trait_ref = TraitRef::identity(self.tcx, candidates[0].def_id);
// Check if the trait is the same in all cases. If so, we'll only show the type.
let mut traits: Vec<_> =
candidates.iter().map(|c| c.print_only_trait_path().to_string()).collect();
traits.sort();
traits.dedup();
// FIXME: this could use a better heuristic, like just checking
// that args[1..] is the same.
let all_traits_equal = traits.len() == 1;
let candidates: Vec<String> = candidates
.into_iter()
.map(|c| {
if all_traits_equal {
format!("\n {}", c.self_ty())
} else {
format!("\n {c}")
}
})
.collect();
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
err.help(format!(
"the following {other}types implement trait `{}`:{}{}",
trait_ref.print_trait_sugared(),
candidates[..end].join(""),
if candidates.len() > 9 {
format!("\nand {} others", candidates.len() - 8)
} else {
String::new()
}
));
true
};
let def_id = trait_ref.def_id();
if impl_candidates.is_empty() {
if self.tcx.trait_is_auto(def_id)
|| self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
|| self.tcx.get_diagnostic_name(def_id).is_some()
{
// Mentioning implementers of `Copy`, `Debug` and friends is not useful.
return false;
}
let mut impl_candidates: Vec<_> = self
.tcx
.all_impls(def_id)
// Ignore automatically derived impls and `!Trait` impls.
.filter_map(|def_id| self.tcx.impl_trait_header(def_id))
.filter_map(|header| {
(header.polarity != ty::ImplPolarity::Negative
|| self.tcx.is_automatically_derived(def_id))
.then(|| header.trait_ref.instantiate_identity())
})
.filter(|trait_ref| {
let self_ty = trait_ref.self_ty();
// Avoid mentioning type parameters.
if let ty::Param(_) = self_ty.kind() {
false
}
// Avoid mentioning types that are private to another crate
else if let ty::Adt(def, _) = self_ty.peel_refs().kind() {
// FIXME(compiler-errors): This could be generalized, both to
// be more granular, and probably look past other `#[fundamental]`
// types, too.
self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx)
} else {
true
}
})
.collect();
impl_candidates.sort_by_key(|tr| tr.to_string());
impl_candidates.dedup();
return report(impl_candidates, err);
}
// Sort impl candidates so that ordering is consistent for UI tests.
// because the ordering of `impl_candidates` may not be deterministic:
// https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
//
// Prefer more similar candidates first, then sort lexicographically
// by their normalized string representation.
let mut impl_candidates: Vec<_> = impl_candidates
.iter()
.cloned()
.map(|mut cand| {
// Fold the consts so that they shows up as, e.g., `10`
// instead of `core::::array::{impl#30}::{constant#0}`.
cand.trait_ref = cand.trait_ref.fold_with(&mut BottomUpFolder {
tcx: self.tcx,
ty_op: |ty| ty,
lt_op: |lt| lt,
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
});
cand
})
.collect();
impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref.to_string()));
let mut impl_candidates: Vec<_> =
impl_candidates.into_iter().map(|cand| cand.trait_ref).collect();
impl_candidates.dedup();
report(impl_candidates, err)
}
fn report_similar_impl_candidates_for_root_obligation(
&self,
obligation: &PredicateObligation<'tcx>,
trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
body_def_id: LocalDefId,
err: &mut Diag<'_>,
) {
// This is *almost* equivalent to
// `obligation.cause.code().peel_derives()`, but it gives us the
// trait predicate for that corresponding root obligation. This
// lets us get a derived obligation from a type parameter, like
// when calling `string.strip_suffix(p)` where `p` is *not* an
// implementer of `Pattern<'_>`.
let mut code = obligation.cause.code();
let mut trait_pred = trait_predicate;
let mut peeled = false;
while let Some((parent_code, parent_trait_pred)) = code.parent() {
code = parent_code;
if let Some(parent_trait_pred) = parent_trait_pred {
trait_pred = parent_trait_pred;
peeled = true;
}
}
let def_id = trait_pred.def_id();
// Mention *all* the `impl`s for the *top most* obligation, the
// user might have meant to use one of them, if any found. We skip
// auto-traits or fundamental traits that might not be exactly what
// the user might expect to be presented with. Instead this is
// useful for less general traits.
if peeled
&& !self.tcx.trait_is_auto(def_id)
&& !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
{
let trait_ref = trait_pred.to_poly_trait_ref();
let impl_candidates = self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
&impl_candidates,
trait_ref,
body_def_id,
err,
true,
obligation.param_env,
);
}
}
/// Gets the parent trait chain start
fn get_parent_trait_ref(
&self,
code: &ObligationCauseCode<'tcx>,
) -> Option<(Ty<'tcx>, Option<Span>)> {
match code {
ObligationCauseCode::BuiltinDerivedObligation(data) => {
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
match self.get_parent_trait_ref(&data.parent_code) {
Some(t) => Some(t),
None => {
let ty = parent_trait_ref.skip_binder().self_ty();
let span = TyCategory::from_ty(self.tcx, ty)
.map(|(_, def_id)| self.tcx.def_span(def_id));
Some((ty, span))
}
}
}
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
self.get_parent_trait_ref(parent_code)
}
_ => None,
}
}
/// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
/// with the same path as `trait_ref`, a help message about
/// a probable version mismatch is added to `err`
fn note_version_mismatch(
&self,
err: &mut Diag<'_>,
trait_ref: &ty::PolyTraitRef<'tcx>,
) -> bool {
let get_trait_impls = |trait_def_id| {
let mut trait_impls = vec![];
self.tcx.for_each_relevant_impl(
trait_def_id,
trait_ref.skip_binder().self_ty(),
|impl_def_id| {
trait_impls.push(impl_def_id);
},
);
trait_impls
};
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
let traits_with_same_path: UnordSet<_> = self
.tcx
.all_traits()
.filter(|trait_def_id| *trait_def_id != trait_ref.def_id())
.map(|trait_def_id| (self.tcx.def_path_str(trait_def_id), trait_def_id))
.filter(|(p, _)| *p == required_trait_path)
.collect();
let traits_with_same_path =
traits_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p);
let mut suggested = false;
for (_, trait_with_same_path) in traits_with_same_path {
let trait_impls = get_trait_impls(trait_with_same_path);
if trait_impls.is_empty() {
continue;
}
let impl_spans: Vec<_> =
trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect();
err.span_help(
impl_spans,
format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
);
let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
let crate_msg =
format!("perhaps two different versions of crate `{trait_crate}` are being used?");
err.note(crate_msg);
suggested = true;
}
suggested
}
/// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
/// `trait_ref`.
///
/// For this to work, `new_self_ty` must have no escaping bound variables.
fn mk_trait_obligation_with_new_self_ty(
&self,
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_ty(self.tcx, new_self_ty));
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
}
#[instrument(skip(self), level = "debug")]
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed {
// Unable to successfully determine, probably means
// insufficient type information, but could mean
// ambiguous impls. The latter *ought* to be a
// coherence violation, so we don't report it here.
let predicate = self.resolve_vars_if_possible(obligation.predicate);
let span = obligation.cause.span;
debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
// Ambiguity errors are often caused as fallout from earlier errors.
// We ignore them if this `infcx` is tainted in some cases below.
let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
let trait_ref = bound_predicate.rebind(data.trait_ref);
debug!(?trait_ref);
if let Err(e) = predicate.error_reported() {
return e;
}
if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) {
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
return guar;
}
// This is kind of a hack: it frequently happens that some earlier
// error prevents types from being fully inferred, and then we get
// a bunch of uninteresting errors saying something like "<generic
// #0> doesn't implement Sized". It may even be true that we
// could just skip over all checks where the self-ty is an
// inference variable, but I was afraid that there might be an
// inference variable created, registered as an obligation, and
// then never forced by writeback, and hence by skipping here we'd
// be ignoring the fact that we don't KNOW the type works
// out. Though even that would probably be harmless, given that
// we're only talking about builtin traits, which are known to be
// inhabited. We used to check for `self.tcx.sess.has_errors()` to
// avoid inundating the user with unnecessary errors, but we now
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
match self.tainted_by_errors() {
None => {
let err = self.emit_inference_failure_err(
obligation.cause.body_id,
span,
trait_ref.self_ty().skip_binder().into(),
ErrorCode::E0282,
false,
);
return err.stash(span, StashKey::MaybeForgetReturn).unwrap();
}
Some(e) => return e,
}
}
// Typically, this ambiguity should only happen if
// there are unresolved type inference variables
// (otherwise it would suggest a coherence
// failure). But given #21974 that is not necessarily
// the case -- we can have multiple where clauses that
// are only distinguished by a region, which results
// in an ambiguity even when all types are fully
// known, since we don't dispatch based on region
// relationships.
// Pick the first generic parameter that still contains inference variables as the one
// we're going to emit an error for. If there are none (see above), fall back to
// a more general error.
let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
let mut err = if let Some(arg) = arg {
self.emit_inference_failure_err(
obligation.cause.body_id,
span,
arg,
ErrorCode::E0283,
true,
)
} else {
struct_span_code_err!(
self.dcx(),
span,
E0283,
"type annotations needed: cannot satisfy `{}`",
predicate,
)
};
let mut ambiguities = ambiguity::compute_applicable_impls_for_diagnostics(
self.infcx,
&obligation.with(self.tcx, trait_ref),
);
let has_non_region_infer =
trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
// It doesn't make sense to talk about applicable impls if there are more than a
// handful of them. If there are a lot of them, but only a few of them have no type
// params, we only show those, as they are more likely to be useful/intended.
if ambiguities.len() > 5 {
let infcx = self.infcx;
if !ambiguities.iter().all(|option| match option {
DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
ParamEnv(_) => true,
}) {
// If not all are blanket impls, we filter blanked impls out.
ambiguities.retain(|option| match option {
DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
ParamEnv(_) => true,
});
}
}
if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
if let Some(e) = self.tainted_by_errors()
&& arg.is_none()
{
// If `arg.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 e;
}
self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
} else {
if let Some(e) = self.tainted_by_errors() {
err.cancel();
return e;
}
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() < 40 {
self.report_similar_impl_candidates(
impl_candidates.as_slice(),
trait_ref,
obligation.cause.body_id,
&mut err,
false,
obligation.param_env,
);
}
}
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());
}
if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
&& let Some(body_id) =
self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
{
let mut expr_finder = FindExprBySpan::new(span, self.tcx);
expr_finder.visit_expr(self.tcx.hir().body(body_id).value);
if let Some(hir::Expr {
kind:
hir::ExprKind::Call(
hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
..
},
_,
)
| hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
..
}) = expr_finder.result
&& let [
..,
trait_path_segment @ hir::PathSegment {
res: Res::Def(DefKind::Trait, trait_id),
..
},
hir::PathSegment {
ident: assoc_item_name,
res: Res::Def(_, item_id),
..
},
] = path.segments
&& data.trait_ref.def_id == *trait_id
&& self.tcx.trait_of_item(*item_id) == Some(*trait_id)
&& let None = self.tainted_by_errors()
{
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
ty::AssocKind::Const => ("refer to the", "constant"),
ty::AssocKind::Fn => ("call", "function"),
// This is already covered by E0223, but this following single match
// arm doesn't hurt here.
ty::AssocKind::Type => ("refer to the", "type"),
};
// Replace the more general E0283 with a more specific error
err.cancel();
err = self.dcx().struct_span_err(
span,
format!(
"cannot {verb} associated {noun} on trait without specifying the \
corresponding `impl` type",
),
);
err.code(E0790);
if let Some(local_def_id) = data.trait_ref.def_id.as_local()
&& let hir::Node::Item(hir::Item {
ident: trait_name,
kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
..
}) = self.tcx.hir_node_by_def_id(local_def_id)
&& let Some(method_ref) = trait_item_refs
.iter()
.find(|item_ref| item_ref.ident == *assoc_item_name)
{
err.span_label(
method_ref.span,
format!("`{trait_name}::{assoc_item_name}` defined here"),
);
}
err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
if 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();
// If there is only one implementation of the trait, suggest using it.
// Otherwise, use a placeholder comment for the implementation.
let (message, self_type) = if non_blanket_impl_count == 1 {
(
"use the fully-qualified path to the only available \
implementation",
format!(
"{}",
self.tcx.type_of(impl_def_id).instantiate_identity()
),
)
} else {
(
"use a fully-qualified path to a specific available \
implementation",
"/* self type */".to_string(),
)
};
let mut suggestions =
vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
if let Some(generic_arg) = trait_path_segment.args {
let between_span =
trait_path_segment.ident.span.between(generic_arg.span_ext);
// get rid of :: between Trait and <type>
// must be '::' between them, otherwise the parser won't accept the code
suggestions.push((between_span, "".to_string()));
suggestions
.push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
} else {
suggestions.push((
trait_path_segment.ident.span.shrink_to_hi(),
">".to_string(),
));
}
err.multipart_suggestion(
message,
suggestions,
Applicability::MaybeIncorrect,
);
}
}
};
err
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
if let Err(e) = arg.error_reported() {
return e;
}
if let Some(e) = self.tainted_by_errors() {
return e;
}
self.emit_inference_failure_err(
obligation.cause.body_id,
span,
arg,
ErrorCode::E0282,
false,
)
}
ty::PredicateKind::Subtype(data) => {
if let Err(e) = data.error_reported() {
return e;
}
if let Some(e) = self.tainted_by_errors() {
return e;
}
let SubtypePredicate { a_is_expected: _, a, b } = data;
// both must be type variables, or the other would've been instantiated
assert!(a.is_ty_var() && b.is_ty_var());
self.emit_inference_failure_err(
obligation.cause.body_id,
span,
a.into(),
ErrorCode::E0282,
true,
)
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
if let Err(e) = predicate.error_reported() {
return e;
}
if let Some(e) = self.tainted_by_errors() {
return e;
}
if let Err(guar) =
self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_ty.def_id))
{
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
return guar;
}
let arg = data
.projection_ty
.args
.iter()
.chain(Some(data.term.into_arg()))
.find(|g| g.has_non_region_infer());
if let Some(arg) = arg {
self.emit_inference_failure_err(
obligation.cause.body_id,
span,
arg,
ErrorCode::E0284,
true,
)
.with_note(format!("cannot satisfy `{predicate}`"))
} else {
// If we can't find a generic parameter, just print a generic error
struct_span_code_err!(
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
}
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
if let Err(e) = predicate.error_reported() {
return e;
}
if let Some(e) = self.tainted_by_errors() {
return e;
}
let arg = data.walk().find(|g| g.is_non_region_infer());
if let Some(arg) = arg {
let err = self.emit_inference_failure_err(
obligation.cause.body_id,
span,
arg,
ErrorCode::E0284,
true,
);
err
} else {
// If we can't find a generic parameter, just print a generic error
struct_span_code_err!(
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
}
_ => {
if let Some(e) = self.tainted_by_errors() {
return e;
}
struct_span_code_err!(
self.dcx(),
span,
E0284,
"type annotations needed: cannot satisfy `{}`",
predicate,
)
.with_span_label(span, format!("cannot satisfy `{predicate}`"))
}
};
self.note_obligation_cause(&mut err, obligation);
err.emit()
}
fn annotate_source_of_ambiguity(
&self,
err: &mut Diag<'_>,
ambiguities: &[ambiguity::CandidateSource],
predicate: ty::Predicate<'tcx>,
) {
let mut spans = vec![];
let mut crates = vec![];
let mut post = vec![];
let mut has_param_env = false;
for ambiguity in ambiguities {
match ambiguity {
ambiguity::CandidateSource::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::CandidateSource::ParamEnv(span) => {
has_param_env = true;
spans.push(*span);
}
}
}
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
crate_names.sort();
crate_names.dedup();
post.sort();
post.dedup();
if self.tainted_by_errors().is_some()
&& (crate_names.len() == 1
&& spans.len() == 0
&& ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
|| predicate.visit_with(&mut HasNumericInferVisitor).is_break())
{
// Avoid complaining about other inference issues for expressions like
// `42 >> 1`, where the types are still `{integer}`, but we want to
// Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
// NOTE(eddyb) this was `.cancel()`, but `err`
// is borrowed, so we can't fully defuse it.
err.downgrade_to_delayed_bug();
return;
}
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 {
format!(": `{}`", post[0])
} else {
String::new()
};
match (spans.len(), crates.len(), crate_names.len()) {
(0, 0, 0) => {
err.note(format!("cannot satisfy `{predicate}`"));
}
(0, _, 1) => {
err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
}
(0, _, _) => {
err.note(format!(
"{} in the following crates: {}{}",
msg,
crate_names.join(", "),
post,
));
}
(_, 0, 0) => {
let span: MultiSpan = spans.into();
err.span_note(span, msg);
}
(_, 1, 1) => {
let span: MultiSpan = spans.into();
err.span_note(span, msg);
err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
}
_ => {
let span: MultiSpan = spans.into();
err.span_note(span, msg);
err.note(format!(
"and more `impl`s found in the following crates: {}{}",
crate_names.join(", "),
post,
));
}
}
}
/// Returns `true` if the trait predicate may apply for *some* assignment
/// to the type parameters.
fn predicate_can_apply(
&self,
param_env: ty::ParamEnv<'tcx>,
pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
struct ParamToVarFolder<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
}
impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ParamToVarFolder<'a, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Param(_) = *ty.kind() {
let infcx = self.infcx;
*self.var_map.entry(ty).or_insert_with(|| {
infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP })
})
} else {
ty.super_fold_with(self)
}
}
}
self.probe(|_| {
let cleaned_pred =
pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
let InferOk { value: cleaned_pred, .. } =
self.infcx.at(&ObligationCause::dummy(), param_env).normalize(cleaned_pred);
let obligation =
Obligation::new(self.tcx, ObligationCause::dummy(), param_env, cleaned_pred);
self.predicate_may_hold(&obligation)
})
}
fn note_obligation_cause(&self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>) {
// First, attempt to add note to this error with an async-await-specific
// message, and fall back to regular note otherwise.
if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
obligation.predicate,
obligation.param_env,
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
);
self.suggest_unsized_bound_if_applicable(err, obligation);
if let Some(span) = err.span.primary_span()
&& let Some(mut diag) =
self.tcx.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion)
&& let Ok(ref mut s1) = err.suggestions
&& let Ok(ref mut s2) = diag.suggestions
{
s1.append(s2);
diag.cancel()
}
}
}
#[instrument(level = "debug", skip_all)]
fn suggest_unsized_bound_if_applicable(
&self,
err: &mut Diag<'_>,
obligation: &PredicateObligation<'tcx>,
) {
let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
obligation.predicate.kind().skip_binder()
else {
return;
};
let (ObligationCauseCode::BindingObligation(item_def_id, span)
| ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) =
*obligation.cause.code().peel_derives()
else {
return;
};
debug!(?pred, ?item_def_id, ?span);
let (Some(node), true) = (
self.tcx.hir().get_if_local(item_def_id),
Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
) else {
return;
};
self.maybe_suggest_unsized_generics(err, span, node);
}
#[instrument(level = "debug", skip_all)]
fn maybe_suggest_unsized_generics(&self, err: &mut Diag<'_>, span: Span, node: Node<'tcx>) {
let Some(generics) = node.generics() else {
return;
};
let sized_trait = self.tcx.lang_items().sized_trait();
debug!(?generics.params);
debug!(?generics.predicates);
let Some(param) = generics.params.iter().find(|param| param.span == span) else {
return;
};
// Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
// `Sized` bound is there intentionally and we don't need to suggest relaxing it.
let explicitly_sized = generics
.bounds_for_param(param.def_id)
.flat_map(|bp| bp.bounds)
.any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
if explicitly_sized {
return;
}
debug!(?param);
match node {
hir::Node::Item(
item @ hir::Item {
// Only suggest indirection for uses of type parameters in ADTs.
kind:
hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
..
},
) => {
if self.maybe_indirection_for_unsized(err, item, param) {
return;
}
}
_ => {}
};
// Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
let (span, separator, open_paren_sp) =
if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
(s, " +", open_paren_sp)
} else {
(param.name.ident().span.shrink_to_hi(), ":", None)
};
let mut suggs = vec![];
let suggestion = format!("{separator} ?Sized");
if let Some(open_paren_sp) = open_paren_sp {
suggs.push((open_paren_sp, "(".to_string()));
suggs.push((span, format!("){suggestion}")));
} else {
suggs.push((span, suggestion));
}
err.multipart_suggestion_verbose(
"consider relaxing the implicit `Sized` restriction",
suggs,
Applicability::MachineApplicable,
);
}
fn maybe_indirection_for_unsized(
&self,
err: &mut Diag<'_>,
item: &Item<'tcx>,
param: &GenericParam<'tcx>,
) -> bool {
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
// is not. Look for invalid "bare" parameter uses, and suggest using indirection.
let mut visitor =
FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
visitor.visit_item(item);
if visitor.invalid_spans.is_empty() {
return false;
}
let mut multispan: MultiSpan = param.span.into();
multispan.push_span_label(
param.span,
format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
);
for sp in visitor.invalid_spans {
multispan.push_span_label(
sp,
format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
);
}
err.span_help(
multispan,
format!(
"you could relax the implicit `Sized` bound on `{T}` if it were \
used through indirection like `&{T}` or `Box<{T}>`",
T = param.name.ident(),
),
);
true
}
fn is_recursive_obligation(
&self,
obligated_types: &mut Vec<Ty<'tcx>>,
cause_code: &ObligationCauseCode<'tcx>,
) -> bool {
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
let self_ty = parent_trait_ref.skip_binder().self_ty();
if obligated_types.iter().any(|ot| ot == &self_ty) {
return true;
}
if let ty::Adt(def, args) = self_ty.kind()
&& let [arg] = &args[..]
&& let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Adt(inner_def, _) = ty.kind()
&& inner_def == def
{
return true;
}
}
false
}
fn get_standard_error_message(
&self,
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
message: Option<String>,
predicate_is_const: bool,
append_const_msg: Option<AppendConstMessage>,
post_message: String,
) -> String {
message
.and_then(|cannot_do_this| {
match (predicate_is_const, append_const_msg) {
// do nothing if predicate is not const
(false, _) => Some(cannot_do_this),
// suggested using default post message
(true, Some(AppendConstMessage::Default)) => {
Some(format!("{cannot_do_this} in const contexts"))
}
// overridden post message
(true, Some(AppendConstMessage::Custom(custom_msg, _))) => {
Some(format!("{cannot_do_this}{custom_msg}"))
}
// fallback to generic message
(true, None) => None,
}
})
.unwrap_or_else(|| {
format!("the trait bound `{trait_predicate}` is not satisfied{post_message}")
})
}
fn get_safe_transmute_error_and_reason(
&self,
obligation: PredicateObligation<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
) -> GetSafeTransmuteErrorAndReason {
use rustc_transmute::Answer;
// Erase regions because layout code doesn't particularly care about regions.
let trait_ref =
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
let src_and_dst = rustc_transmute::Types {
dst: trait_ref.args.type_at(0),
src: trait_ref.args.type_at(1),
};
let Some(assume) = rustc_transmute::Assume::from_const(
self.infcx.tcx,
obligation.param_env,
trait_ref.args.const_at(2),
) else {
self.dcx().span_delayed_bug(
span,
"Unable to construct rustc_transmute::Assume where it was previously possible",
);
return GetSafeTransmuteErrorAndReason::Silent;
};
let dst = trait_ref.args.type_at(0);
let src = trait_ref.args.type_at(1);
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
obligation.cause,
src_and_dst,
assume,
) {
Answer::No(reason) => {
let safe_transmute_explanation = match reason {
rustc_transmute::Reason::SrcIsNotYetSupported => {
format!("analyzing the transmutability of `{src}` is not yet supported")
}
rustc_transmute::Reason::DstIsNotYetSupported => {
format!("analyzing the transmutability of `{dst}` is not yet supported")
}
rustc_transmute::Reason::DstIsBitIncompatible => {
format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`")
}
rustc_transmute::Reason::DstUninhabited => {
format!("`{dst}` is uninhabited")
}
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
format!("`{dst}` may carry safety invariants")
}
rustc_transmute::Reason::DstIsTooBig => {
format!("the size of `{src}` is smaller than the size of `{dst}`")
}
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
let src_size = src.size;
let dst_size = dst.size;
format!(
"the referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)"
)
}
rustc_transmute::Reason::SrcSizeOverflow => {
format!(
"values of the type `{src}` are too big for the current architecture"
)
}
rustc_transmute::Reason::DstSizeOverflow => {
format!(
"values of the type `{dst}` are too big for the current architecture"
)
}
rustc_transmute::Reason::DstHasStricterAlignment {
src_min_align,
dst_min_align,
} => {
format!(
"the minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
)
}
rustc_transmute::Reason::DstIsMoreUnique => {
format!("`{src}` is a shared reference, but `{dst}` is a unique reference")
}
// Already reported by rustc
rustc_transmute::Reason::TypeError => {
return GetSafeTransmuteErrorAndReason::Silent;
}
rustc_transmute::Reason::SrcLayoutUnknown => {
format!("`{src}` has an unknown layout")
}
rustc_transmute::Reason::DstLayoutUnknown => {
format!("`{dst}` has an unknown layout")
}
};
GetSafeTransmuteErrorAndReason::Error {
err_msg,
safe_transmute_explanation: Some(safe_transmute_explanation),
}
}
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
Answer::Yes => span_bug!(
span,
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
),
// Reached when a different obligation (namely `Freeze`) causes the
// transmutability analysis to fail. In this case, silence the
// transmutability error message in favor of that more specific
// error.
Answer::If(_) => {
GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None }
}
}
}
fn add_tuple_trait_message(
&self,
obligation_cause_code: &ObligationCauseCode<'tcx>,
err: &mut Diag<'_>,
) {
match obligation_cause_code {
ObligationCauseCode::RustCall => {
err.primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
}
ObligationCauseCode::BindingObligation(def_id, _)
| ObligationCauseCode::ItemObligation(def_id)
if self.tcx.is_fn_trait(*def_id) =>
{
err.code(E0059);
err.primary_message(format!(
"type parameter to bare `{}` trait must be a tuple",
self.tcx.def_path_str(*def_id)
));
}
_ => {}
}
}
fn try_to_add_help_message(
&self,
obligation: &PredicateObligation<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
err: &mut Diag<'_>,
span: Span,
is_fn_trait: bool,
suggested: bool,
unsatisfied_const: bool,
) {
let body_def_id = obligation.cause.body_id;
let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } =
obligation.cause.code()
{
*rhs_span
} else {
span
};
// Try to report a help message
if is_fn_trait
&& let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
obligation.param_env,
trait_ref.self_ty(),
trait_predicate.skip_binder().polarity,
)
{
self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
} else if !trait_ref.has_non_region_infer()
&& self.predicate_can_apply(obligation.param_env, *trait_predicate)
{
// If a where-clause may be useful, remind the
// user that they can add it.
//
// don't display an on-unimplemented note, as
// these notes will often be of the form
// "the type `T` can't be frobnicated"
// which is somewhat confusing.
self.suggest_restricting_param_bound(
err,
*trait_predicate,
None,
obligation.cause.body_id,
);
} else if trait_ref.def_id().is_local()
&& self.tcx.trait_impls_of(trait_ref.def_id()).is_empty()
&& !self.tcx.trait_is_auto(trait_ref.def_id())
&& !self.tcx.trait_is_alias(trait_ref.def_id())
{
err.span_help(
self.tcx.def_span(trait_ref.def_id()),
crate::fluent_generated::trait_selection_trait_has_no_impls,
);
} else if !suggested && !unsatisfied_const {
// Can't show anything else useful, try to find similar impls.
let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
if !self.report_similar_impl_candidates(
&impl_candidates,
trait_ref,
body_def_id,
err,
true,
obligation.param_env,
) {
self.report_similar_impl_candidates_for_root_obligation(
obligation,
*trait_predicate,
body_def_id,
err,
);
}
self.suggest_convert_to_slice(
err,
obligation,
trait_ref,
impl_candidates.as_slice(),
span,
);
}
}
fn add_help_message_for_fn_trait(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
err: &mut Diag<'_>,
implemented_kind: ty::ClosureKind,
params: ty::Binder<'tcx, Ty<'tcx>>,
) {
// If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
// suggestion to add trait bounds for the type, since we only typically implement
// these traits once.
// Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
// to implement.
let selected_kind = self
.tcx
.fn_trait_kind_from_def_id(trait_ref.def_id())
.expect("expected to map DefId to ClosureKind");
if !implemented_kind.extends(selected_kind) {
err.note(format!(
"`{}` implements `{}`, but it must implement `{}`, which is more general",
trait_ref.skip_binder().self_ty(),
implemented_kind,
selected_kind
));
}
// Note any argument mismatches
let given_ty = params.skip_binder();
let expected_ty = trait_ref.skip_binder().args.type_at(1);
if let ty::Tuple(given) = given_ty.kind()
&& let ty::Tuple(expected) = expected_ty.kind()
{
if expected.len() != given.len() {
// Note number of types that were expected and given
err.note(
format!(
"expected a closure taking {} argument{}, but one taking {} argument{} was given",
given.len(),
pluralize!(given.len()),
expected.len(),
pluralize!(expected.len()),
)
);
} else if !self.same_type_modulo_infer(given_ty, expected_ty) {
// Print type mismatch
let (expected_args, given_args) = self.cmp(given_ty, expected_ty);
err.note_expected_found(
&"a closure with arguments",
expected_args,
&"a closure with arguments",
given_args,
);
}
}
}
fn maybe_add_note_for_unsatisfied_const(
&self,
_trait_predicate: &ty::PolyTraitPredicate<'tcx>,
_err: &mut Diag<'_>,
_span: Span,
) -> UnsatisfiedConst {
let unsatisfied_const = UnsatisfiedConst(false);
// FIXME(effects)
unsatisfied_const
}
fn report_closure_error(
&self,
obligation: &PredicateObligation<'tcx>,
closure_def_id: DefId,
found_kind: ty::ClosureKind,
kind: ty::ClosureKind,
trait_prefix: &'static str,
) -> Diag<'tcx> {
let closure_span = self.tcx.def_span(closure_def_id);
let mut err = ClosureKindMismatch {
closure_span,
expected: kind,
found: found_kind,
cause_span: obligation.cause.span,
trait_prefix,
fn_once_label: None,
fn_mut_label: None,
};
// Additional context information explaining why the closure only implements
// a particular trait.
if let Some(typeck_results) = &self.typeck_results {
let hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id.expect_local());
match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
(ty::ClosureKind::FnOnce, Some((span, place))) => {
err.fn_once_label = Some(ClosureFnOnceLabel {
span: *span,
place: ty::place_to_string_for_capture(self.tcx, place),
})
}
(ty::ClosureKind::FnMut, Some((span, place))) => {
err.fn_mut_label = Some(ClosureFnMutLabel {
span: *span,
place: ty::place_to_string_for_capture(self.tcx, place),
})
}
_ => {}
}
}
self.dcx().create_err(err)
}
fn report_cyclic_signature_error(
&self,
obligation: &PredicateObligation<'tcx>,
found_trait_ref: ty::TraitRef<'tcx>,
expected_trait_ref: ty::TraitRef<'tcx>,
terr: TypeError<'tcx>,
) -> Diag<'tcx> {
let self_ty = found_trait_ref.self_ty();
let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
(
ObligationCause::dummy_with_span(self.tcx.def_span(def_id)),
TypeError::CyclicTy(self_ty),
)
} else {
(obligation.cause.clone(), terr)
};
self.report_and_explain_type_error(
TypeTrace::trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
terr,
)
}
fn report_opaque_type_auto_trait_leakage(
&self,
obligation: &PredicateObligation<'tcx>,
def_id: DefId,
) -> ErrorGuaranteed {
let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
"opaque type".to_string()
}
hir::OpaqueTyOrigin::TyAlias { .. } => {
format!("`{}`", self.tcx.def_path_debug_str(def_id))
}
};
let mut err = self.dcx().struct_span_err(
obligation.cause.span,
format!("cannot check whether the hidden type of {name} satisfies auto traits"),
);
err.note(
"fetching the hidden types of an opaque inside of the defining scope is not supported. \
You can try moving the opaque type and the item that actually registers a hidden type into a new submodule",
);
err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err)
}
// FIXME(@lcnr): This function could be changed to trait `TraitRef` directly
// instead of using a `Binder`.
fn report_signature_mismatch_error(
&self,
obligation: &PredicateObligation<'tcx>,
span: Span,
found_trait_ref: ty::TraitRef<'tcx>,
expected_trait_ref: ty::TraitRef<'tcx>,
) -> Result<Diag<'tcx>, ErrorGuaranteed> {
let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
expected_trait_ref.self_ty().error_reported()?;
let found_trait_ty = found_trait_ref.self_ty();
let found_did = match *found_trait_ty.kind() {
ty::Closure(did, _) | ty::FnDef(did, _) | ty::Coroutine(did, ..) => Some(did),
_ => 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_signature_mismatch.borrow_mut().insert((span, found_span)) {
// We check closures twice, with obligations flowing in different directions,
// but we want to complain about them only once.
return Err(self.dcx().span_delayed_bug(span, "already_reported"));
}
let mut not_tupled = false;
let found = match found_trait_ref.args.type_at(1).kind() {
ty::Tuple(tys) => vec![ArgKind::empty(); tys.len()],
_ => {
not_tupled = true;
vec![ArgKind::empty()]
}
};
let expected_ty = expected_trait_ref.args.type_at(1);
let expected = match expected_ty.kind() {
ty::Tuple(tys) => {
tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
}
_ => {
not_tupled = true;
vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
}
};
// If this is a `Fn` family trait and either the expected or found
// is not tupled, then fall back to just a regular mismatch error.
// This shouldn't be common unless manually implementing one of the
// traits manually, but don't make it more confusing when it does
// happen.
Ok(
if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait()
&& not_tupled
{
self.report_and_explain_type_error(
TypeTrace::trait_refs(
&obligation.cause,
true,
expected_trait_ref,
found_trait_ref,
),
ty::error::TypeError::Mismatch,
)
} else if found.len() == expected.len() {
self.report_closure_arg_mismatch(
span,
found_span,
found_trait_ref,
expected_trait_ref,
obligation.cause.code(),
found_node,
obligation.param_env,
)
} else {
let (closure_span, closure_arg_span, found) = found_did
.and_then(|did| {
let node = self.tcx.hir().get_if_local(did)?;
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, None, found));
self.report_arg_count_mismatch(
span,
closure_span,
expected,
found,
found_trait_ty.is_closure(),
closure_arg_span,
)
},
)
}
fn report_not_const_evaluatable_error(
&self,
obligation: &PredicateObligation<'tcx>,
span: Span,
) -> Result<Diag<'tcx>, ErrorGuaranteed> {
if !self.tcx.features().generic_const_exprs {
let guar = self
.dcx()
.struct_span_err(span, "constant expression depends on a generic parameter")
// FIXME(const_generics): we should suggest to the user how they can resolve this
// issue. However, this is currently not actually possible
// (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
//
// Note that with `feature(generic_const_exprs)` this case should not
// be reachable.
.with_note("this may fail depending on what value the parameter takes")
.emit();
return Err(guar);
}
match obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => match ct.kind() {
ty::ConstKind::Unevaluated(uv) => {
let mut err =
self.dcx().struct_span_err(span, "unconstrained generic constant");
let const_span = self.tcx.def_span(uv.def);
let const_ty = self.tcx.type_of(uv.def).instantiate(self.tcx, uv.args);
let cast = if const_ty != self.tcx.types.usize { " as usize" } else { "" };
let msg = "try adding a `where` bound";
match self.tcx.sess.source_map().span_to_snippet(const_span) {
Ok(snippet) => {
let code = format!("[(); {snippet}{cast}]:");
let def_id = if let ObligationCauseCode::CompareImplItemObligation {
trait_item_def_id,
..
} = obligation.cause.code()
{
trait_item_def_id.as_local()
} else {
Some(obligation.cause.body_id)
};
if let Some(def_id) = def_id
&& let Some(generics) = self.tcx.hir().get_generics(def_id)
{
err.span_suggestion_verbose(
generics.tail_span_for_predicate_suggestion(),
msg,
format!("{} {code}", generics.add_where_or_trailing_comma()),
Applicability::MaybeIncorrect,
);
} else {
err.help(format!("{msg}: where {code}"));
};
}
_ => {
err.help(msg);
}
};
Ok(err)
}
ty::ConstKind::Expr(_) => {
let err = self
.dcx()
.struct_span_err(span, format!("unconstrained generic constant `{ct}`"));
Ok(err)
}
_ => {
bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
}
},
_ => {
span_bug!(
span,
"unexpected non-ConstEvaluatable predicate, this should not be reachable"
)
}
}
}
}