summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/error_reporting
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_trait_selection/src/traits/error_reporting
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/error_reporting')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs102
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs1382
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs545
5 files changed, 1048 insertions, 1017 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
index 0475f24d8..7ab652761 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
@@ -87,7 +87,7 @@ pub fn recompute_applicable_impls<'tcx>(
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
{
- if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) {
+ if kind.rebind(trait_pred.trait_ref) == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) {
ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id())))
} else {
ambiguities.push(Ambiguity::ParamEnv(span))
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
deleted file mode 100644
index 7e1dba4ed..000000000
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-use crate::infer::InferCtxt;
-
-use rustc_infer::infer::ObligationEmittingRelation;
-use rustc_infer::traits::PredicateObligations;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-
-pub struct CollectAllMismatches<'a, 'tcx> {
- pub infcx: &'a InferCtxt<'tcx>,
- pub param_env: ty::ParamEnv<'tcx>,
- pub errors: Vec<TypeError<'tcx>>,
-}
-
-impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
- fn tag(&self) -> &'static str {
- "CollectAllMismatches"
- }
-
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.param_env
- }
-
- fn a_is_expected(&self) -> bool {
- true
- }
-
- fn relate_with_variance<T: Relate<'tcx>>(
- &mut self,
- _: ty::Variance,
- _: ty::VarianceDiagInfo<'tcx>,
- a: T,
- b: T,
- ) -> RelateResult<'tcx, T> {
- self.relate(a, b)
- }
-
- fn regions(
- &mut self,
- a: ty::Region<'tcx>,
- _b: ty::Region<'tcx>,
- ) -> RelateResult<'tcx, ty::Region<'tcx>> {
- Ok(a)
- }
-
- fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- self.infcx.probe(|_| {
- if a.is_ty_var() || b.is_ty_var() {
- Ok(a)
- } else {
- self.infcx.super_combine_tys(self, a, b).or_else(|e| {
- self.errors.push(e);
- Ok(a)
- })
- }
- })
- }
-
- fn consts(
- &mut self,
- a: ty::Const<'tcx>,
- b: ty::Const<'tcx>,
- ) -> RelateResult<'tcx, ty::Const<'tcx>> {
- self.infcx.probe(|_| {
- if a.is_ct_infer() || b.is_ct_infer() {
- Ok(a)
- } else {
- relate::super_relate_consts(self, a, b) // could do something similar here for constants!
- }
- })
- }
-
- fn binders<T: Relate<'tcx>>(
- &mut self,
- a: ty::Binder<'tcx, T>,
- b: ty::Binder<'tcx, T>,
- ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> {
- Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
- }
-}
-
-impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
- fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
- // FIXME(deferred_projection_equality): We really should get rid of this relation.
- ty::AliasRelationDirection::Equate
- }
-
- fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
- // FIXME(deferred_projection_equality)
- }
-
- fn register_predicates(
- &mut self,
- _obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>,
- ) {
- // FIXME(deferred_projection_equality)
- }
-}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 1b741b730..a10ececbb 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1,5 +1,4 @@
mod ambiguity;
-pub mod method_chain;
pub mod on_unimplemented;
pub mod suggestions;
@@ -15,8 +14,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::QueryNormalizeExt as _;
use crate::traits::specialize::to_pretty_impl_header;
use crate::traits::NormalizeExt;
-use on_unimplemented::OnUnimplementedNote;
-use on_unimplemented::TypeErrCtxtExt as _;
+use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -30,9 +28,9 @@ use rustc_hir::{GenericParam, Item, Node};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_middle::traits::select::OverflowError;
+use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fast_reject::TreatProjections;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
@@ -273,7 +271,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
let underscores = vec!["_"; expected_args.len()].join(", ");
err.span_suggestion_verbose(
closure_arg_span.unwrap_or(found_span),
- &format!(
+ format!(
"consider changing the closure to take and ignore the expected argument{}",
pluralize!(expected_args.len())
),
@@ -360,7 +358,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
span: DUMMY_SP,
kind: TypeVariableOriginKind::MiscVariable,
});
- let trait_ref = self.tcx.mk_trait_ref(trait_def_id, [ty.skip_binder(), var]);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
let obligation = Obligation::new(
self.tcx,
ObligationCause::dummy(),
@@ -439,7 +437,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// 1) strictly implied by another error.
// 2) implied by an error with a smaller index.
for error2 in error_set {
- if error2.index.map_or(false, |index2| is_suppressed[index2]) {
+ 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.
@@ -467,7 +465,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fullfillment errors")
+ self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors")
}
/// Reports that an overflow has occurred and halts compilation. We
@@ -561,6 +559,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
suggest_increasing_limit,
|err| {
self.note_obligation_cause_code(
+ obligation.cause.body_id,
err,
predicate,
obligation.param_env,
@@ -577,7 +576,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Limit(0) => Limit(2),
limit => limit * 2,
};
- err.help(&format!(
+ err.help(format!(
"consider increasing the recursion limit by adding a \
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
suggested_limit,
@@ -707,42 +706,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
conversion on the error value using the `From` trait"
.to_owned(),
),
- Some(None),
+ Some(AppendConstMessage::Default),
)
} else {
(message, note, append_const_msg)
};
- let err_msg = 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(None)) => {
- Some(format!("{cannot_do_this} in const contexts"))
- }
- // overridden post message
- (true, Some(Some(post_message))) => {
- Some(format!("{cannot_do_this}{post_message}"))
- }
- // fallback to generic message
- (true, None) => None,
- }
- })
- .unwrap_or_else(|| {
- format!(
- "the trait bound `{}` is not satisfied{}",
- trait_predicate, post_message,
- )
- });
+ let err_msg = self.get_standard_error_message(
+ &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
self.get_safe_transmute_error_and_reason(
- trait_predicate,
obligation.clone(),
trait_ref,
span,
@@ -756,7 +738,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
err.span_label(
ret_span,
- &format!(
+ format!(
"expected `{}` because of this",
trait_ref.skip_binder().self_ty()
),
@@ -764,22 +746,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
- match obligation.cause.code().peel_derives() {
- ObligationCauseCode::RustCall => {
- err.set_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 tcx.is_fn_trait(*def_id) =>
- {
- err.code(rustc_errors::error_code!(E0059));
- err.set_primary_message(format!(
- "type parameter to bare `{}` trait must be a tuple",
- tcx.def_path_str(*def_id)
- ));
- }
- _ => {}
- }
+ self.add_tuple_trait_message(
+ &obligation.cause.code().peel_derives(),
+ &mut err,
+ );
}
if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
@@ -789,33 +759,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
}
- let explanation = if let ObligationCauseCode::MainFunctionType =
- obligation.cause.code()
- {
- "consider using `()`, or a `Result`".to_owned()
- } else {
- let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
- ty::FnDef(_, _) => Some("fn item"),
- ty::Closure(_, _) => Some("closure"),
- _ => None,
- };
+ let explanation = get_explanation_based_on_obligation(
+ &obligation,
+ trait_ref,
+ &trait_predicate,
+ pre_message,
+ );
- match ty_desc {
- Some(desc) => format!(
- "{}the trait `{}` is not implemented for {} `{}`",
- pre_message,
- trait_predicate.print_modifiers_and_trait_path(),
- desc,
- trait_ref.skip_binder().self_ty(),
- ),
- None => format!(
- "{}the trait `{}` is not implemented for `{}`",
- pre_message,
- trait_predicate.print_modifiers_and_trait_path(),
- trait_ref.skip_binder().self_ty(),
- ),
- }
- };
self.check_for_binding_assigned_block_without_tail_expression(
&obligation,
&mut err,
@@ -831,7 +781,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.emit();
return;
}
- if let Some(ref s) = label {
+ 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);
@@ -839,7 +789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// 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);
+ err.help(explanation);
}
} else if let Some(custom_explanation) = safe_transmute_explanation {
err.span_label(span, custom_explanation);
@@ -847,42 +797,36 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_label(span, explanation);
}
- if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
- Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
- self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
- }
-
- let mut unsatisfied_const = false;
- if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
- let non_const_predicate = trait_ref.without_const();
- let non_const_obligation = Obligation {
- cause: obligation.cause.clone(),
- param_env: obligation.param_env.without_const(),
- predicate: non_const_predicate.to_predicate(tcx),
- recursion_depth: obligation.recursion_depth,
- };
- if self.predicate_may_hold(&non_const_obligation) {
- unsatisfied_const = true;
- err.span_note(
- span,
- &format!(
- "the trait `{}` is implemented for `{}`, \
- but that implementation is not `const`",
- non_const_predicate.print_modifiers_and_trait_path(),
- trait_ref.skip_binder().self_ty(),
- ),
+ 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(
+ &obligation,
+ trait_ref,
+ &trait_predicate,
+ &mut err,
+ span,
+ );
+
if let Some((msg, span)) = type_def {
- err.span_label(span, &msg);
+ err.span_label(span, msg);
}
- if let Some(ref s) = note {
+ if let Some(s) = note {
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
- err.note(s.as_str());
+ err.note(s);
}
- if let Some(ref s) = parent_label {
+ if let Some(s) = parent_label {
let body = obligation.cause.body_id;
err.span_label(tcx.def_span(body), s);
}
@@ -941,7 +885,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return;
}
- if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
+ if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
err.emit();
return;
}
@@ -971,137 +915,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}
- let body_def_id = obligation.cause.body_id;
- // 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().constness,
- trait_predicate.skip_binder().polarity,
- )
- {
- // 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().substs.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,
- );
- }
- }
- } 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(
- &mut err,
- trait_predicate,
- None,
- obligation.cause.body_id,
- );
- } 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,
- &mut err,
- true,
- ) {
- // 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,
- &mut err,
- true,
- );
- }
- }
-
- self.maybe_suggest_convert_to_slice(
- &mut err,
- trait_ref,
- impl_candidates.as_slice(),
- span,
- );
- }
+ 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)
@@ -1196,59 +1019,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
let found_kind = self.closure_kind(closure_substs).unwrap();
- let closure_span = self.tcx.def_span(closure_def_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- closure_span,
- E0525,
- "expected a closure that implements the `{}` trait, \
- but this closure only implements `{}`",
- kind,
- found_kind
- );
-
- err.span_label(
- closure_span,
- format!("this closure implements `{}`, not `{}`", found_kind, kind),
- );
- err.span_label(
- obligation.cause.span,
- format!("the requirement to implement `{}` derives from here", kind),
- );
-
- // 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
- .hir()
- .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.span_label(
- *span,
- format!(
- "closure is `FnOnce` because it moves the \
- variable `{}` out of its environment",
- ty::place_to_string_for_capture(tcx, place)
- ),
- );
- }
- (ty::ClosureKind::FnMut, Some((span, place))) => {
- err.span_label(
- *span,
- format!(
- "closure is `FnMut` because it mutates the \
- variable `{}` here",
- ty::place_to_string_for_capture(tcx, place)
- ),
- );
- }
- _ => {}
- }
- }
-
- err
+ self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
}
ty::PredicateKind::WellFormed(ty) => {
@@ -1266,7 +1037,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// which bounds actually failed to hold.
self.tcx.sess.struct_span_err(
span,
- &format!("the type `{}` is not well-formed", ty),
+ format!("the type `{}` is not well-formed", ty),
)
}
}
@@ -1309,7 +1080,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
let mut diag = self.tcx.sess.struct_span_err(
span,
- &format!("the constant `{}` is not of type `{}`", ct, ty),
+ format!("the constant `{}` is not of type `{}`", ct, ty),
);
self.note_type_err(
&mut diag,
@@ -1325,121 +1096,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- OutputTypeParameterMismatch(
+ OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
found_trait_ref,
expected_trait_ref,
- terr @ TypeError::CyclicTy(_),
- ) => {
- let self_ty = found_trait_ref.self_ty().skip_binder();
- let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
- (
- ObligationCause::dummy_with_span(tcx.def_span(def_id)),
- TypeError::CyclicTy(self_ty),
- )
- } else {
- (obligation.cause.clone(), terr)
- };
- self.report_and_explain_type_error(
- TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
- terr,
- )
- }
- OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
- let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
- let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
-
- if expected_trait_ref.self_ty().references_error() {
- return;
- }
-
- let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
- return;
- };
-
- let found_did = match *found_trait_ty.kind() {
- ty::Closure(did, _)
- | ty::Foreign(did)
- | ty::FnDef(did, _)
- | ty::Generator(did, ..) => Some(did),
- ty::Adt(def, _) => Some(def.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_closure_mismatch.borrow().contains(&(span, found_span)) {
- // We check closures twice, with obligations flowing in different directions,
- // but we want to complain about them only once.
- return;
- }
-
- self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
-
- let mut not_tupled = false;
-
- let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
- ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
- _ => {
- not_tupled = true;
- vec![ArgKind::empty()]
- }
- };
-
- let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
- let expected = match expected_ty.kind() {
- ty::Tuple(ref 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.
- if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled {
- self.report_and_explain_type_error(
- TypeTrace::poly_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,
- )
+ terr: terr @ TypeError::CyclicTy(_),
+ }) => self.report_type_parameter_mismatch_cyclic_type_error(
+ &obligation,
+ found_trait_ref,
+ expected_trait_ref,
+ terr,
+ ),
+ OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
+ found_trait_ref,
+ expected_trait_ref,
+ terr: _,
+ }) => {
+ match self.report_type_parameter_mismatch_error(
+ &obligation,
+ span,
+ found_trait_ref,
+ expected_trait_ref,
+ ) {
+ Some(err) => err,
+ None => return,
}
}
@@ -1454,45 +1133,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
}
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
- if !self.tcx.features().generic_const_exprs {
- let mut err = self.tcx.sess.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.
- err.note("this may fail depending on what value the parameter takes");
- err.emit();
- return;
- }
-
- match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::ConstEvaluatable(ct) => {
- let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
- bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
- };
- let mut err =
- self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
- let const_span = self.tcx.def_span(uv.def.did);
- match self.tcx.sess.source_map().span_to_snippet(const_span) {
- Ok(snippet) => err.help(&format!(
- "try adding a `where` bound using this expression: `where [(); {}]:`",
- snippet
- )),
- _ => err.help("consider adding a `where` bound using this expression"),
- };
- err
- }
- _ => {
- span_bug!(
- span,
- "unexpected non-ConstEvaluatable predicate, this should not be reachable"
- )
- }
+ match self.report_not_const_evaluatable_error(&obligation, span) {
+ Some(err) => err,
+ None => return,
}
}
@@ -1564,6 +1207,14 @@ trait InferCtxtPrivExt<'tcx> {
other: bool,
) -> bool;
+ 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 Diagnostic,
+ );
+
/// Gets the parent trait chain start
fn get_parent_trait_ref(
&self,
@@ -1627,13 +1278,86 @@ trait InferCtxtPrivExt<'tcx> {
cause_code: &ObligationCauseCode<'tcx>,
) -> bool;
+ 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;
+
fn get_safe_transmute_error_and_reason(
&self,
- trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
- obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ obligation: PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
) -> (String, Option<String>);
+
+ fn add_tuple_trait_message(
+ &self,
+ obligation_cause_code: &ObligationCauseCode<'tcx>,
+ err: &mut Diagnostic,
+ );
+
+ fn try_to_add_help_message(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ is_fn_trait: bool,
+ suggested: bool,
+ unsatisfied_const: bool,
+ );
+
+ fn add_help_message_for_fn_trait(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ err: &mut Diagnostic,
+ implemented_kind: ty::ClosureKind,
+ params: ty::Binder<'tcx, Ty<'tcx>>,
+ );
+
+ fn maybe_add_note_for_unsatisfied_const(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ ) -> UnsatisfiedConst;
+
+ fn report_closure_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ closure_def_id: DefId,
+ found_kind: ty::ClosureKind,
+ kind: ty::ClosureKind,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+ fn report_type_parameter_mismatch_cyclic_type_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ terr: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+ fn report_type_parameter_mismatch_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ span: Span,
+ found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
+
+ fn report_not_const_evaluatable_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ span: Span,
+ ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
}
impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
@@ -1720,6 +1444,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::ExprItemObligation(..) = code
{
self.note_obligation_cause_code(
+ error.obligation.cause.body_id,
&mut diag,
error.obligation.predicate,
error.obligation.param_env,
@@ -1773,7 +1498,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.tcx
.mk_const(
ty::UnevaluatedConst {
- def: ty::WithOptConstParam::unknown(data.projection_ty.def_id),
+ def: data.projection_ty.def_id,
substs: data.projection_ty.substs,
},
ct.ty(),
@@ -1793,7 +1518,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ExprItemObligation(..)
| ObligationCauseCode::ExprBindingObligation(..)
- | ObligationCauseCode::ObjectCastObligation(..)
+ | ObligationCauseCode::Coercion { .. }
| ObligationCauseCode::OpaqueType
);
@@ -1838,57 +1563,61 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
});
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
- let secondary_span = match predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self
- .tcx
- .opt_associated_item(proj.projection_ty.def_id)
- .and_then(|trait_assoc_item| {
- self.tcx
- .trait_of_item(proj.projection_ty.def_id)
- .map(|id| (trait_assoc_item, id))
- })
- .and_then(|(trait_assoc_item, id)| {
- let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
- self.tcx.find_map_relevant_impl(
- id,
- proj.projection_ty.self_ty(),
- TreatProjections::ForLookup,
- |did| {
- self.tcx
- .associated_items(did)
- .in_definition_order()
- .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
- },
- )
- })
- .and_then(|item| match self.tcx.hir().get_if_local(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!(format!(
- "type mismatch resolving `{}`",
- self.resolve_vars_if_possible(predicate)
- .print(FmtPrinter::new_with_limit(
- self.tcx,
- Namespace::TypeNS,
- rustc_session::Limit(5),
- ))
- .unwrap()
- .into_buffer()
- )),
+ let secondary_span = (|| {
+ let ty::PredicateKind::Clause(ty::Clause::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!(format!(
+ "type mismatch resolving `{}`",
+ self.resolve_vars_if_possible(predicate)
+ .print(FmtPrinter::new_with_limit(
+ self.tcx,
+ Namespace::TypeNS,
+ rustc_session::Limit(5),
+ ))
+ .unwrap()
+ .into_buffer()
)),
- _ => None,
- }),
- _ => None,
- };
+ )),
+ _ => None,
+ }
+ })();
+
self.note_type_err(
&mut diag,
&obligation.cause,
@@ -1971,13 +1700,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Tuple(..) => Some(10),
ty::Param(..) => Some(11),
ty::Alias(ty::Projection, ..) => Some(12),
- ty::Alias(ty::Opaque, ..) => Some(13),
- ty::Never => Some(14),
- ty::Adt(..) => Some(15),
- ty::Generator(..) => Some(16),
- ty::Foreign(..) => Some(17),
- ty::GeneratorWitness(..) => Some(18),
- ty::GeneratorWitnessMIR(..) => Some(19),
+ ty::Alias(ty::Inherent, ..) => Some(13),
+ ty::Alias(ty::Opaque, ..) => Some(14),
+ ty::Never => Some(15),
+ ty::Adt(..) => Some(16),
+ ty::Generator(..) => Some(17),
+ ty::Foreign(..) => Some(18),
+ ty::GeneratorWitness(..) => Some(19),
+ ty::GeneratorWitnessMIR(..) => Some(20),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}
@@ -2058,7 +1788,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
// If any of the candidates is a perfect match, we don't want to show all of them.
// This is particularly relevant for the case of numeric types (as they all have the
- // same cathegory).
+ // same category).
candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
}
candidates
@@ -2120,7 +1850,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
candidates.sort();
candidates.dedup();
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
- err.help(&format!(
+ err.help(format!(
"the following {other}types implement trait `{}`:{}{}",
trait_ref.print_only_trait_path(),
candidates[..end].join(""),
@@ -2197,6 +1927,51 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
report(normalized_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 Diagnostic,
+ ) {
+ // 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,
+ );
+ }
+ }
+
/// Gets the parent trait chain start
fn get_parent_trait_ref(
&self,
@@ -2230,14 +2005,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err: &mut Diagnostic,
trait_ref: &ty::PolyTraitRef<'tcx>,
) -> bool {
- let get_trait_impl = |trait_def_id| {
- self.tcx.find_map_relevant_impl(
+ 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(),
- TreatProjections::ForLookup,
- Some,
- )
+ |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: std::collections::BTreeSet<_> = self
.tcx
@@ -2247,17 +2026,23 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.collect();
let mut suggested = false;
for trait_with_same_path in traits_with_same_path {
- if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) {
- let impl_span = self.tcx.def_span(impl_def_id);
- err.span_help(impl_span, "trait impl with same name found");
- let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
- let crate_msg = format!(
- "perhaps two different versions of crate `{}` are being used?",
- trait_crate
- );
- err.note(&crate_msg);
- suggested = true;
+ 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 `{}` are being used?",
+ trait_crate
+ );
+ err.note(crate_msg);
+ suggested = true;
}
suggested
}
@@ -2388,7 +2173,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.cancel();
return;
}
- err.note(&format!("cannot satisfy `{}`", predicate));
+ err.note(format!("cannot satisfy `{}`", predicate));
let impl_candidates = self.find_similar_impl_candidates(
predicate.to_opt_poly_trait_pred().unwrap(),
);
@@ -2408,7 +2193,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.cancel();
return;
}
- err.note(&format!("cannot satisfy `{}`", predicate));
+ err.note(format!("cannot satisfy `{}`", predicate));
}
}
@@ -2453,9 +2238,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.cancel();
err = self.tcx.sess.struct_span_err_with_code(
span,
- &format!(
+ format!(
"cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type",
- ),
+ ),
rustc_errors::error_code!(E0790),
);
@@ -2562,7 +2347,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ErrorCode::E0284,
true,
);
- err.note(&format!("cannot satisfy `{}`", predicate));
+ err.note(format!("cannot satisfy `{}`", predicate));
err
} else {
// If we can't find a substitution, just print a generic error
@@ -2573,7 +2358,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"type annotations needed: cannot satisfy `{}`",
predicate,
);
- err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+ err.span_label(span, format!("cannot satisfy `{}`", predicate));
err
}
}
@@ -2601,7 +2386,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"type annotations needed: cannot satisfy `{}`",
predicate,
);
- err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+ err.span_label(span, format!("cannot satisfy `{}`", predicate));
err
}
}
@@ -2616,7 +2401,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"type annotations needed: cannot satisfy `{}`",
predicate,
);
- err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+ err.span_label(span, format!("cannot satisfy `{}`", predicate));
err
}
};
@@ -2689,13 +2474,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
match (spans.len(), crates.len(), crate_names.len()) {
(0, 0, 0) => {
- err.note(&format!("cannot satisfy `{}`", predicate));
+ err.note(format!("cannot satisfy `{}`", predicate));
}
(0, _, 1) => {
- err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,));
+ err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
}
(0, _, _) => {
- err.note(&format!(
+ err.note(format!(
"{} in the following crates: {}{}",
msg,
crate_names.join(", "),
@@ -2704,19 +2489,17 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
(_, 0, 0) => {
let span: MultiSpan = spans.into();
- err.span_note(span, &msg);
+ 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,),
- );
+ 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!(
+ err.span_note(span, msg);
+ err.note(format!(
"and more `impl`s found in the following crates: {}{}",
crate_names.join(", "),
post,
@@ -2776,6 +2559,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// 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,
@@ -2887,7 +2671,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
err.span_help(
multispan,
- &format!(
+ 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(),
@@ -2919,20 +2703,52 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
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 `{}` is not satisfied{}", trait_predicate, post_message)
+ })
+ }
+
fn get_safe_transmute_error_and_reason(
&self,
- trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
- obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ obligation: PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
) -> (String, Option<String>) {
- let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types {
- dst: p.trait_ref.substs.type_at(0),
- src: p.trait_ref.substs.type_at(1),
- });
- let scope = trait_ref.skip_binder().substs.type_at(2);
+ // Erase regions because layout code doesn't particularly care about regions.
+ let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
+
+ let src_and_dst = rustc_transmute::Types {
+ dst: trait_ref.substs.type_at(0),
+ src: trait_ref.substs.type_at(1),
+ };
+ let scope = trait_ref.substs.type_at(2);
let Some(assume) =
- rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.skip_binder().substs.const_at(3)) else {
+ rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
};
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@@ -2942,24 +2758,27 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
assume,
) {
rustc_transmute::Answer::No(reason) => {
- let dst = trait_ref.skip_binder().substs.type_at(0);
- let src = trait_ref.skip_binder().substs.type_at(1);
- let custom_err_msg = format!("`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`").to_string();
+ let dst = trait_ref.substs.type_at(0);
+ let src = trait_ref.substs.type_at(1);
+ let custom_err_msg = format!(
+ "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
+ );
let reason_msg = match reason {
rustc_transmute::Reason::SrcIsUnspecified => {
- format!("`{src}` does not have a well-specified layout").to_string()
+ format!("`{src}` does not have a well-specified layout")
}
+
rustc_transmute::Reason::DstIsUnspecified => {
- format!("`{dst}` does not have a well-specified layout").to_string()
+ format!("`{dst}` does not have a well-specified layout")
}
+
rustc_transmute::Reason::DstIsBitIncompatible => {
format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`")
- .to_string()
}
+
rustc_transmute::Reason::DstIsPrivate => format!(
"`{dst}` is or contains a type or field that is not visible in that scope"
- )
- .to_string(),
+ ),
// FIXME(bryangarza): Include the number of bytes of src and dst
rustc_transmute::Reason::DstIsTooBig => {
format!("The size of `{src}` is smaller than the size of `{dst}`")
@@ -2975,8 +2794,449 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"),
}
}
+
+ fn add_tuple_trait_message(
+ &self,
+ obligation_cause_code: &ObligationCauseCode<'tcx>,
+ err: &mut Diagnostic,
+ ) {
+ match obligation_cause_code {
+ ObligationCauseCode::RustCall => {
+ err.set_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(rustc_errors::error_code!(E0059));
+ err.set_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 Diagnostic,
+ span: Span,
+ is_fn_trait: bool,
+ suggested: bool,
+ unsatisfied_const: bool,
+ ) {
+ let body_def_id = obligation.cause.body_id;
+ // 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().constness,
+ 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 !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,
+ ) {
+ self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err);
+ }
+
+ self.maybe_suggest_convert_to_slice(
+ err,
+ trait_ref,
+ impl_candidates.as_slice(),
+ span,
+ );
+ }
+ }
+
+ fn add_help_message_for_fn_trait(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ err: &mut Diagnostic,
+ 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().substs.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,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ ) -> UnsatisfiedConst {
+ let mut unsatisfied_const = UnsatisfiedConst(false);
+ if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
+ let non_const_predicate = trait_ref.without_const();
+ let non_const_obligation = Obligation {
+ cause: obligation.cause.clone(),
+ param_env: obligation.param_env.without_const(),
+ predicate: non_const_predicate.to_predicate(self.tcx),
+ recursion_depth: obligation.recursion_depth,
+ };
+ if self.predicate_may_hold(&non_const_obligation) {
+ unsatisfied_const = UnsatisfiedConst(true);
+ err.span_note(
+ span,
+ format!(
+ "the trait `{}` is implemented for `{}`, \
+ but that implementation is not `const`",
+ non_const_predicate.print_modifiers_and_trait_path(),
+ trait_ref.skip_binder().self_ty(),
+ ),
+ );
+ }
+ }
+ unsatisfied_const
+ }
+
+ fn report_closure_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ closure_def_id: DefId,
+ found_kind: ty::ClosureKind,
+ kind: ty::ClosureKind,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let closure_span = self.tcx.def_span(closure_def_id);
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ closure_span,
+ E0525,
+ "expected a closure that implements the `{}` trait, \
+ but this closure only implements `{}`",
+ kind,
+ found_kind
+ );
+
+ err.span_label(
+ closure_span,
+ format!("this closure implements `{}`, not `{}`", found_kind, kind),
+ );
+ err.span_label(
+ obligation.cause.span,
+ format!("the requirement to implement `{}` derives from here", kind),
+ );
+
+ // 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.hir().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.span_label(
+ *span,
+ format!(
+ "closure is `FnOnce` because it moves the \
+ variable `{}` out of its environment",
+ ty::place_to_string_for_capture(self.tcx, place)
+ ),
+ );
+ }
+ (ty::ClosureKind::FnMut, Some((span, place))) => {
+ err.span_label(
+ *span,
+ format!(
+ "closure is `FnMut` because it mutates the \
+ variable `{}` here",
+ ty::place_to_string_for_capture(self.tcx, place)
+ ),
+ );
+ }
+ _ => {}
+ }
+ }
+
+ err
+ }
+
+ fn report_type_parameter_mismatch_cyclic_type_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ terr: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let self_ty = found_trait_ref.self_ty().skip_binder();
+ 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::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+ terr,
+ )
+ }
+
+ fn report_type_parameter_mismatch_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ span: Span,
+ found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ ) -> Option<DiagnosticBuilder<'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);
+
+ if expected_trait_ref.self_ty().references_error() {
+ return None;
+ }
+
+ let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
+ return None;
+ };
+
+ let found_did = match *found_trait_ty.kind() {
+ ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) | ty::Generator(did, ..) => {
+ Some(did)
+ }
+ ty::Adt(def, _) => Some(def.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_closure_mismatch.borrow().contains(&(span, found_span)) {
+ // We check closures twice, with obligations flowing in different directions,
+ // but we want to complain about them only once.
+ return None;
+ }
+
+ self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
+
+ let mut not_tupled = false;
+
+ let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
+ ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
+ _ => {
+ not_tupled = true;
+ vec![ArgKind::empty()]
+ }
+ };
+
+ let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
+ let expected = match expected_ty.kind() {
+ ty::Tuple(ref 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.
+ Some(
+ if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().gen_trait() && not_tupled
+ {
+ self.report_and_explain_type_error(
+ TypeTrace::poly_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,
+ ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+ if !self.tcx.features().generic_const_exprs {
+ let mut err = self
+ .tcx
+ .sess
+ .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.
+ err.note("this may fail depending on what value the parameter takes");
+ err.emit();
+ return None;
+ }
+
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+ bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
+ };
+ let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
+ let const_span = self.tcx.def_span(uv.def);
+ match self.tcx.sess.source_map().span_to_snippet(const_span) {
+ Ok(snippet) => err.help(format!(
+ "try adding a `where` bound using this expression: `where [(); {}]:`",
+ snippet
+ )),
+ _ => err.help("consider adding a `where` bound using this expression"),
+ };
+ Some(err)
+ }
+ _ => {
+ span_bug!(
+ span,
+ "unexpected non-ConstEvaluatable predicate, this should not be reachable"
+ )
+ }
+ }
+ }
}
+struct UnsatisfiedConst(pub bool);
+
+fn get_explanation_based_on_obligation<'tcx>(
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ pre_message: String,
+) -> String {
+ if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+ "consider using `()`, or a `Result`".to_owned()
+ } else {
+ let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
+ ty::FnDef(_, _) => Some("fn item"),
+ ty::Closure(_, _) => Some("closure"),
+ _ => None,
+ };
+
+ match ty_desc {
+ Some(desc) => format!(
+ "{}the trait `{}` is not implemented for {} `{}`",
+ pre_message,
+ trait_predicate.print_modifiers_and_trait_path(),
+ desc,
+ trait_ref.skip_binder().self_ty(),
+ ),
+ None => format!(
+ "{}the trait `{}` is not implemented for `{}`",
+ pre_message,
+ trait_predicate.print_modifiers_and_trait_path(),
+ trait_ref.skip_binder().self_ty(),
+ ),
+ }
+ }
+}
/// Crude way of getting back an `Expr` from a `Span`.
pub struct FindExprBySpan<'hir> {
pub span: Span,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index a9c4e1268..10bd027b6 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -306,6 +306,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
}
+
+ // `&[{integral}]` - `FromIterator` needs that.
+ if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) = self_ty.kind()
+ && let ty::Slice(sty) = ref_ty.kind()
+ && sty.is_integral()
+ {
+ flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
+ }
});
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
@@ -327,7 +335,7 @@ pub struct OnUnimplementedDirective {
pub label: Option<OnUnimplementedFormatString>,
pub note: Option<OnUnimplementedFormatString>,
pub parent_label: Option<OnUnimplementedFormatString>,
- pub append_const_msg: Option<Option<Symbol>>,
+ pub append_const_msg: Option<AppendConstMessage>,
}
/// For the `#[rustc_on_unimplemented]` attribute
@@ -337,11 +345,21 @@ pub struct OnUnimplementedNote {
pub label: Option<String>,
pub note: Option<String>,
pub parent_label: Option<String>,
- /// Append a message for `~const Trait` errors. `None` means not requested and
- /// should fallback to a generic message, `Some(None)` suggests using the default
- /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
- /// default one..
- pub append_const_msg: Option<Option<Symbol>>,
+ // If none, should fall back to a generic message
+ pub append_const_msg: Option<AppendConstMessage>,
+}
+
+/// Append a message for `~const Trait` errors.
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum AppendConstMessage {
+ Default,
+ Custom(Symbol),
+}
+
+impl Default for AppendConstMessage {
+ fn default() -> Self {
+ AppendConstMessage::Default
+ }
}
impl<'tcx> OnUnimplementedDirective {
@@ -419,10 +437,10 @@ impl<'tcx> OnUnimplementedDirective {
}
} else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
if let Some(msg) = item.value_str() {
- append_const_msg = Some(Some(msg));
+ append_const_msg = Some(AppendConstMessage::Custom(msg));
continue;
} else if item.is_word() {
- append_const_msg = Some(None);
+ append_const_msg = Some(AppendConstMessage::Default);
continue;
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index fb75ec767..82bad96ea 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -25,23 +25,22 @@ use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
use rustc_hir::{Expr, HirId};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime};
use rustc_middle::hir::map;
use rustc_middle::ty::error::TypeError::{self, Sorts};
-use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
- GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
- IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
- TypeSuperFoldable, TypeVisitableExt, TypeckResults,
+ GeneratorDiagnosticData, GeneratorInteriorTypeCause, InferTy, InternalSubsts, IsSuggestable,
+ ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable,
+ TypeVisitableExt, TypeckResults,
};
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
+use std::iter;
use std::ops::Deref;
-use super::method_chain::CollectAllMismatches;
use super::InferCtxtPrivExt;
use crate::infer::InferCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -262,7 +261,6 @@ pub trait TypeErrCtxtExt<'tcx> {
fn suggest_impl_trait(
&self,
err: &mut Diagnostic,
- span: Span,
obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
@@ -319,6 +317,7 @@ pub trait TypeErrCtxtExt<'tcx> {
fn note_obligation_cause_code<T>(
&self,
+ body_id: LocalDefId,
err: &mut Diagnostic,
predicate: T,
param_env: ty::ParamEnv<'tcx>,
@@ -359,8 +358,9 @@ pub trait TypeErrCtxtExt<'tcx> {
);
fn note_function_argument_obligation(
&self,
- arg_hir_id: HirId,
+ body_id: LocalDefId,
err: &mut Diagnostic,
+ arg_hir_id: HirId,
parent_code: &ObligationCauseCode<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: ty::Predicate<'tcx>,
@@ -386,7 +386,7 @@ pub trait TypeErrCtxtExt<'tcx> {
fn maybe_suggest_convert_to_slice(
&self,
err: &mut Diagnostic,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
candidate_impls: &[ImplCandidate<'tcx>],
span: Span,
);
@@ -420,7 +420,7 @@ fn suggest_restriction<'tcx>(
) {
if hir_generics.where_clause_span.from_expansion()
|| hir_generics.where_clause_span.desugaring_kind().is_some()
- || projection.map_or(false, |projection| tcx.opt_rpitit_info(projection.def_id).is_some())
+ || projection.is_some_and(|projection| tcx.opt_rpitit_info(projection.def_id).is_some())
{
return;
}
@@ -515,7 +515,7 @@ fn suggest_restriction<'tcx>(
err.span_suggestion_verbose(
sp,
- &format!("consider further restricting {}", msg),
+ format!("consider further restricting {}", msg),
suggestion,
Applicability::MachineApplicable,
);
@@ -530,6 +530,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
associated_ty: Option<(&'static str, Ty<'tcx>)>,
mut body_id: LocalDefId,
) {
+ if trait_pred.skip_binder().polarity == ty::ImplPolarity::Negative {
+ return;
+ }
+
let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
let self_ty = trait_pred.skip_binder().self_ty();
@@ -964,7 +968,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// a more general note.
err.span_suggestion_verbose(
obligation.cause.span.shrink_to_hi(),
- &msg,
+ msg,
format!("({args})"),
Applicability::HasPlaceholders,
);
@@ -994,7 +998,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
_ => return false,
};
- err.help(&format!("{msg}: `{name}({args})`"));
+ err.help(format!("{msg}: `{name}({args})`"));
}
true
}
@@ -1334,7 +1338,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let msg = format!("the trait bound `{}` is not satisfied", old_pred);
if has_custom_message {
- err.note(&msg);
+ err.note(msg);
} else {
err.message =
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
@@ -1358,7 +1362,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} else {
let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
- let sugg_msg = &format!(
+ let sugg_msg = format!(
"consider{} borrowing here",
if is_mut { " mutably" } else { "" }
);
@@ -1381,7 +1385,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- // Issue #104961, we need to add parentheses properly for compond expressions
+ // Issue #104961, we need to add parentheses properly for compound expressions
// for example, `x.starts_with("hi".to_string() + "you")`
// should be `x.starts_with(&("hi".to_string() + "you"))`
let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; };
@@ -1437,8 +1441,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err: &mut Diagnostic,
obligation: &PredicateObligation<'tcx>,
self_ty: Ty<'tcx>,
- object_ty: Ty<'tcx>,
+ target_ty: Ty<'tcx>,
) {
+ let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; };
let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; };
let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);
@@ -1452,8 +1457,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_suggestion(
obligation.cause.span.shrink_to_lo(),
- &format!(
- "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`"
+ format!(
+ "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`"
),
"&",
Applicability::MaybeIncorrect,
@@ -1505,7 +1510,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
};
err.multipart_suggestion_verbose(
- &msg,
+ msg,
suggestions,
Applicability::MachineApplicable,
);
@@ -1583,55 +1588,68 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {
- let span = obligation.cause.span;
-
- if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() {
- let hir = self.tcx.hir();
- if let Some(hir::Node::Expr(expr)) = hir_id.and_then(|hir_id| hir.find(hir_id)) {
- // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
- // and if not maybe suggest doing something else? If we kept the expression around we
- // could also check if it is an fn call (very likely) and suggest changing *that*, if
- // it is from the local crate.
+ let hir = self.tcx.hir();
+ if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = obligation.cause.code().peel_derives()
+ && let hir::Node::Expr(expr) = hir.get(*hir_id)
+ {
+ // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
+ // and if not maybe suggest doing something else? If we kept the expression around we
+ // could also check if it is an fn call (very likely) and suggest changing *that*, if
+ // it is from the local crate.
+
+ // use nth(1) to skip one layer of desugaring from `IntoIter::into_iter`
+ if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1)
+ && let Some(expr_span) = expr.span.find_ancestor_inside(await_expr.span)
+ {
+ let removal_span = self.tcx
+ .sess
+ .source_map()
+ .span_extend_while(expr_span, char::is_whitespace)
+ .unwrap_or(expr_span)
+ .shrink_to_hi()
+ .to(await_expr.span.shrink_to_hi());
err.span_suggestion(
- span,
+ removal_span,
"remove the `.await`",
"",
Applicability::MachineApplicable,
);
- // FIXME: account for associated `async fn`s.
- if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
- if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) =
- obligation.predicate.kind().skip_binder()
+ } else {
+ err.span_label(obligation.cause.span, "remove the `.await`");
+ }
+ // FIXME: account for associated `async fn`s.
+ if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) =
+ obligation.predicate.kind().skip_binder()
+ {
+ err.span_label(*span, format!("this call returns `{}`", pred.self_ty()));
+ }
+ if let Some(typeck_results) = &self.typeck_results
+ && let ty = typeck_results.expr_ty_adjusted(base)
+ && let ty::FnDef(def_id, _substs) = ty.kind()
+ && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
+ hir.get_if_local(*def_id)
{
- err.span_label(*span, &format!("this call returns `{}`", pred.self_ty()));
- }
- if let Some(typeck_results) = &self.typeck_results
- && let ty = typeck_results.expr_ty_adjusted(base)
- && let ty::FnDef(def_id, _substs) = ty.kind()
- && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
- hir.get_if_local(*def_id)
- {
- let msg = format!(
- "alternatively, consider making `fn {}` asynchronous",
- ident
+ let msg = format!(
+ "alternatively, consider making `fn {}` asynchronous",
+ ident
+ );
+ if vis_span.is_empty() {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ msg,
+ "async ",
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ vis_span.shrink_to_hi(),
+ msg,
+ " async",
+ Applicability::MaybeIncorrect,
);
- if vis_span.is_empty() {
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- &msg,
- "async ",
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_suggestion_verbose(
- vis_span.shrink_to_hi(),
- &msg,
- " async",
- Applicability::MaybeIncorrect,
- );
- }
}
- }
+ }
}
}
}
@@ -1704,7 +1722,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Applicability::MachineApplicable,
);
} else {
- err.note(&format!(
+ err.note(format!(
"`{}` is implemented for `{:?}`, but not for `{:?}`",
trait_pred.print_modifiers_and_trait_path(),
suggested_ty,
@@ -1741,7 +1759,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
err.span_label(
expr.span,
- &format!(
+ format!(
"this expression has type `{}`, which implements `{}`",
ty,
trait_pred.print_modifiers_and_trait_path()
@@ -1773,215 +1791,66 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn suggest_impl_trait(
&self,
err: &mut Diagnostic,
- span: Span,
obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
- match obligation.cause.code().peel_derives() {
- // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
- ObligationCauseCode::SizedReturnType => {}
- _ => return false,
- }
-
- let hir = self.tcx.hir();
- let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id);
- let node = hir.find_by_def_id(obligation.cause.body_id);
- let Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(sig, _, body_id),
- ..
- })) = node
- else {
+ let ObligationCauseCode::SizedReturnType = obligation.cause.code() else {
return false;
};
- let body = hir.body(*body_id);
- let trait_pred = self.resolve_vars_if_possible(trait_pred);
- let ty = trait_pred.skip_binder().self_ty();
- let is_object_safe = match ty.kind() {
- ty::Dynamic(predicates, _, ty::Dyn) => {
- // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
- predicates
- .principal_def_id()
- .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id))
- }
- // We only want to suggest `impl Trait` to `dyn Trait`s.
- // For example, `fn foo() -> str` needs to be filtered out.
- _ => return false,
- };
-
- let hir::FnRetTy::Return(ret_ty) = sig.decl.output else {
+ let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else {
return false;
};
- // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
- // cases like `fn foo() -> (dyn Trait, i32) {}`.
- // Recursively look for `TraitObject` types and if there's only one, use that span to
- // suggest `impl Trait`.
-
- // Visit to make sure there's a single `return` type to suggest `impl Trait`,
- // otherwise suggest using `Box<dyn Trait>` or an enum.
- let mut visitor = ReturnsVisitor::default();
- visitor.visit_body(&body);
-
- let typeck_results = self.typeck_results.as_ref().unwrap();
- let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
-
- let ret_types = visitor
- .returns
- .iter()
- .filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?)))
- .map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty)));
- let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold(
- (None, true, true),
- |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool),
- (_, ty)| {
- let ty = self.resolve_vars_if_possible(ty);
- same &=
- !matches!(ty.kind(), ty::Error(_))
- && last_ty.map_or(true, |last_ty| {
- // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes
- // *after* in the dependency graph.
- match (ty.kind(), last_ty.kind()) {
- (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_)))
- | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_)))
- | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_)))
- | (
- Infer(InferTy::FreshFloatTy(_)),
- Infer(InferTy::FreshFloatTy(_)),
- ) => true,
- _ => ty == last_ty,
- }
- });
- (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never))
- },
- );
- let mut spans_and_needs_box = vec![];
-
- match liberated_sig.output().kind() {
- ty::Dynamic(predicates, _, ty::Dyn) => {
- let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id);
- let param_env = ty::ParamEnv::empty();
-
- if !only_never_return {
- for (expr_span, return_ty) in ret_types {
- let self_ty_satisfies_dyn_predicates = |self_ty| {
- predicates.iter().all(|predicate| {
- let pred = predicate.with_self_ty(self.tcx, self_ty);
- let obl = Obligation::new(self.tcx, cause.clone(), param_env, pred);
- self.predicate_may_hold(&obl)
- })
- };
-
- if let ty::Adt(def, substs) = return_ty.kind()
- && def.is_box()
- && self_ty_satisfies_dyn_predicates(substs.type_at(0))
- {
- spans_and_needs_box.push((expr_span, false));
- } else if self_ty_satisfies_dyn_predicates(return_ty) {
- spans_and_needs_box.push((expr_span, true));
- } else {
- return false;
- }
- }
- }
- }
- _ => return false,
- };
-
- let sm = self.tcx.sess.source_map();
- if !ret_ty.span.overlaps(span) {
- return false;
- }
- let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind {
- if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) {
- snippet
- } else {
- return false;
- }
- } else {
- // Substitute the type, so we can print a fixup given `type Alias = dyn Trait`
- let name = liberated_sig.output().to_string();
- let name =
- name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name);
- if !name.starts_with("dyn ") {
- return false;
- }
- name.to_owned()
- };
-
err.code(error_code!(E0746));
err.set_primary_message("return type cannot have an unboxed trait object");
err.children.clear();
- let impl_trait_msg = "for information on `impl Trait`, see \
- <https://doc.rust-lang.org/book/ch10-02-traits.html\
- #returning-types-that-implement-traits>";
- let trait_obj_msg = "for information on trait objects, see \
- <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
- #using-trait-objects-that-allow-for-values-of-different-types>";
-
- let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
- let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
- if only_never_return {
- // No return paths, probably using `panic!()` or similar.
- // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
- suggest_trait_object_return_type_alternatives(
- err,
- ret_ty.span,
- trait_obj,
- is_object_safe,
- );
- } else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) {
- // Suggest `-> impl Trait`.
+
+ let span = obligation.cause.span;
+ if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
+ && snip.starts_with("dyn ")
+ {
err.span_suggestion(
- ret_ty.span,
- &format!(
- "use `impl {1}` as the return type, as all return paths are of type `{}`, \
- which implements `{1}`",
- last_ty, trait_obj,
- ),
- format!("impl {}", trait_obj),
- Applicability::MachineApplicable,
+ span.with_hi(span.lo() + BytePos(4)),
+ "return an `impl Trait` instead of a `dyn Trait`, \
+ if all returned values are the same type",
+ "impl ",
+ Applicability::MaybeIncorrect,
);
- err.note(impl_trait_msg);
- } else {
- if is_object_safe {
- // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
- err.multipart_suggestion(
- "return a boxed trait object instead",
- vec![
- (ret_ty.span.shrink_to_lo(), "Box<".to_string()),
- (span.shrink_to_hi(), ">".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- for (span, needs_box) in spans_and_needs_box {
- if needs_box {
- err.multipart_suggestion(
- "... and box this value",
- vec![
- (span.shrink_to_lo(), "Box::new(".to_string()),
- (span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- }
- }
+ }
+
+ let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id));
+
+ let mut visitor = ReturnsVisitor::default();
+ visitor.visit_body(&body);
+
+ let mut sugg =
+ vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())];
+ sugg.extend(visitor.returns.into_iter().flat_map(|expr| {
+ let span = expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span);
+ if !span.can_be_used_for_suggestions() {
+ vec![]
+ } else if let hir::ExprKind::Call(path, ..) = expr.kind
+ && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, method)) = path.kind
+ && method.ident.name == sym::new
+ && let hir::TyKind::Path(hir::QPath::Resolved(.., box_path)) = ty.kind
+ && box_path.res.opt_def_id().is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box())
+ {
+ // Don't box `Box::new`
+ vec![]
} else {
- // This is currently not possible to trigger because E0038 takes precedence, but
- // leave it in for completeness in case anything changes in an earlier stage.
- err.note(&format!(
- "if trait `{}` were object-safe, you could return a trait object",
- trait_obj,
- ));
+ vec![
+ (span.shrink_to_lo(), "Box::new(".to_string()),
+ (span.shrink_to_hi(), ")".to_string()),
+ ]
}
- err.note(trait_obj_msg);
- err.note(&format!(
- "if all the returned values were of the same type you could use `impl {}` as the \
- return type",
- trait_obj,
- ));
- err.note(impl_trait_msg);
- err.note("you can create a new `enum` with a variant for each returned type");
- }
+ }));
+
+ err.multipart_suggestion(
+ "box the return type, and wrap all of the returned values in `Box::new`",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+
true
}
@@ -2014,7 +1883,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} else {
err.span_label(
expr.span,
- &format!("this returned value is of type `{}`", ty),
+ format!("this returned value is of type `{}`", ty),
);
}
}
@@ -2164,7 +2033,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) {
if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) {
if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind {
- err.note(&format!(
+ err.note(format!(
"{}s cannot be accessed directly on a `trait`, they can only be \
accessed through a specific `impl`",
self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id)
@@ -2428,10 +2297,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& generator_did.is_local()
// Try to avoid cycles.
&& !generator_within_in_progress_typeck
+ && let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did)
{
- let generator_info = &self.tcx.mir_generator_witnesses(generator_did);
debug!(?generator_info);
-
'find_source: for (variant, source_info) in
generator_info.variant_fields.iter().zip(&generator_info.variant_source_info)
{
@@ -2594,7 +2462,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
err.span_note(
span,
- &format!(
+ format!(
"{} {} as this value is used across {}",
future_or_generator, trait_explanation, an_await_or_yield
),
@@ -2615,7 +2483,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
err.span_note(
span,
- &format!(
+ format!(
"future {not_trait} as it awaits another future which {not_trait}",
not_trait = trait_explanation
),
@@ -2717,7 +2585,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut span = MultiSpan::from_span(upvar_span);
span.push_span_label(upvar_span, span_label);
- err.span_note(span, &span_note);
+ err.span_note(span, span_note);
}
}
@@ -2725,6 +2593,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// bound that introduced the obligation (e.g. `T: Send`).
debug!(?next_code);
self.note_obligation_cause_code(
+ obligation.cause.body_id,
err,
obligation.predicate,
obligation.param_env,
@@ -2736,6 +2605,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn note_obligation_cause_code<T>(
&self,
+ body_id: LocalDefId,
err: &mut Diagnostic,
predicate: T,
param_env: ty::ParamEnv<'tcx>,
@@ -2773,7 +2643,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::LetElse
| ObligationCauseCode::BinOp { .. }
| ObligationCauseCode::AscribeUserTypeProvePredicate(..)
- | ObligationCauseCode::RustCall => {}
+ | ObligationCauseCode::RustCall
+ | ObligationCauseCode::DropImpl => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
@@ -2781,15 +2652,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.note("only the last element of a tuple may have a dynamically sized type");
}
ObligationCauseCode::ProjectionWf(data) => {
- err.note(&format!("required so that the projection `{data}` is well-formed"));
+ err.note(format!("required so that the projection `{data}` is well-formed"));
}
ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
- err.note(&format!(
+ err.note(format!(
"required so that reference `{ref_ty}` does not outlive its referent"
));
}
ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
- err.note(&format!(
+ err.note(format!(
"required so that the lifetime bound of `{}` for `{}` is satisfied",
region, object_ty,
));
@@ -2825,35 +2696,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if span.is_visible(sm) {
let msg = format!("required by this bound in `{short_item_name}`");
multispan.push_span_label(span, msg);
- err.span_note(multispan, &descr);
+ err.span_note(multispan, descr);
} else {
- err.span_note(tcx.def_span(item_def_id), &descr);
+ err.span_note(tcx.def_span(item_def_id), descr);
}
}
- ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => {
- let (concrete_ty, concrete_file) =
- self.tcx.short_ty_string(self.resolve_vars_if_possible(concrete_ty));
- let (object_ty, object_file) =
- self.tcx.short_ty_string(self.resolve_vars_if_possible(object_ty));
- err.note(&with_forced_trimmed_paths!(format!(
- "required for the cast from `{concrete_ty}` to the object type `{object_ty}`",
+ ObligationCauseCode::Coercion { source, target } => {
+ let (source, source_file) =
+ self.tcx.short_ty_string(self.resolve_vars_if_possible(source));
+ let (target, target_file) =
+ self.tcx.short_ty_string(self.resolve_vars_if_possible(target));
+ err.note(with_forced_trimmed_paths!(format!(
+ "required for the cast from `{source}` to `{target}`",
)));
- if let Some(file) = concrete_file {
- err.note(&format!(
- "the full name for the casted type has been written to '{}'",
+ if let Some(file) = source_file {
+ err.note(format!(
+ "the full name for the source type has been written to '{}'",
file.display(),
));
}
- if let Some(file) = object_file {
- err.note(&format!(
- "the full name for the object type has been written to '{}'",
+ if let Some(file) = target_file {
+ err.note(format!(
+ "the full name for the target type has been written to '{}'",
file.display(),
));
}
}
- ObligationCauseCode::Coercion { source: _, target } => {
- err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
- }
ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
err.note(
"the `Copy` trait is required because this value will be copied for each element of the array",
@@ -3055,8 +2923,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
));
match ty.kind() {
ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
- Some(ident) => err.span_note(ident.span, &msg),
- None => err.note(&msg),
+ Some(ident) => err.span_note(ident.span, msg),
+ None => err.note(msg),
},
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// If the previous type is async fn, this is the future generated by the body of an async function.
@@ -3068,7 +2936,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"note_obligation_cause_code: check for async fn"
);
if is_future
- && obligated_types.last().map_or(false, |ty| match ty.kind() {
+ && obligated_types.last().is_some_and(|ty| match ty.kind() {
ty::Generator(last_def_id, ..) => {
tcx.generator_is_async(*last_def_id)
}
@@ -3077,7 +2945,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
break 'print;
}
- err.span_note(self.tcx.def_span(def_id), &msg)
+ err.span_note(self.tcx.def_span(def_id), msg)
}
ty::GeneratorWitness(bound_tys) => {
use std::fmt::Write;
@@ -3113,7 +2981,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let kind = tcx.generator_kind(def_id).unwrap().descr();
err.span_note(
sp,
- with_forced_trimmed_paths!(&format!(
+ with_forced_trimmed_paths!(format!(
"required because it's used within this {kind}",
)),
)
@@ -3123,7 +2991,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"required because it's used within this closure",
),
ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"),
- _ => err.note(&msg),
+ _ => err.note(msg),
};
}
}
@@ -3135,6 +3003,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
parent_predicate,
param_env,
@@ -3146,6 +3015,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} else {
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
parent_predicate,
param_env,
@@ -3177,7 +3047,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// FIXME: we should do something else so that it works even on crate foreign
// auto traits.
is_auto_trait = matches!(is_auto, hir::IsAuto::Yes);
- err.span_note(ident.span, &msg);
+ err.span_note(ident.span, msg);
}
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
@@ -3206,15 +3076,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"unsatisfied trait bound introduced here",
);
}
- err.span_note(spans, &msg);
+ err.span_note(spans, msg);
}
_ => {
- err.note(&msg);
+ err.note(msg);
}
};
if let Some(file) = file {
- err.note(&format!(
+ err.note(format!(
"the full type name has been written to '{}'",
file.display(),
));
@@ -3254,19 +3124,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
parent_trait_pred = child_trait_pred;
}
if count > 0 {
- err.note(&format!(
+ err.note(format!(
"{} redundant requirement{} hidden",
count,
pluralize!(count)
));
let (self_ty, file) =
self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty());
- err.note(&format!(
+ err.note(format!(
"required for `{self_ty}` to implement `{}`",
parent_trait_pred.print_modifiers_and_trait_path()
));
if let Some(file) = file {
- err.note(&format!(
+ err.note(format!(
"the full type name has been written to '{}'",
file.display(),
));
@@ -3275,6 +3145,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
parent_predicate,
param_env,
@@ -3290,6 +3161,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
parent_predicate,
param_env,
@@ -3306,8 +3178,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
..
} => {
self.note_function_argument_obligation(
- arg_hir_id,
+ body_id,
err,
+ arg_hir_id,
parent_code,
param_env,
predicate,
@@ -3315,6 +3188,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
predicate,
param_env,
@@ -3347,7 +3221,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
assoc_span.push_span_label(ident.span, "in this trait");
}
- err.span_note(assoc_span, &msg);
+ err.span_note(assoc_span, msg);
}
ObligationCauseCode::TrivialBound => {
err.help("see issue #48214");
@@ -3485,7 +3359,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => None,
};
let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
- trait_ref: self.tcx.mk_trait_ref(
+ trait_ref: ty::TraitRef::new(self.tcx,
trait_pred.def_id(),
[field_ty].into_iter().chain(trait_substs),
),
@@ -3503,7 +3377,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if can_derive {
err.span_suggestion_verbose(
self.tcx.def_span(adt.did()).shrink_to_lo(),
- &format!(
+ format!(
"consider annotating `{}` with `#[derive({})]`",
trait_pred.skip_binder().self_ty(),
diagnostic_name,
@@ -3536,8 +3410,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
fn note_function_argument_obligation(
&self,
- arg_hir_id: HirId,
+ body_id: LocalDefId,
err: &mut Diagnostic,
+ arg_hir_id: HirId,
parent_code: &ObligationCauseCode<'tcx>,
param_env: ty::ParamEnv<'tcx>,
failed_pred: ty::Predicate<'tcx>,
@@ -3570,7 +3445,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// to an associated type (as seen from `trait_pred`) in the predicate. Like in
// trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>`
let mut type_diffs = vec![];
-
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
&& let Some(node_substs) = typeck_results.node_substs_opt(call_hir_id)
&& let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs)
@@ -3579,14 +3453,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let Some(where_pred) = where_pred.to_opt_poly_trait_pred()
&& let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
{
- let mut c = CollectAllMismatches {
- infcx: self.infcx,
- param_env,
- errors: vec![],
+ let where_pred = self.instantiate_binder_with_placeholders(where_pred);
+ let failed_pred = self.instantiate_binder_with_fresh_vars(
+ expr.span,
+ LateBoundRegionConversionTime::FnCall,
+ failed_pred
+ );
+
+ let zipped =
+ iter::zip(where_pred.trait_ref.substs, failed_pred.trait_ref.substs);
+ for (expected, actual) in zipped {
+ self.probe(|_| {
+ match self
+ .at(&ObligationCause::misc(expr.span, body_id), param_env)
+ .eq(DefineOpaqueTypes::No, expected, actual)
+ {
+ Ok(_) => (), // We ignore nested obligations here for now.
+ Err(err) => type_diffs.push(err),
+ }
+ })
};
- if let Ok(_) = c.relate(where_pred, failed_pred) {
- type_diffs = c.errors;
- }
} else if let Some(where_pred) = where_pred.to_opt_poly_projection_pred()
&& let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
&& let Some(found) = failed_pred.skip_binder().term.ty()
@@ -3848,7 +3734,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn maybe_suggest_convert_to_slice(
&self,
err: &mut Diagnostic,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
candidate_impls: &[ImplCandidate<'tcx>],
span: Span,
) {
@@ -3890,7 +3776,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.map(|trait_ref| trait_ref.trait_ref.self_ty())
.find(|t| is_slice(*t))
{
- let msg = &format!("convert the array to a `{}` slice instead", slice_ty);
+ let msg = format!("convert the array to a `{}` slice instead", slice_ty);
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
let mut suggestions = vec![];
@@ -4103,37 +3989,6 @@ impl NextTypeParamName for &[hir::GenericParam<'_>] {
}
}
-fn suggest_trait_object_return_type_alternatives(
- err: &mut Diagnostic,
- ret_ty: Span,
- trait_obj: &str,
- is_object_safe: bool,
-) {
- err.span_suggestion(
- ret_ty,
- &format!(
- "use `impl {}` as the return type if all return paths have the same type but you \
- want to expose only the trait in the signature",
- trait_obj,
- ),
- format!("impl {}", trait_obj),
- Applicability::MaybeIncorrect,
- );
- if is_object_safe {
- err.multipart_suggestion(
- &format!(
- "use a boxed trait object if all return paths implement trait `{}`",
- trait_obj,
- ),
- vec![
- (ret_ty.shrink_to_lo(), "Box<".to_string()),
- (ret_ty.shrink_to_hi(), ">".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- }
-}
-
/// Collect the spans that we see the generic param `param_did`
struct ReplaceImplTraitVisitor<'a> {
ty_spans: &'a mut Vec<Span>,