summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_trait_selection/src
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs42
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs34
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs16
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs (renamed from compiler/rustc_trait_selection/src/solve/eval_ctxt.rs)16
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs12
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/build.rs121
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs (renamed from compiler/rustc_trait_selection/src/solve/inherent_projection.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/mod.rs (renamed from compiler/rustc_trait_selection/src/solve/project_goals.rs)101
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs (renamed from compiler/rustc_trait_selection/src/solve/opaques.rs)2
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs (renamed from compiler/rustc_trait_selection/src/solve/weak_types.rs)0
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph.rs (renamed from compiler/rustc_trait_selection/src/solve/search_graph/mod.rs)38
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs94
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs305
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs275
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs3407
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs196
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs878
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs3278
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs91
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs127
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs131
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs79
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs86
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs66
38 files changed, 5190 insertions, 4309 deletions
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 56d37d58d..5ba29f878 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -11,6 +11,9 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
#![feature(associated_type_bounds)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 23d2c0c4e..27d2bdead 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -37,6 +37,8 @@ pub(super) trait GoalKind<'tcx>:
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
+ fn polarity(self) -> ty::ImplPolarity;
+
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
@@ -191,18 +193,26 @@ pub(super) trait GoalKind<'tcx>:
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
- /// A generator (that comes from an `async` desugaring) is known to implement
- /// `Future<Output = O>`, where `O` is given by the generator's return type
+ /// A coroutine (that comes from an `async` desugaring) is known to implement
+ /// `Future<Output = O>`, where `O` is given by the coroutine's return type
/// that was computed during type-checking.
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
- /// A generator (that doesn't come from an `async` desugaring) is known to
- /// implement `Generator<R, Yield = Y, Return = O>`, given the resume, yield,
- /// and return types of the generator computed during type-checking.
- fn consider_builtin_generator_candidate(
+ /// A coroutine (that comes from a `gen` desugaring) is known to implement
+ /// `Iterator<Item = O>`, where `O` is given by the generator's yield type
+ /// that was computed during type-checking.
+ fn consider_builtin_iterator_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx>;
+
+ /// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
+ /// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
+ /// and return types of the coroutine computed during type-checking.
+ fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
@@ -410,7 +420,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
- | ty::Generator(_, _, _)
+ | ty::Coroutine(_, _, _)
| ty::Never
| ty::Tuple(_) => {
let simp =
@@ -467,9 +477,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
// FIXME: These should ideally not exist as a self type. It would be nice for
- // the builtin auto trait impls of generators to instead directly recurse
+ // the builtin auto trait impls of coroutines to instead directly recurse
// into the witness.
- ty::GeneratorWitness(..) => (),
+ ty::CoroutineWitness(..) => (),
// These variants should not exist as a self type.
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
@@ -552,8 +562,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
G::consider_builtin_pointee_candidate(self, goal)
} else if lang_items.future_trait() == Some(trait_def_id) {
G::consider_builtin_future_candidate(self, goal)
- } else if lang_items.gen_trait() == Some(trait_def_id) {
- G::consider_builtin_generator_candidate(self, goal)
+ } else if lang_items.iterator_trait() == Some(trait_def_id) {
+ G::consider_builtin_iterator_candidate(self, goal)
+ } else if lang_items.coroutine_trait() == Some(trait_def_id) {
+ G::consider_builtin_coroutine_candidate(self, goal)
} else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
G::consider_builtin_discriminant_kind_candidate(self, goal)
} else if lang_items.destruct_trait() == Some(trait_def_id) {
@@ -620,8 +632,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::FnPtr(_)
| ty::Dynamic(..)
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Param(_)
@@ -776,8 +788,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::FnPtr(_)
| ty::Alias(..)
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Param(_)
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 16f288045..839968b25 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -12,7 +12,7 @@ use crate::solve::EvalCtxt;
// Calculates the constituent types of a type for `auto trait` purposes.
//
-// For types with an "existential" binder, i.e. generator witnesses, we also
+// For types with an "existential" binder, i.e. coroutine witnesses, we also
// instantiate the binder with placeholders eagerly.
#[instrument(level = "debug", skip(ecx), ret)]
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
@@ -57,14 +57,14 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
ty::Closure(_, ref args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
- ty::Generator(_, ref args, _) => {
- let generator_args = args.as_generator();
- Ok(vec![generator_args.tupled_upvars_ty(), generator_args.witness()])
+ ty::Coroutine(_, ref args, _) => {
+ let coroutine_args = args.as_coroutine();
+ Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])
}
- ty::GeneratorWitness(def_id, args) => Ok(ecx
+ ty::CoroutineWitness(def_id, args) => Ok(ecx
.tcx()
- .generator_hidden_types(def_id)
+ .coroutine_hidden_types(def_id)
.map(|bty| {
ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
tcx,
@@ -124,8 +124,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
| ty::RawPtr(..)
| ty::Char
| ty::Ref(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Array(..)
| ty::Closure(..)
| ty::Never
@@ -177,7 +177,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
ty::Dynamic(..)
| ty::Str
| ty::Slice(_)
- | ty::Generator(_, _, Movability::Static)
+ | ty::Coroutine(_, _, Movability::Static)
| ty::Foreign(..)
| ty::Ref(_, _, Mutability::Mut)
| ty::Adt(_, _)
@@ -194,18 +194,18 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
- ty::Generator(_, args, Movability::Movable) => {
- if ecx.tcx().features().generator_clone {
- let generator = args.as_generator();
- Ok(vec![generator.tupled_upvars_ty(), generator.witness()])
+ ty::Coroutine(_, args, Movability::Movable) => {
+ if ecx.tcx().features().coroutine_clone {
+ let coroutine = args.as_coroutine();
+ Ok(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])
} else {
Err(NoSolution)
}
}
- ty::GeneratorWitness(def_id, args) => Ok(ecx
+ ty::CoroutineWitness(def_id, args) => Ok(ecx
.tcx()
- .generator_hidden_types(def_id)
+ .coroutine_hidden_types(def_id)
.map(|bty| {
ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
ecx.tcx(),
@@ -278,8 +278,8 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
| ty::RawPtr(_)
| ty::Ref(_, _, _)
| ty::Dynamic(_, _, _)
- | ty::Generator(_, _, _)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(_, _, _)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Alias(_, _)
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index aa92b924e..377ae1b4e 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -224,12 +224,20 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
let kind = match *r {
ty::ReLateBound(..) => return r,
- ty::ReStatic => match self.canonicalize_mode {
+ // We may encounter `ReStatic` in item signatures or the hidden type
+ // of an opaque. `ReErased` should only be encountered in the hidden
+ // type of an opaque for regions that are ignored for the purposes of
+ // captures.
+ //
+ // FIXME: We should investigate the perf implications of not uniquifying
+ // `ReErased`. We may be able to short-circuit registering region
+ // obligations if we encounter a `ReErased` on one side, for example.
+ ty::ReStatic | ty::ReErased => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Response { .. } => return r,
},
- ty::ReErased | ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode {
+ ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"),
},
@@ -329,8 +337,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
- | ty::Generator(_, _, _)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(_, _, _)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Alias(_, _)
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 066129d8e..70235b710 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -119,25 +119,11 @@ impl NestedGoals<'_> {
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
pub enum GenerateProofTree {
- Yes(UseGlobalCache),
+ Yes,
IfEnabled,
Never,
}
-#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
-pub enum UseGlobalCache {
- Yes,
- No,
-}
-impl UseGlobalCache {
- pub fn from_bool(use_cache: bool) -> Self {
- match use_cache {
- true => UseGlobalCache::Yes,
- false => UseGlobalCache::No,
- }
- }
-}
-
pub trait InferCtxtEvalExt<'tcx> {
/// Evaluates a goal from **outside** of the trait solver.
///
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 15c8d9e5b..69bfdd468 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -17,7 +17,7 @@ use rustc_middle::traits::solve::{Certainty, Goal};
use rustc_middle::ty;
use crate::solve::inspect::ProofTreeBuilder;
-use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache};
+use crate::solve::{GenerateProofTree, InferCtxtEvalExt};
pub struct InspectGoal<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
@@ -82,8 +82,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
}
for &goal in &instantiated_goals {
- let (_, proof_tree) =
- infcx.evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No));
+ let (_, proof_tree) = infcx.evaluate_root_goal(goal, GenerateProofTree::Yes);
let proof_tree = proof_tree.unwrap();
visitor.visit_goal(&InspectGoal::new(
infcx,
@@ -169,11 +168,11 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
let mut candidates = vec![];
let last_eval_step = match self.evaluation.evaluation.kind {
inspect::CanonicalGoalEvaluationKind::Overflow
- | inspect::CanonicalGoalEvaluationKind::CacheHit(_) => {
+ | inspect::CanonicalGoalEvaluationKind::CycleInStack => {
warn!("unexpected root evaluation: {:?}", self.evaluation);
return vec![];
}
- inspect::CanonicalGoalEvaluationKind::Uncached { ref revisions } => {
+ inspect::CanonicalGoalEvaluationKind::Evaluation { ref revisions } => {
if let Some(last) = revisions.last() {
last
} else {
@@ -227,8 +226,7 @@ impl<'tcx> ProofTreeInferCtxtExt<'tcx> for InferCtxt<'tcx> {
goal: Goal<'tcx, ty::Predicate<'tcx>>,
visitor: &mut V,
) -> ControlFlow<V::BreakTy> {
- let (_, proof_tree) =
- self.evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No));
+ let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes);
let proof_tree = proof_tree.unwrap();
visitor.visit_goal(&InspectGoal::new(self, 0, &proof_tree))
}
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index 2eba98b02..088455b38 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -3,6 +3,8 @@
//! This code is *a bit* of a mess and can hopefully be
//! mostly ignored. For a general overview of how it works,
//! see the comment on [ProofTreeBuilder].
+use std::mem;
+
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{
CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult,
@@ -10,7 +12,6 @@ use rustc_middle::traits::solve::{
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::DumpSolverProofTree;
-use crate::solve::eval_ctxt::UseGlobalCache;
use crate::solve::{self, inspect, EvalCtxt, GenerateProofTree};
/// The core data structure when building proof trees.
@@ -34,12 +35,7 @@ use crate::solve::{self, inspect, EvalCtxt, GenerateProofTree};
/// is called to recursively convert the whole structure to a
/// finished proof tree.
pub(in crate::solve) struct ProofTreeBuilder<'tcx> {
- state: Option<Box<BuilderData<'tcx>>>,
-}
-
-struct BuilderData<'tcx> {
- tree: DebugSolver<'tcx>,
- use_global_cache: UseGlobalCache,
+ state: Option<Box<DebugSolver<'tcx>>>,
}
/// The current state of the proof tree builder, at most places
@@ -118,36 +114,46 @@ pub(in crate::solve) enum WipGoalEvaluationKind<'tcx> {
Nested { is_normalizes_to_hack: IsNormalizesToHack },
}
-#[derive(Eq, PartialEq, Debug)]
-pub(in crate::solve) enum WipCanonicalGoalEvaluationKind {
+#[derive(Eq, PartialEq)]
+pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<'tcx> {
Overflow,
- CacheHit(inspect::CacheHit),
+ CycleInStack,
+ Interned { revisions: &'tcx [inspect::GoalEvaluationStep<'tcx>] },
+}
+
+impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Overflow => write!(f, "Overflow"),
+ Self::CycleInStack => write!(f, "CycleInStack"),
+ Self::Interned { revisions: _ } => f.debug_struct("Interned").finish_non_exhaustive(),
+ }
+ }
}
#[derive(Eq, PartialEq, Debug)]
struct WipCanonicalGoalEvaluation<'tcx> {
goal: CanonicalInput<'tcx>,
- kind: Option<WipCanonicalGoalEvaluationKind>,
+ kind: Option<WipCanonicalGoalEvaluationKind<'tcx>>,
+ /// Only used for uncached goals. After we finished evaluating
+ /// the goal, this is interned and moved into `kind`.
revisions: Vec<WipGoalEvaluationStep<'tcx>>,
result: Option<QueryResult<'tcx>>,
}
impl<'tcx> WipCanonicalGoalEvaluation<'tcx> {
fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> {
- let kind = match self.kind {
- Some(WipCanonicalGoalEvaluationKind::Overflow) => {
+ assert!(self.revisions.is_empty());
+ let kind = match self.kind.unwrap() {
+ WipCanonicalGoalEvaluationKind::Overflow => {
inspect::CanonicalGoalEvaluationKind::Overflow
}
- Some(WipCanonicalGoalEvaluationKind::CacheHit(hit)) => {
- inspect::CanonicalGoalEvaluationKind::CacheHit(hit)
+ WipCanonicalGoalEvaluationKind::CycleInStack => {
+ inspect::CanonicalGoalEvaluationKind::CycleInStack
+ }
+ WipCanonicalGoalEvaluationKind::Interned { revisions } => {
+ inspect::CanonicalGoalEvaluationKind::Evaluation { revisions }
}
- None => inspect::CanonicalGoalEvaluationKind::Uncached {
- revisions: self
- .revisions
- .into_iter()
- .map(WipGoalEvaluationStep::finalize)
- .collect(),
- },
};
inspect::CanonicalGoalEvaluation { goal: self.goal, kind, result: self.result.unwrap() }
@@ -226,33 +232,20 @@ impl<'tcx> WipProbeStep<'tcx> {
}
impl<'tcx> ProofTreeBuilder<'tcx> {
- fn new(
- state: impl Into<DebugSolver<'tcx>>,
- use_global_cache: UseGlobalCache,
- ) -> ProofTreeBuilder<'tcx> {
- ProofTreeBuilder {
- state: Some(Box::new(BuilderData { tree: state.into(), use_global_cache })),
- }
+ fn new(state: impl Into<DebugSolver<'tcx>>) -> ProofTreeBuilder<'tcx> {
+ ProofTreeBuilder { state: Some(Box::new(state.into())) }
}
fn nested<T: Into<DebugSolver<'tcx>>>(&self, state: impl FnOnce() -> T) -> Self {
- match &self.state {
- Some(prev_state) => Self {
- state: Some(Box::new(BuilderData {
- tree: state().into(),
- use_global_cache: prev_state.use_global_cache,
- })),
- },
- None => Self { state: None },
- }
+ ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) }
}
fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> {
- self.state.as_mut().map(|boxed| &mut boxed.tree)
+ self.state.as_deref_mut()
}
pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> {
- match self.state?.tree {
+ match *self.state? {
DebugSolver::GoalEvaluation(wip_goal_evaluation) => {
Some(wip_goal_evaluation.finalize())
}
@@ -260,13 +253,6 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
}
}
- pub fn use_global_cache(&self) -> bool {
- self.state
- .as_ref()
- .map(|state| matches!(state.use_global_cache, UseGlobalCache::Yes))
- .unwrap_or(true)
- }
-
pub fn new_maybe_root(
tcx: TyCtxt<'tcx>,
generate_proof_tree: GenerateProofTree,
@@ -276,10 +262,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
GenerateProofTree::IfEnabled => {
let opts = &tcx.sess.opts.unstable_opts;
match opts.dump_solver_proof_tree {
- DumpSolverProofTree::Always => {
- let use_cache = opts.dump_solver_proof_tree_use_cache.unwrap_or(true);
- ProofTreeBuilder::new_root(UseGlobalCache::from_bool(use_cache))
- }
+ DumpSolverProofTree::Always => ProofTreeBuilder::new_root(),
// `OnError` is handled by reevaluating goals in error
// reporting with `GenerateProofTree::Yes`.
DumpSolverProofTree::OnError | DumpSolverProofTree::Never => {
@@ -287,12 +270,12 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
}
}
}
- GenerateProofTree::Yes(use_cache) => ProofTreeBuilder::new_root(use_cache),
+ GenerateProofTree::Yes => ProofTreeBuilder::new_root(),
}
}
- pub fn new_root(use_global_cache: UseGlobalCache) -> ProofTreeBuilder<'tcx> {
- ProofTreeBuilder::new(DebugSolver::Root, use_global_cache)
+ pub fn new_root() -> ProofTreeBuilder<'tcx> {
+ ProofTreeBuilder::new(DebugSolver::Root)
}
pub fn new_noop() -> ProofTreeBuilder<'tcx> {
@@ -336,9 +319,27 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
})
}
+ pub fn finalize_evaluation(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ ) -> Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]> {
+ self.as_mut().map(|this| match this {
+ DebugSolver::CanonicalGoalEvaluation(evaluation) => {
+ let revisions = mem::take(&mut evaluation.revisions)
+ .into_iter()
+ .map(WipGoalEvaluationStep::finalize);
+ let revisions = &*tcx.arena.alloc_from_iter(revisions);
+ let kind = WipCanonicalGoalEvaluationKind::Interned { revisions };
+ assert_eq!(evaluation.kind.replace(kind), None);
+ revisions
+ }
+ _ => unreachable!(),
+ })
+ }
+
pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() {
- match (this, canonical_goal_evaluation.state.unwrap().tree) {
+ match (this, *canonical_goal_evaluation.state.unwrap()) {
(
DebugSolver::GoalEvaluation(goal_evaluation),
DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation),
@@ -348,7 +349,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
}
}
- pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind) {
+ pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<'tcx>) {
if let Some(this) = self.as_mut() {
match this {
DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
@@ -372,7 +373,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
}
pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() {
- match (this, goal_evaluation.state.unwrap().tree) {
+ match (this, *goal_evaluation.state.unwrap()) {
(
DebugSolver::AddedGoalsEvaluation(WipAddedGoalsEvaluation {
evaluations, ..
@@ -396,7 +397,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
}
pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() {
- match (this, goal_evaluation_step.state.unwrap().tree) {
+ match (this, *goal_evaluation_step.state.unwrap()) {
(
DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluations),
DebugSolver::GoalEvaluationStep(goal_evaluation_step),
@@ -444,7 +445,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
pub fn finish_probe(&mut self, probe: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() {
- match (this, probe.state.unwrap().tree) {
+ match (this, *probe.state.unwrap()) {
(
DebugSolver::Probe(WipProbe { steps, .. })
| DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
@@ -486,7 +487,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
pub fn added_goals_evaluation(&mut self, added_goals_evaluation: ProofTreeBuilder<'tcx>) {
if let Some(this) = self.as_mut() {
- match (this, added_goals_evaluation.state.unwrap().tree) {
+ match (this, *added_goals_evaluation.state.unwrap()) {
(
DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep {
evaluation: WipProbe { steps, .. },
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 77a3b5e12..dba5369fa 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -32,18 +32,13 @@ mod assembly;
mod canonicalize;
mod eval_ctxt;
mod fulfill;
-mod inherent_projection;
pub mod inspect;
mod normalize;
-mod opaques;
mod project_goals;
mod search_graph;
mod trait_goals;
-mod weak_types;
-pub use eval_ctxt::{
- EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache,
-};
+pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt};
pub use fulfill::FulfillmentCtxt;
pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index 872f0c879..b0a348985 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -129,7 +129,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
self.at.cause.clone(),
self.at.param_env,
ty::ProjectionPredicate {
- projection_ty: tcx.mk_alias_ty(uv.def, uv.args),
+ projection_ty: AliasTy::new(tcx, uv.def, uv.args),
term: new_infer_ct.into(),
},
);
diff --git a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs
index 28fe59b7f..28fe59b7f 100644
--- a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
index 0f9d36342..240141065 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs
@@ -18,6 +18,10 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
+mod inherent_projection;
+mod opaques;
+mod weak_types;
+
impl<'tcx> EvalCtxt<'_, 'tcx> {
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn compute_projection_goal(
@@ -97,6 +101,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
self.projection_ty.trait_ref(tcx)
}
+ fn polarity(self) -> ty::ImplPolarity {
+ ty::ImplPolarity::Positive
+ }
+
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
self.with_self_ty(tcx, self_ty)
}
@@ -346,14 +354,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
});
- let pred = ty::Clause::from_projection_clause(
- tcx,
- tupled_inputs_and_output.map_bound(|(inputs, output)| ty::ProjectionPredicate {
- projection_ty: tcx
- .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]),
+ let pred = tupled_inputs_and_output
+ .map_bound(|(inputs, output)| ty::ProjectionPredicate {
+ projection_ty: ty::AliasTy::new(
+ tcx,
+ goal.predicate.def_id(),
+ [goal.predicate.self_ty(), inputs],
+ ),
term: output.into(),
- }),
- );
+ })
+ .to_predicate(tcx);
// A built-in `Fn` impl only holds if the output is sized.
// (FIXME: technically we only need to check this if the type is a fn ptr...)
@@ -386,8 +396,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
| ty::FnPtr(..)
| ty::Closure(..)
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Foreign(..) => tcx.types.unit,
@@ -453,70 +463,103 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
let self_ty = goal.predicate.self_ty();
- let ty::Generator(def_id, args, _) = *self_ty.kind() else {
+ let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
return Err(NoSolution);
};
- // Generators are not futures unless they come from `async` desugaring
+ // Coroutines are not futures unless they come from `async` desugaring
let tcx = ecx.tcx();
- if !tcx.generator_is_async(def_id) {
+ if !tcx.coroutine_is_async(def_id) {
return Err(NoSolution);
}
- let term = args.as_generator().return_ty().into();
+ let term = args.as_coroutine().return_ty().into();
Self::consider_implied_clause(
ecx,
goal,
ty::ProjectionPredicate {
- projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]),
+ projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
term,
}
.to_predicate(tcx),
// Technically, we need to check that the future type is Sized,
+ // but that's already proven by the coroutine being WF.
+ [],
+ )
+ }
+
+ fn consider_builtin_iterator_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx> {
+ let self_ty = goal.predicate.self_ty();
+ let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
+ return Err(NoSolution);
+ };
+
+ // Coroutines are not Iterators unless they come from `gen` desugaring
+ let tcx = ecx.tcx();
+ if !tcx.coroutine_is_gen(def_id) {
+ return Err(NoSolution);
+ }
+
+ let term = args.as_coroutine().yield_ty().into();
+
+ Self::consider_implied_clause(
+ ecx,
+ goal,
+ ty::ProjectionPredicate {
+ projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
+ term,
+ }
+ .to_predicate(tcx),
+ // Technically, we need to check that the iterator type is Sized,
// but that's already proven by the generator being WF.
[],
)
}
- fn consider_builtin_generator_candidate(
+ fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
let self_ty = goal.predicate.self_ty();
- let ty::Generator(def_id, args, _) = *self_ty.kind() else {
+ let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
return Err(NoSolution);
};
- // `async`-desugared generators do not implement the generator trait
+ // `async`-desugared coroutines do not implement the coroutine trait
let tcx = ecx.tcx();
- if tcx.generator_is_async(def_id) {
+ if !tcx.is_general_coroutine(def_id) {
return Err(NoSolution);
}
- let generator = args.as_generator();
+ let coroutine = args.as_coroutine();
let name = tcx.associated_item(goal.predicate.def_id()).name;
let term = if name == sym::Return {
- generator.return_ty().into()
+ coroutine.return_ty().into()
} else if name == sym::Yield {
- generator.yield_ty().into()
+ coroutine.yield_ty().into()
} else {
- bug!("unexpected associated item `<{self_ty} as Generator>::{name}`")
+ bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`")
};
Self::consider_implied_clause(
ecx,
goal,
ty::ProjectionPredicate {
- projection_ty: ecx
- .tcx()
- .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
+ projection_ty: ty::AliasTy::new(
+ ecx.tcx(),
+ goal.predicate.def_id(),
+ [self_ty, coroutine.resume_ty()],
+ ),
term,
}
.to_predicate(tcx),
- // Technically, we need to check that the future type is Sized,
- // but that's already proven by the generator being WF.
+ // Technically, we need to check that the coroutine type is Sized,
+ // but that's already proven by the coroutine being WF.
[],
)
}
@@ -553,8 +596,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
| ty::FnPtr(..)
| ty::Closure(..)
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Foreign(..)
| ty::Adt(_, _)
diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs
index f08adc020..ebd129f32 100644
--- a/compiler/rustc_trait_selection/src/solve/opaques.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs
@@ -7,7 +7,7 @@ use rustc_middle::traits::Reveal;
use rustc_middle::ty;
use rustc_middle::ty::util::NotUniqueParam;
-use super::{EvalCtxt, SolverMode};
+use crate::solve::{EvalCtxt, SolverMode};
impl<'tcx> EvalCtxt<'_, 'tcx> {
pub(super) fn normalize_opaque_type(
diff --git a/compiler/rustc_trait_selection/src/solve/weak_types.rs b/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs
index 54de32cf6..54de32cf6 100644
--- a/compiler/rustc_trait_selection/src/solve/weak_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs
index 33513f6bd..7ffa1d7d3 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs
@@ -6,7 +6,6 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_index::Idx;
use rustc_index::IndexVec;
use rustc_middle::dep_graph::dep_kinds;
-use rustc_middle::traits::solve::inspect::CacheHit;
use rustc_middle::traits::solve::CacheData;
use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
use rustc_middle::ty::TyCtxt;
@@ -191,8 +190,8 @@ impl<'tcx> SearchGraph<'tcx> {
};
// Try to fetch the goal from the global cache.
- if inspect.use_global_cache() {
- if let Some(CacheData { result, reached_depth, encountered_overflow }) =
+ 'global: {
+ let Some(CacheData { result, proof_tree, reached_depth, encountered_overflow }) =
self.global_cache(tcx).get(
tcx,
input,
@@ -201,13 +200,26 @@ impl<'tcx> SearchGraph<'tcx> {
},
available_depth,
)
- {
- inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit(
- CacheHit::Global,
- ));
- self.on_cache_hit(reached_depth, encountered_overflow);
- return result;
+ else {
+ break 'global;
+ };
+
+ // If we're building a proof tree and the current cache entry does not
+ // contain a proof tree, we do not use the entry but instead recompute
+ // the goal. We simply overwrite the existing entry once we're done,
+ // caching the proof tree.
+ if !inspect.is_noop() {
+ if let Some(revisions) = proof_tree {
+ inspect.goal_evaluation_kind(
+ inspect::WipCanonicalGoalEvaluationKind::Interned { revisions },
+ );
+ } else {
+ break 'global;
+ }
}
+
+ self.on_cache_hit(reached_depth, encountered_overflow);
+ return result;
}
// Check whether we're in a cycle.
@@ -238,9 +250,7 @@ impl<'tcx> SearchGraph<'tcx> {
// Finally we can return either the provisional response for that goal if we have a
// coinductive cycle or an ambiguous result if the cycle is inductive.
Entry::Occupied(entry) => {
- inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit(
- CacheHit::Provisional,
- ));
+ inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CycleInStack);
let stack_depth = *entry.get();
debug!("encountered cycle with depth {stack_depth:?}");
@@ -329,6 +339,8 @@ impl<'tcx> SearchGraph<'tcx> {
(current_entry, result)
});
+ let proof_tree = inspect.finalize_evaluation(tcx);
+
// We're now done with this goal. In case this goal is involved in a larger cycle
// do not remove it from the provisional cache and update its provisional result.
// We only add the root of cycles to the global cache.
@@ -346,7 +358,9 @@ impl<'tcx> SearchGraph<'tcx> {
// more details.
let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len();
self.global_cache(tcx).insert(
+ tcx,
input,
+ proof_tree,
reached_depth,
final_entry.encountered_overflow,
final_entry.cycle_participants,
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 8055c63b9..a0e2ad6e2 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -22,6 +22,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
self.trait_ref
}
+ fn polarity(self) -> ty::ImplPolarity {
+ self.polarity
+ }
+
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
self.with_self_ty(tcx, self_ty)
}
@@ -136,12 +140,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
// `assemble_candidates_after_normalizing_self_ty`, and we'd
// just be registering an identical candidate here.
//
- // Returning `Err(NoSolution)` here is ok in `SolverMode::Coherence`
- // since we'll always be registering an ambiguous candidate in
+ // We always return `Err(NoSolution)` here in `SolverMode::Coherence`
+ // since we'll always register an ambiguous candidate in
// `assemble_candidates_after_normalizing_self_ty` due to normalizing
// the TAIT.
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
if matches!(goal.param_env.reveal(), Reveal::All)
+ || matches!(ecx.solver_mode(), SolverMode::Coherence)
|| opaque_ty
.def_id
.as_local()
@@ -237,14 +242,25 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
- if goal.predicate.polarity != ty::ImplPolarity::Positive {
- return Err(NoSolution);
- }
-
- if let ty::FnPtr(..) = goal.predicate.self_ty().kind() {
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- } else {
- Err(NoSolution)
+ let self_ty = goal.predicate.self_ty();
+ match goal.predicate.polarity {
+ ty::ImplPolarity::Positive => {
+ if self_ty.is_fn_ptr() {
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ } else {
+ Err(NoSolution)
+ }
+ }
+ ty::ImplPolarity::Negative => {
+ // If a type is rigid and not a fn ptr, then we know for certain
+ // that it does *not* implement `FnPtr`.
+ if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ } else {
+ Err(NoSolution)
+ }
+ }
+ ty::ImplPolarity::Reservation => bug!(),
}
}
@@ -318,23 +334,47 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
return Err(NoSolution);
}
- let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
+ let ty::Coroutine(def_id, _, _) = *goal.predicate.self_ty().kind() else {
return Err(NoSolution);
};
- // Generators are not futures unless they come from `async` desugaring
+ // Coroutines are not futures unless they come from `async` desugaring
let tcx = ecx.tcx();
- if !tcx.generator_is_async(def_id) {
+ if !tcx.coroutine_is_async(def_id) {
return Err(NoSolution);
}
- // Async generator unconditionally implement `Future`
+ // Async coroutine unconditionally implement `Future`
// Technically, we need to check that the future output type is Sized,
- // but that's already proven by the generator being WF.
+ // but that's already proven by the coroutine being WF.
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+
+ fn consider_builtin_iterator_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ ) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
+ let ty::Coroutine(def_id, _, _) = *goal.predicate.self_ty().kind() else {
+ return Err(NoSolution);
+ };
+
+ // Coroutines are not iterators unless they come from `gen` desugaring
+ let tcx = ecx.tcx();
+ if !tcx.coroutine_is_gen(def_id) {
+ return Err(NoSolution);
+ }
+
+ // Gen coroutines unconditionally implement `Iterator`
+ // Technically, we need to check that the iterator output type is Sized,
+ // but that's already proven by the coroutines being WF.
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
- fn consider_builtin_generator_candidate(
+ fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
@@ -343,24 +383,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
let self_ty = goal.predicate.self_ty();
- let ty::Generator(def_id, args, _) = *self_ty.kind() else {
+ let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
return Err(NoSolution);
};
- // `async`-desugared generators do not implement the generator trait
+ // `async`-desugared coroutines do not implement the coroutine trait
let tcx = ecx.tcx();
- if tcx.generator_is_async(def_id) {
+ if !tcx.is_general_coroutine(def_id) {
return Err(NoSolution);
}
- let generator = args.as_generator();
+ let coroutine = args.as_coroutine();
Self::consider_implied_clause(
ecx,
goal,
- ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, generator.resume_ty()])
+ ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
.to_predicate(tcx),
- // Technically, we need to check that the generator types are Sized,
- // but that's already proven by the generator being WF.
+ // Technically, we need to check that the coroutine types are Sized,
+ // but that's already proven by the coroutine being WF.
[],
)
}
@@ -843,10 +883,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
- // Generators have one special built-in candidate, `Unpin`, which
+ // Coroutines have one special built-in candidate, `Unpin`, which
// takes precedence over the structural auto trait candidate being
// assembled.
- ty::Generator(_, _, movability)
+ ty::Coroutine(_, _, movability)
if Some(goal.predicate.def_id()) == self.tcx().lang_items().unpin_trait() =>
{
match movability {
@@ -878,8 +918,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Closure(_, _)
- | ty::Generator(_, _, _)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(_, _, _)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Adt(_, _)
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index acab4498a..dcf5fd869 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -9,20 +9,18 @@ use crate::infer::InferOk;
use crate::solve::inspect;
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
use crate::traits::engine::TraitEngineExt;
-use crate::traits::outlives_bounds::InferCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs};
use crate::traits::structural_normalize::StructurallyNormalizeExt;
-use crate::traits::util::impl_subject_and_oblig;
use crate::traits::NormalizeExt;
use crate::traits::SkipLeakCheck;
use crate::traits::{
- self, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
+ Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations,
SelectionContext,
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{util, TraitEngine};
use rustc_middle::traits::query::NoSolution;
@@ -32,12 +30,11 @@ use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE;
use rustc_span::symbol::sym;
use rustc_span::DUMMY_SP;
use std::fmt::Debug;
-use std::iter;
use std::ops::ControlFlow;
/// Whether we do the orphan check relative to this crate or
@@ -142,16 +139,13 @@ pub fn overlapping_impls(
Some(overlap)
}
-fn with_fresh_ty_vars<'cx, 'tcx>(
- selcx: &mut SelectionContext<'cx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- impl_def_id: DefId,
-) -> ty::ImplHeader<'tcx> {
- let tcx = selcx.tcx();
- let impl_args = selcx.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
+fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ty::ImplHeader<'tcx> {
+ let tcx = infcx.tcx;
+ let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
- let header = ty::ImplHeader {
+ ty::ImplHeader {
impl_def_id,
+ impl_args,
self_ty: tcx.type_of(impl_def_id).instantiate(tcx, impl_args),
trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.instantiate(tcx, impl_args)),
predicates: tcx
@@ -160,10 +154,18 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
.iter()
.map(|(c, _)| c.as_predicate())
.collect(),
- };
+ }
+}
+
+fn fresh_impl_header_normalized<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ impl_def_id: DefId,
+) -> ty::ImplHeader<'tcx> {
+ let header = fresh_impl_header(infcx, impl_def_id);
let InferOk { value: mut header, obligations } =
- selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
+ infcx.at(&ObligationCause::dummy(), param_env).normalize(header);
header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
header
@@ -206,12 +208,13 @@ fn overlap<'tcx>(
// empty environment.
let param_env = ty::ParamEnv::empty();
- let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
- let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
+ let impl1_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl1_def_id);
+ let impl2_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl2_def_id);
// Equate the headers to find their intersection (the general type, with infer vars,
// that may apply both impls).
- let mut obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?;
+ let mut obligations =
+ equate_impl_headers(selcx.infcx, param_env, &impl1_header, &impl2_header)?;
debug!("overlap: unification check succeeded");
obligations.extend(
@@ -312,20 +315,22 @@ fn overlap<'tcx>(
#[instrument(level = "debug", skip(infcx), ret)]
fn equate_impl_headers<'tcx>(
infcx: &InferCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
impl1: &ty::ImplHeader<'tcx>,
impl2: &ty::ImplHeader<'tcx>,
) -> Option<PredicateObligations<'tcx>> {
- let result = match (impl1.trait_ref, impl2.trait_ref) {
- (Some(impl1_ref), Some(impl2_ref)) => infcx
- .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
- .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
- (None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
- DefineOpaqueTypes::Yes,
- impl1.self_ty,
- impl2.self_ty,
- ),
- _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
- };
+ let result =
+ match (impl1.trait_ref, impl2.trait_ref) {
+ (Some(impl1_ref), Some(impl2_ref)) => infcx
+ .at(&ObligationCause::dummy(), param_env)
+ .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref),
+ (None, None) => infcx.at(&ObligationCause::dummy(), param_env).eq(
+ DefineOpaqueTypes::Yes,
+ impl1.self_ty,
+ impl2.self_ty,
+ ),
+ _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
+ };
result.map(|infer_ok| infer_ok.obligations).ok()
}
@@ -391,107 +396,182 @@ fn impl_intersection_has_negative_obligation(
) -> bool {
debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
- // Create an infcx, taking the predicates of impl1 as assumptions:
- let infcx = tcx.infer_ctxt().build();
- // create a parameter environment corresponding to a (placeholder) instantiation of impl1
- let impl_env = tcx.param_env(impl1_def_id);
- let subject1 = match traits::fully_normalize(
- &infcx,
- ObligationCause::dummy(),
- impl_env,
- tcx.impl_subject(impl1_def_id).instantiate_identity(),
- ) {
- Ok(s) => s,
- Err(err) => {
- tcx.sess.delay_span_bug(
- tcx.def_span(impl1_def_id),
- format!("failed to fully normalize {impl1_def_id:?}: {err:?}"),
- );
- return false;
- }
- };
+ let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build();
+ let universe = infcx.universe();
- // Attempt to prove that impl2 applies, given all of the above.
- let selcx = &mut SelectionContext::new(&infcx);
- let impl2_args = infcx.fresh_args_for_item(DUMMY_SP, impl2_def_id);
- let (subject2, normalization_obligations) =
- impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_args, |_, _| {
- ObligationCause::dummy()
- });
-
- // do the impls unify? If not, then it's not currently possible to prove any
- // obligations about their intersection.
- let Ok(InferOk { obligations: equate_obligations, .. }) =
- infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No, subject1, subject2)
+ let impl1_header = fresh_impl_header(infcx, impl1_def_id);
+ let param_env =
+ ty::EarlyBinder::bind(tcx.param_env(impl1_def_id)).instantiate(tcx, impl1_header.impl_args);
+
+ let impl2_header = fresh_impl_header(infcx, impl2_def_id);
+
+ // Equate the headers to find their intersection (the general type, with infer vars,
+ // that may apply both impls).
+ let Some(_equate_obligations) =
+ equate_impl_headers(infcx, param_env, &impl1_header, &impl2_header)
else {
- debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
return false;
};
- for obligation in normalization_obligations.into_iter().chain(equate_obligations) {
- if negative_impl_exists(&infcx, &obligation, impl1_def_id) {
- debug!("overlap: obligation unsatisfiable {:?}", obligation);
- return true;
- }
- }
+ plug_infer_with_placeholders(infcx, universe, (impl1_header.impl_args, impl2_header.impl_args));
- false
+ util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args))
+ .any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env))
}
-/// Try to prove that a negative impl exist for the obligation or its supertraits.
-///
-/// If such a negative impl exists, then the obligation definitely must not hold
-/// due to coherence, even if it's not necessarily "knowable" in this crate. Any
-/// valid impl downstream would not be able to exist due to the overlapping
-/// negative impl.
-#[instrument(level = "debug", skip(infcx))]
-fn negative_impl_exists<'tcx>(
+fn plug_infer_with_placeholders<'tcx>(
infcx: &InferCtxt<'tcx>,
- o: &PredicateObligation<'tcx>,
- body_def_id: DefId,
-) -> bool {
- // Try to prove a negative obligation exists for super predicates
- for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) {
- if prove_negated_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) {
- return true;
+ universe: ty::UniverseIndex,
+ value: impl TypeVisitable<TyCtxt<'tcx>>,
+) {
+ struct PlugInferWithPlaceholder<'a, 'tcx> {
+ infcx: &'a InferCtxt<'tcx>,
+ universe: ty::UniverseIndex,
+ var: ty::BoundVar,
+ }
+
+ impl<'tcx> PlugInferWithPlaceholder<'_, 'tcx> {
+ fn next_var(&mut self) -> ty::BoundVar {
+ let var = self.var;
+ self.var = self.var + 1;
+ var
+ }
+ }
+
+ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlugInferWithPlaceholder<'_, 'tcx> {
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let ty = self.infcx.shallow_resolve(ty);
+ if ty.is_ty_var() {
+ let Ok(InferOk { value: (), obligations }) =
+ self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+ DefineOpaqueTypes::No,
+ ty,
+ Ty::new_placeholder(
+ self.infcx.tcx,
+ ty::Placeholder {
+ universe: self.universe,
+ bound: ty::BoundTy {
+ var: self.next_var(),
+ kind: ty::BoundTyKind::Anon,
+ },
+ },
+ ),
+ )
+ else {
+ bug!()
+ };
+ assert_eq!(obligations, &[]);
+ ControlFlow::Continue(())
+ } else {
+ ty.super_visit_with(self)
+ }
+ }
+
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let ct = self.infcx.shallow_resolve(ct);
+ if ct.is_ct_infer() {
+ let Ok(InferOk { value: (), obligations }) =
+ self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+ DefineOpaqueTypes::No,
+ ct,
+ ty::Const::new_placeholder(
+ self.infcx.tcx,
+ ty::Placeholder { universe: self.universe, bound: self.next_var() },
+ ct.ty(),
+ ),
+ )
+ else {
+ bug!()
+ };
+ assert_eq!(obligations, &[]);
+ ControlFlow::Continue(())
+ } else {
+ ct.super_visit_with(self)
+ }
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ReVar(vid) = *r {
+ let r = self
+ .infcx
+ .inner
+ .borrow_mut()
+ .unwrap_region_constraints()
+ .opportunistic_resolve_var(self.infcx.tcx, vid);
+ if r.is_var() {
+ let Ok(InferOk { value: (), obligations }) =
+ self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq(
+ DefineOpaqueTypes::No,
+ r,
+ ty::Region::new_placeholder(
+ self.infcx.tcx,
+ ty::Placeholder {
+ universe: self.universe,
+ bound: ty::BoundRegion {
+ var: self.next_var(),
+ kind: ty::BoundRegionKind::BrAnon,
+ },
+ },
+ ),
+ )
+ else {
+ bug!()
+ };
+ assert_eq!(obligations, &[]);
+ }
+ }
+ ControlFlow::Continue(())
}
}
- false
+ value.visit_with(&mut PlugInferWithPlaceholder {
+ infcx,
+ universe,
+ var: ty::BoundVar::from_u32(0),
+ });
}
-#[instrument(level = "debug", skip(infcx))]
-fn prove_negated_obligation<'tcx>(
- infcx: InferCtxt<'tcx>,
- o: &PredicateObligation<'tcx>,
- body_def_id: DefId,
+fn try_prove_negated_where_clause<'tcx>(
+ root_infcx: &InferCtxt<'tcx>,
+ clause: ty::Clause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
) -> bool {
- let tcx = infcx.tcx;
-
- let Some(o) = o.flip_polarity(tcx) else {
+ let Some(negative_predicate) = clause.as_predicate().flip_polarity(root_infcx.tcx) else {
return false;
};
- let param_env = o.param_env;
- let ocx = ObligationCtxt::new(&infcx);
- ocx.register_obligation(o);
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
+ // FIXME(with_negative_coherence): the infcx has region contraints from equating
+ // the impl headers as requirements. Given that the only region constraints we
+ // get are involving inference regions in the root, it shouldn't matter, but
+ // still sus.
+ //
+ // We probably should just throw away the region obligations registered up until
+ // now, or ideally use them as assumptions when proving the region obligations
+ // that we get from proving the negative predicate below.
+ let ref infcx = root_infcx.fork();
+ let ocx = ObligationCtxt::new(infcx);
+
+ ocx.register_obligation(Obligation::new(
+ infcx.tcx,
+ ObligationCause::dummy(),
+ param_env,
+ negative_predicate,
+ ));
+ if !ocx.select_all_or_error().is_empty() {
return false;
}
- let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID);
+ // FIXME: We could use the assumed_wf_types from both impls, I think,
+ // if that wasn't implemented just for LocalDefId, and we'd need to do
+ // the normalization ourselves since this is totally fallible...
+ let outlives_env = OutlivesEnvironment::new(param_env);
- let ocx = ObligationCtxt::new(&infcx);
- let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id) else {
+ let errors = infcx.resolve_regions(&outlives_env);
+ if !errors.is_empty() {
return false;
- };
+ }
- let outlives_env = OutlivesEnvironment::with_bounds(
- param_env,
- infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
- );
- infcx.resolve_regions(&outlives_env).is_empty()
+ true
}
/// Returns whether all impls which would apply to the `trait_ref`
@@ -506,13 +586,6 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>(
trait_ref: ty::TraitRef<'tcx>,
mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
) -> Result<Result<(), Conflict>, E> {
- if Some(trait_ref.def_id) == tcx.lang_items().fn_ptr_trait() {
- // The only types implementing `FnPtr` are function pointers,
- // so if there's no impl of `FnPtr` in the current crate,
- // then such an impl will never be added in the future.
- return Ok(Ok(()));
- }
-
if orphan_check_trait_ref(trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() {
// A downstream or cousin crate is allowed to implement some
// substitution of this trait-ref.
@@ -817,7 +890,7 @@ where
}
}
ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
- ty::Closure(did, ..) | ty::Generator(did, ..) => {
+ ty::Closure(did, ..) | ty::Coroutine(did, ..) => {
if self.def_id_is_local(did) {
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
} else {
@@ -827,7 +900,7 @@ where
// This should only be created when checking whether we have to check whether some
// auto trait impl applies. There will never be multiple impls, so we can just
// act as if it were a local type here.
- ty::GeneratorWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+ ty::CoroutineWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
ty::Alias(ty::Opaque, ..) => {
// This merits some explanation.
// Normally, opaque types are not involved when performing
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 015e38b2a..d9a1a9819 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -37,10 +37,10 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
(TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => {
Box::new(FulfillmentContext::new(infcx))
}
- (TraitSolver::Next | TraitSolver::NextCoherence, true) => {
+ (TraitSolver::Classic | TraitSolver::Next | TraitSolver::NextCoherence, true) => {
Box::new(NextFulfillmentCtxt::new(infcx))
}
- _ => bug!(
+ (TraitSolver::Next, false) => bug!(
"incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})",
infcx.tcx.sess.opts.unstable_opts.trait_solver,
infcx.next_trait_solver()
@@ -218,7 +218,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
def_id: LocalDefId,
) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> {
self.assumed_wf_types(param_env, def_id)
- .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(&errors))
+ .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(errors))
}
pub fn assumed_wf_types(
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 fd813ca4e..5bc5a12a8 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,9 @@ pub fn recompute_applicable_impls<'tcx>(
if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder()
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
{
- if kind.rebind(trait_pred.trait_ref) == ty::Binder::dummy(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/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
new file mode 100644
index 000000000..b4835b011
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
@@ -0,0 +1,275 @@
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::InferCtxt;
+use crate::traits::{Obligation, ObligationCause, ObligationCtxt};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_hir as hir;
+use rustc_hir::Node;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{Span, DUMMY_SP};
+
+use super::ArgKind;
+
+pub use rustc_infer::traits::error_reporting::*;
+
+pub trait InferCtxtExt<'tcx> {
+ /// Given some node representing a fn-like thing in the HIR map,
+ /// returns a span and `ArgKind` information that describes the
+ /// arguments it expects. This can be supplied to
+ /// `report_arg_count_mismatch`.
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>;
+
+ /// Reports an error when the number of arguments needed by a
+ /// trait match doesn't match the number that the expression
+ /// provides.
+ fn report_arg_count_mismatch(
+ &self,
+ span: Span,
+ found_span: Option<Span>,
+ expected_args: Vec<ArgKind>,
+ found_args: Vec<ArgKind>,
+ is_closure: bool,
+ closure_pipe_span: Option<Span>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+ /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
+ /// in that order, and returns the generic type corresponding to the
+ /// argument of that trait (corresponding to the closure arguments).
+ fn type_implements_fn_trait(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: ty::Binder<'tcx, Ty<'tcx>>,
+ polarity: ty::ImplPolarity,
+ ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
+}
+
+impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
+ /// Given some node representing a fn-like thing in the HIR map,
+ /// returns a span and `ArgKind` information that describes the
+ /// arguments it expects. This can be supplied to
+ /// `report_arg_count_mismatch`.
+ fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)> {
+ let sm = self.tcx.sess.source_map();
+ let hir = self.tcx.hir();
+ Some(match node {
+ Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }),
+ ..
+ }) => (
+ fn_decl_span,
+ fn_arg_span,
+ hir.body(body)
+ .params
+ .iter()
+ .map(|arg| {
+ if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
+ *arg.pat
+ {
+ Some(ArgKind::Tuple(
+ Some(span),
+ args.iter()
+ .map(|pat| {
+ sm.span_to_snippet(pat.span)
+ .ok()
+ .map(|snippet| (snippet, "_".to_owned()))
+ })
+ .collect::<Option<Vec<_>>>()?,
+ ))
+ } else {
+ let name = sm.span_to_snippet(arg.pat.span).ok()?;
+ Some(ArgKind::Arg(name, "_".to_owned()))
+ }
+ })
+ .collect::<Option<Vec<ArgKind>>>()?,
+ ),
+ Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. })
+ | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
+ | Node::TraitItem(&hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(ref sig, _), ..
+ }) => (
+ sig.span,
+ None,
+ sig.decl
+ .inputs
+ .iter()
+ .map(|arg| match arg.kind {
+ hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
+ Some(arg.span),
+ vec![("_".to_owned(), "_".to_owned()); tys.len()],
+ ),
+ _ => ArgKind::empty(),
+ })
+ .collect::<Vec<ArgKind>>(),
+ ),
+ Node::Ctor(ref variant_data) => {
+ let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
+ (span, None, vec![ArgKind::empty(); variant_data.fields().len()])
+ }
+ _ => panic!("non-FnLike node found: {node:?}"),
+ })
+ }
+
+ /// Reports an error when the number of arguments needed by a
+ /// trait match doesn't match the number that the expression
+ /// provides.
+ fn report_arg_count_mismatch(
+ &self,
+ span: Span,
+ found_span: Option<Span>,
+ expected_args: Vec<ArgKind>,
+ found_args: Vec<ArgKind>,
+ is_closure: bool,
+ closure_arg_span: Option<Span>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let kind = if is_closure { "closure" } else { "function" };
+
+ let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
+ let arg_length = arguments.len();
+ let distinct = matches!(other, &[ArgKind::Tuple(..)]);
+ match (arg_length, arguments.get(0)) {
+ (1, Some(ArgKind::Tuple(_, fields))) => {
+ format!("a single {}-tuple as argument", fields.len())
+ }
+ _ => format!(
+ "{} {}argument{}",
+ arg_length,
+ if distinct && arg_length > 1 { "distinct " } else { "" },
+ pluralize!(arg_length)
+ ),
+ }
+ };
+
+ let expected_str = args_str(&expected_args, &found_args);
+ let found_str = args_str(&found_args, &expected_args);
+
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0593,
+ "{} is expected to take {}, but it takes {}",
+ kind,
+ expected_str,
+ found_str,
+ );
+
+ err.span_label(span, format!("expected {kind} that takes {expected_str}"));
+
+ if let Some(found_span) = found_span {
+ err.span_label(found_span, format!("takes {found_str}"));
+
+ // Suggest to take and ignore the arguments with expected_args_length `_`s if
+ // found arguments is empty (assume the user just wants to ignore args in this case).
+ // For example, if `expected_args_length` is 2, suggest `|_, _|`.
+ if found_args.is_empty() && is_closure {
+ let underscores = vec!["_"; expected_args.len()].join(", ");
+ err.span_suggestion_verbose(
+ closure_arg_span.unwrap_or(found_span),
+ format!(
+ "consider changing the closure to take and ignore the expected argument{}",
+ pluralize!(expected_args.len())
+ ),
+ format!("|{underscores}|"),
+ Applicability::MachineApplicable,
+ );
+ }
+
+ if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
+ if fields.len() == expected_args.len() {
+ let sugg = fields
+ .iter()
+ .map(|(name, _)| name.to_owned())
+ .collect::<Vec<String>>()
+ .join(", ");
+ err.span_suggestion_verbose(
+ found_span,
+ "change the closure to take multiple arguments instead of a single tuple",
+ format!("|{sugg}|"),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
+ && fields.len() == found_args.len()
+ && is_closure
+ {
+ let sugg = format!(
+ "|({}){}|",
+ found_args
+ .iter()
+ .map(|arg| match arg {
+ ArgKind::Arg(name, _) => name.to_owned(),
+ _ => "_".to_owned(),
+ })
+ .collect::<Vec<String>>()
+ .join(", "),
+ // add type annotations if available
+ if found_args.iter().any(|arg| match arg {
+ ArgKind::Arg(_, ty) => ty != "_",
+ _ => false,
+ }) {
+ format!(
+ ": ({})",
+ fields
+ .iter()
+ .map(|(_, ty)| ty.to_owned())
+ .collect::<Vec<String>>()
+ .join(", ")
+ )
+ } else {
+ String::new()
+ },
+ );
+ err.span_suggestion_verbose(
+ found_span,
+ "change the closure to accept a tuple instead of individual arguments",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
+ err
+ }
+
+ fn type_implements_fn_trait(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: ty::Binder<'tcx, Ty<'tcx>>,
+ polarity: ty::ImplPolarity,
+ ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
+ self.commit_if_ok(|_| {
+ for trait_def_id in [
+ self.tcx.lang_items().fn_trait(),
+ self.tcx.lang_items().fn_mut_trait(),
+ self.tcx.lang_items().fn_once_trait(),
+ ] {
+ let Some(trait_def_id) = trait_def_id else { continue };
+ // Make a fresh inference variable so we can determine what the substitutions
+ // of the trait are.
+ let var = self.next_ty_var(TypeVariableOrigin {
+ span: DUMMY_SP,
+ kind: TypeVariableOriginKind::MiscVariable,
+ });
+ // FIXME(effects)
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
+ let obligation = Obligation::new(
+ self.tcx,
+ ObligationCause::dummy(),
+ param_env,
+ ty.rebind(ty::TraitPredicate { trait_ref, polarity }),
+ );
+ let ocx = ObligationCtxt::new(self);
+ ocx.register_obligation(obligation);
+ if ocx.select_all_or_error().is_empty() {
+ return Ok((
+ self.tcx
+ .fn_trait_kind_from_def_id(trait_def_id)
+ .expect("expected to map DefId to ClosureKind"),
+ ty.rebind(self.resolve_vars_if_possible(var)),
+ ));
+ }
+ }
+
+ Err(())
+ })
+ }
+}
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 2a586f810..0796cb57d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1,57 +1,25 @@
+// ignore-tidy-filelength :(
+
mod ambiguity;
+mod infer_ctxt_ext;
pub mod on_unimplemented;
pub mod suggestions;
+mod type_err_ctxt_ext;
-use super::{
- FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, ObligationCause,
- ObligationCauseCode, ObligationCtxt, OutputTypeParameterMismatch, Overflow,
- PredicateObligation, SelectionError, TraitNotObjectSafe,
-};
-use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch};
-use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
-use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::infer::{self, InferCtxt};
-use crate::solve::{GenerateProofTree, InferCtxtEvalExt, UseGlobalCache};
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::specialize::to_pretty_impl_header;
-use crate::traits::NormalizeExt;
-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,
- MultiSpan, Style,
-};
+use super::{Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
+use crate::infer::InferCtxt;
+use crate::solve::{GenerateProofTree, InferCtxtEvalExt};
use rustc_hir as hir;
-use rustc_hir::def::Namespace;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
-use rustc_hir::{GenericParam, Item, Node};
-use rustc_infer::infer::error_reporting::TypeErrCtxt;
-use rustc_infer::infer::{InferOk, TypeTrace};
-use rustc_middle::traits::select::OverflowError;
use rustc_middle::traits::solve::Goal;
-use rustc_middle::traits::{DefiningAnchor, SelectionOutputTypeParameterMismatch};
-use rustc_middle::ty::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
-use rustc_middle::ty::{
- self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
- TypeVisitable, TypeVisitableExt,
-};
-use rustc_session::config::{DumpSolverProofTree, TraitSolver};
-use rustc_session::Limit;
-use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::symbol::sym;
-use rustc_span::{ExpnKind, Span, DUMMY_SP};
-use std::borrow::Cow;
-use std::fmt;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::Span;
use std::io::Write;
-use std::iter;
use std::ops::ControlFlow;
-use suggestions::TypeErrCtxtExt as _;
-pub use rustc_infer::traits::error_reporting::*;
+pub use self::infer_ctxt_ext::*;
+pub use self::type_err_ctxt_ext::*;
// When outputting impl candidates, prefer showing those that are more similar.
//
@@ -67,6 +35,7 @@ pub enum CandidateSimilarity {
pub struct ImplCandidate<'tcx> {
pub trait_ref: ty::TraitRef<'tcx>,
pub similarity: CandidateSimilarity,
+ impl_def_id: DefId,
}
enum GetSafeTransmuteErrorAndReason {
@@ -74,3356 +43,8 @@ enum GetSafeTransmuteErrorAndReason {
Error { err_msg: String, safe_transmute_explanation: String },
}
-pub trait InferCtxtExt<'tcx> {
- /// Given some node representing a fn-like thing in the HIR map,
- /// returns a span and `ArgKind` information that describes the
- /// arguments it expects. This can be supplied to
- /// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)>;
-
- /// Reports an error when the number of arguments needed by a
- /// trait match doesn't match the number that the expression
- /// provides.
- fn report_arg_count_mismatch(
- &self,
- span: Span,
- found_span: Option<Span>,
- expected_args: Vec<ArgKind>,
- found_args: Vec<ArgKind>,
- is_closure: bool,
- closure_pipe_span: Option<Span>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
-
- /// Checks if the type implements one of `Fn`, `FnMut`, or `FnOnce`
- /// in that order, and returns the generic type corresponding to the
- /// argument of that trait (corresponding to the closure arguments).
- fn type_implements_fn_trait(
- &self,
- param_env: ty::ParamEnv<'tcx>,
- ty: ty::Binder<'tcx, Ty<'tcx>>,
- polarity: ty::ImplPolarity,
- ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
-}
-
-pub trait TypeErrCtxtExt<'tcx> {
- fn build_overflow_error<T>(
- &self,
- predicate: &T,
- span: Span,
- suggest_increasing_limit: bool,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
- where
- T: fmt::Display
- + TypeFoldable<TyCtxt<'tcx>>
- + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
- <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
-
- fn report_overflow_error<T>(
- &self,
- predicate: &T,
- span: Span,
- suggest_increasing_limit: bool,
- mutate: impl FnOnce(&mut Diagnostic),
- ) -> !
- where
- T: fmt::Display
- + TypeFoldable<TyCtxt<'tcx>>
- + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
- <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
-
- fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed;
-
- fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed;
-
- fn report_overflow_obligation<T>(
- &self,
- obligation: &Obligation<'tcx, T>,
- suggest_increasing_limit: bool,
- ) -> !
- where
- T: ToPredicate<'tcx> + Clone;
-
- fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
-
- fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
-
- /// The `root_obligation` parameter should be the `root_obligation` field
- /// from a `FulfillmentError`. If no `FulfillmentError` is available,
- /// then it should be the same as `obligation`.
- fn report_selection_error(
- &self,
- obligation: PredicateObligation<'tcx>,
- root_obligation: &PredicateObligation<'tcx>,
- error: &SelectionError<'tcx>,
- );
-
- fn report_const_param_not_wf(
- &self,
- ty: Ty<'tcx>,
- obligation: &PredicateObligation<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
-}
-
-impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
- /// Given some node representing a fn-like thing in the HIR map,
- /// returns a span and `ArgKind` information that describes the
- /// arguments it expects. This can be supplied to
- /// `report_arg_count_mismatch`.
- fn get_fn_like_arguments(&self, node: Node<'_>) -> Option<(Span, Option<Span>, Vec<ArgKind>)> {
- let sm = self.tcx.sess.source_map();
- let hir = self.tcx.hir();
- Some(match node {
- Node::Expr(&hir::Expr {
- kind: hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, fn_arg_span, .. }),
- ..
- }) => (
- fn_decl_span,
- fn_arg_span,
- hir.body(body)
- .params
- .iter()
- .map(|arg| {
- if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
- *arg.pat
- {
- Some(ArgKind::Tuple(
- Some(span),
- args.iter()
- .map(|pat| {
- sm.span_to_snippet(pat.span)
- .ok()
- .map(|snippet| (snippet, "_".to_owned()))
- })
- .collect::<Option<Vec<_>>>()?,
- ))
- } else {
- let name = sm.span_to_snippet(arg.pat.span).ok()?;
- Some(ArgKind::Arg(name, "_".to_owned()))
- }
- })
- .collect::<Option<Vec<ArgKind>>>()?,
- ),
- Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. })
- | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
- | Node::TraitItem(&hir::TraitItem {
- kind: hir::TraitItemKind::Fn(ref sig, _), ..
- }) => (
- sig.span,
- None,
- sig.decl
- .inputs
- .iter()
- .map(|arg| match arg.kind {
- hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
- Some(arg.span),
- vec![("_".to_owned(), "_".to_owned()); tys.len()],
- ),
- _ => ArgKind::empty(),
- })
- .collect::<Vec<ArgKind>>(),
- ),
- Node::Ctor(ref variant_data) => {
- let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
- (span, None, vec![ArgKind::empty(); variant_data.fields().len()])
- }
- _ => panic!("non-FnLike node found: {node:?}"),
- })
- }
-
- /// Reports an error when the number of arguments needed by a
- /// trait match doesn't match the number that the expression
- /// provides.
- fn report_arg_count_mismatch(
- &self,
- span: Span,
- found_span: Option<Span>,
- expected_args: Vec<ArgKind>,
- found_args: Vec<ArgKind>,
- is_closure: bool,
- closure_arg_span: Option<Span>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let kind = if is_closure { "closure" } else { "function" };
-
- let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
- let arg_length = arguments.len();
- let distinct = matches!(other, &[ArgKind::Tuple(..)]);
- match (arg_length, arguments.get(0)) {
- (1, Some(ArgKind::Tuple(_, fields))) => {
- format!("a single {}-tuple as argument", fields.len())
- }
- _ => format!(
- "{} {}argument{}",
- arg_length,
- if distinct && arg_length > 1 { "distinct " } else { "" },
- pluralize!(arg_length)
- ),
- }
- };
-
- let expected_str = args_str(&expected_args, &found_args);
- let found_str = args_str(&found_args, &expected_args);
-
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0593,
- "{} is expected to take {}, but it takes {}",
- kind,
- expected_str,
- found_str,
- );
-
- err.span_label(span, format!("expected {kind} that takes {expected_str}"));
-
- if let Some(found_span) = found_span {
- err.span_label(found_span, format!("takes {found_str}"));
-
- // Suggest to take and ignore the arguments with expected_args_length `_`s if
- // found arguments is empty (assume the user just wants to ignore args in this case).
- // For example, if `expected_args_length` is 2, suggest `|_, _|`.
- if found_args.is_empty() && is_closure {
- let underscores = vec!["_"; expected_args.len()].join(", ");
- err.span_suggestion_verbose(
- closure_arg_span.unwrap_or(found_span),
- format!(
- "consider changing the closure to take and ignore the expected argument{}",
- pluralize!(expected_args.len())
- ),
- format!("|{underscores}|"),
- Applicability::MachineApplicable,
- );
- }
-
- if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
- if fields.len() == expected_args.len() {
- let sugg = fields
- .iter()
- .map(|(name, _)| name.to_owned())
- .collect::<Vec<String>>()
- .join(", ");
- err.span_suggestion_verbose(
- found_span,
- "change the closure to take multiple arguments instead of a single tuple",
- format!("|{sugg}|"),
- Applicability::MachineApplicable,
- );
- }
- }
- if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..]
- && fields.len() == found_args.len()
- && is_closure
- {
- let sugg = format!(
- "|({}){}|",
- found_args
- .iter()
- .map(|arg| match arg {
- ArgKind::Arg(name, _) => name.to_owned(),
- _ => "_".to_owned(),
- })
- .collect::<Vec<String>>()
- .join(", "),
- // add type annotations if available
- if found_args.iter().any(|arg| match arg {
- ArgKind::Arg(_, ty) => ty != "_",
- _ => false,
- }) {
- format!(
- ": ({})",
- fields
- .iter()
- .map(|(_, ty)| ty.to_owned())
- .collect::<Vec<String>>()
- .join(", ")
- )
- } else {
- String::new()
- },
- );
- err.span_suggestion_verbose(
- found_span,
- "change the closure to accept a tuple instead of individual arguments",
- sugg,
- Applicability::MachineApplicable,
- );
- }
- }
-
- err
- }
-
- fn type_implements_fn_trait(
- &self,
- param_env: ty::ParamEnv<'tcx>,
- ty: ty::Binder<'tcx, Ty<'tcx>>,
- polarity: ty::ImplPolarity,
- ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
- self.commit_if_ok(|_| {
- for trait_def_id in [
- self.tcx.lang_items().fn_trait(),
- self.tcx.lang_items().fn_mut_trait(),
- self.tcx.lang_items().fn_once_trait(),
- ] {
- let Some(trait_def_id) = trait_def_id else { continue };
- // Make a fresh inference variable so we can determine what the substitutions
- // of the trait are.
- let var = self.next_ty_var(TypeVariableOrigin {
- span: DUMMY_SP,
- kind: TypeVariableOriginKind::MiscVariable,
- });
- // FIXME(effects)
- let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
- let obligation = Obligation::new(
- self.tcx,
- ObligationCause::dummy(),
- param_env,
- ty.rebind(ty::TraitPredicate { trait_ref, polarity }),
- );
- let ocx = ObligationCtxt::new(self);
- ocx.register_obligation(obligation);
- if ocx.select_all_or_error().is_empty() {
- return Ok((
- self.tcx
- .fn_trait_kind_from_def_id(trait_def_id)
- .expect("expected to map DefId to ClosureKind"),
- ty.rebind(self.resolve_vars_if_possible(var)),
- ));
- }
- }
-
- Err(())
- })
- }
-}
-
-impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
- fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed {
- #[derive(Debug)]
- struct ErrorDescriptor<'tcx> {
- predicate: ty::Predicate<'tcx>,
- index: Option<usize>, // None if this is an old error
- }
-
- let mut error_map: FxIndexMap<_, Vec<_>> = self
- .reported_trait_errors
- .borrow()
- .iter()
- .map(|(&span, predicates)| {
- (
- span,
- predicates
- .iter()
- .map(|&predicate| ErrorDescriptor { predicate, index: None })
- .collect(),
- )
- })
- .collect();
-
- for (index, error) in errors.iter().enumerate() {
- // We want to ignore desugarings here: spans are equivalent even
- // if one is the result of a desugaring and the other is not.
- let mut span = error.obligation.cause.span;
- let expn_data = span.ctxt().outer_expn_data();
- if let ExpnKind::Desugaring(_) = expn_data.kind {
- span = expn_data.call_site;
- }
-
- error_map.entry(span).or_default().push(ErrorDescriptor {
- predicate: error.obligation.predicate,
- index: Some(index),
- });
-
- self.reported_trait_errors
- .borrow_mut()
- .entry(span)
- .or_default()
- .push(error.obligation.predicate);
- }
-
- // We do this in 2 passes because we want to display errors in order, though
- // maybe it *is* better to sort errors by span or something.
- let mut is_suppressed = vec![false; errors.len()];
- for (_, error_set) in error_map.iter() {
- // We want to suppress "duplicate" errors with the same span.
- for error in error_set {
- if let Some(index) = error.index {
- // Suppress errors that are either:
- // 1) strictly implied by another error.
- // 2) implied by an error with a smaller index.
- for error2 in error_set {
- if error2.index.is_some_and(|index2| is_suppressed[index2]) {
- // Avoid errors being suppressed by already-suppressed
- // errors, to prevent all errors from being suppressed
- // at once.
- continue;
- }
-
- if self.error_implies(error2.predicate, error.predicate)
- && !(error2.index >= error.index
- && self.error_implies(error.predicate, error2.predicate))
- {
- info!("skipping {:?} (implied by {:?})", error, error2);
- is_suppressed[index] = true;
- break;
- }
- }
- }
- }
- }
-
- for from_expansion in [false, true] {
- for (error, suppressed) in iter::zip(errors, &is_suppressed) {
- if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
- self.report_fulfillment_error(error);
- }
- }
- }
-
- self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors")
- }
-
- /// Reports that an overflow has occurred and halts compilation. We
- /// halt compilation unconditionally because it is important that
- /// overflows never be masked -- they basically represent computations
- /// whose result could not be truly determined and thus we can't say
- /// if the program type checks or not -- and they are unusual
- /// occurrences in any case.
- fn report_overflow_error<T>(
- &self,
- predicate: &T,
- span: Span,
- suggest_increasing_limit: bool,
- mutate: impl FnOnce(&mut Diagnostic),
- ) -> !
- where
- T: fmt::Display
- + TypeFoldable<TyCtxt<'tcx>>
- + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
- <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
- {
- let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit);
- mutate(&mut err);
- err.emit();
-
- self.tcx.sess.abort_if_errors();
- bug!();
- }
-
- fn build_overflow_error<T>(
- &self,
- predicate: &T,
- span: Span,
- suggest_increasing_limit: bool,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
- where
- T: fmt::Display
- + TypeFoldable<TyCtxt<'tcx>>
- + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
- <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug,
- {
- let predicate = self.resolve_vars_if_possible(predicate.clone());
- let mut pred_str = predicate.to_string();
-
- if pred_str.len() > 50 {
- // We don't need to save the type to a file, we will be talking about this type already
- // in a separate note when we explain the obligation, so it will be available that way.
- pred_str = predicate
- .print(FmtPrinter::new_with_limit(
- self.tcx,
- Namespace::TypeNS,
- rustc_session::Limit(6),
- ))
- .unwrap()
- .into_buffer();
- }
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0275,
- "overflow evaluating the requirement `{}`",
- pred_str,
- );
-
- if suggest_increasing_limit {
- self.suggest_new_overflow_limit(&mut err);
- }
-
- err
- }
-
- /// Reports that an overflow has occurred and halts compilation. We
- /// halt compilation unconditionally because it is important that
- /// overflows never be masked -- they basically represent computations
- /// whose result could not be truly determined and thus we can't say
- /// if the program type checks or not -- and they are unusual
- /// occurrences in any case.
- fn report_overflow_obligation<T>(
- &self,
- obligation: &Obligation<'tcx, T>,
- suggest_increasing_limit: bool,
- ) -> !
- where
- T: ToPredicate<'tcx> + Clone,
- {
- let predicate = obligation.predicate.clone().to_predicate(self.tcx);
- let predicate = self.resolve_vars_if_possible(predicate);
- self.report_overflow_error(
- &predicate,
- obligation.cause.span,
- suggest_increasing_limit,
- |err| {
- self.note_obligation_cause_code(
- obligation.cause.body_id,
- err,
- predicate,
- obligation.param_env,
- obligation.cause.code(),
- &mut vec![],
- &mut Default::default(),
- );
- },
- );
- }
-
- fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
- let suggested_limit = match self.tcx.recursion_limit() {
- Limit(0) => Limit(2),
- limit => limit * 2,
- };
- err.help(format!(
- "consider increasing the recursion limit by adding a \
- `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
- suggested_limit,
- self.tcx.crate_name(LOCAL_CRATE),
- ));
- }
-
- /// Reports that a cycle was detected which led to overflow and halts
- /// compilation. This is equivalent to `report_overflow_obligation` except
- /// that we can give a more helpful error message (and, in particular,
- /// we do not suggest increasing the overflow limit, which is not
- /// going to help).
- fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
- let cycle = self.resolve_vars_if_possible(cycle.to_owned());
- assert!(!cycle.is_empty());
-
- debug!(?cycle, "report_overflow_error_cycle");
-
- // The 'deepest' obligation is most likely to have a useful
- // cause 'backtrace'
- self.report_overflow_obligation(
- cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
- false,
- );
- }
-
- fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
- let obligation = self.resolve_vars_if_possible(obligation);
- let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true);
- self.note_obligation_cause(&mut err, &obligation);
- self.point_at_returns_when_relevant(&mut err, &obligation);
- err.emit()
- }
-
- fn report_selection_error(
- &self,
- mut obligation: PredicateObligation<'tcx>,
- root_obligation: &PredicateObligation<'tcx>,
- error: &SelectionError<'tcx>,
- ) {
- let tcx = self.tcx;
-
- if tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError {
- dump_proof_tree(root_obligation, self.infcx);
- }
-
- let mut span = obligation.cause.span;
- // FIXME: statically guarantee this by tainting after the diagnostic is emitted
- self.set_tainted_by_errors(
- tcx.sess.delay_span_bug(span, "`report_selection_error` did not emit an error"),
- );
-
- let mut err = match *error {
- SelectionError::Unimplemented => {
- // If this obligation was generated as a result of well-formedness checking, see if we
- // can get a better error message by performing HIR-based well-formedness checking.
- if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
- root_obligation.cause.code().peel_derives()
- && !obligation.predicate.has_non_region_infer()
- {
- if let Some(cause) = self
- .tcx
- .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc))
- {
- obligation.cause = cause.clone();
- span = obligation.cause.span;
- }
- }
-
- if let ObligationCauseCode::CompareImplItemObligation {
- impl_item_def_id,
- trait_item_def_id,
- kind: _,
- } = *obligation.cause.code()
- {
- self.report_extra_impl_obligation(
- span,
- impl_item_def_id,
- trait_item_def_id,
- &format!("`{}`", obligation.predicate),
- )
- .emit();
- return;
- }
-
- // Report a const-param specific error
- if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()
- {
- self.report_const_param_not_wf(ty, &obligation).emit();
- return;
- }
-
- let bound_predicate = obligation.predicate.kind();
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
- let trait_predicate = bound_predicate.rebind(trait_predicate);
- let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
-
- // FIXME(effects)
- let predicate_is_const = false;
-
- if self.tcx.sess.has_errors().is_some()
- && trait_predicate.references_error()
- {
- return;
- }
- let trait_ref = trait_predicate.to_poly_trait_ref();
-
- let (post_message, pre_message, type_def) = self
- .get_parent_trait_ref(obligation.cause.code())
- .map(|(t, s)| {
- (
- format!(" in `{t}`"),
- format!("within `{t}`, "),
- s.map(|s| (format!("within this `{t}`"), s)),
- )
- })
- .unwrap_or_default();
-
- let OnUnimplementedNote {
- message,
- label,
- note,
- parent_label,
- append_const_msg,
- } = self.on_unimplemented_note(trait_ref, &obligation);
- let have_alt_message = message.is_some() || label.is_some();
- let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
- let is_unsize =
- Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
- let (message, note, append_const_msg) = if is_try_conversion {
- (
- Some(format!(
- "`?` couldn't convert the error to `{}`",
- trait_ref.skip_binder().self_ty(),
- )),
- Some(
- "the question mark operation (`?`) implicitly performs a \
- conversion on the error value using the `From` trait"
- .to_owned(),
- ),
- Some(AppendConstMessage::Default),
- )
- } else {
- (message, note, append_const_msg)
- };
-
- 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
- match self.get_safe_transmute_error_and_reason(
- obligation.clone(),
- trait_ref,
- span,
- ) {
- GetSafeTransmuteErrorAndReason::Silent => return,
- GetSafeTransmuteErrorAndReason::Error {
- err_msg,
- safe_transmute_explanation,
- } => (err_msg, Some(safe_transmute_explanation)),
- }
- } else {
- (err_msg, None)
- };
-
- let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg);
-
- if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
- err.span_label(
- ret_span,
- format!(
- "expected `{}` because of this",
- trait_ref.skip_binder().self_ty()
- ),
- );
- }
-
- if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
- self.add_tuple_trait_message(
- &obligation.cause.code().peel_derives(),
- &mut err,
- );
- }
-
- if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
- && predicate_is_const
- {
- err.note("`~const Drop` was renamed to `~const Destruct`");
- err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
- }
-
- let explanation = get_explanation_based_on_obligation(
- &obligation,
- trait_ref,
- &trait_predicate,
- pre_message,
- );
-
- self.check_for_binding_assigned_block_without_tail_expression(
- &obligation,
- &mut err,
- trait_predicate,
- );
- if self.suggest_add_reference_to_arg(
- &obligation,
- &mut err,
- trait_predicate,
- have_alt_message,
- ) {
- self.note_obligation_cause(&mut err, &obligation);
- err.emit();
- return;
- }
- if let Some(s) = label {
- // If it has a custom `#[rustc_on_unimplemented]`
- // error message, let's display it as the label!
- err.span_label(span, s);
- if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
- // When the self type is a type param We don't need to "the trait
- // `std::marker::Sized` is not implemented for `T`" as we will point
- // at the type param with a label to suggest constraining it.
- err.help(explanation);
- }
- } else if let Some(custom_explanation) = safe_transmute_explanation {
- err.span_label(span, custom_explanation);
- } else {
- err.span_label(span, explanation);
- }
-
- if let ObligationCauseCode::Coercion { source, target } =
- *obligation.cause.code().peel_derives()
- {
- if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
- self.suggest_borrowing_for_object_cast(
- &mut err,
- &root_obligation,
- source,
- target,
- );
- }
- }
-
- let UnsatisfiedConst(unsatisfied_const) = self
- .maybe_add_note_for_unsatisfied_const(
- &obligation,
- trait_ref,
- &trait_predicate,
- &mut err,
- span,
- );
-
- if let Some((msg, span)) = type_def {
- err.span_label(span, msg);
- }
- if let Some(s) = note {
- // If it has a custom `#[rustc_on_unimplemented]` note, let's display it
- err.note(s);
- }
- if let Some(s) = parent_label {
- let body = obligation.cause.body_id;
- err.span_label(tcx.def_span(body), s);
- }
-
- self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
- self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate);
- let mut suggested =
- self.suggest_dereferences(&obligation, &mut err, trait_predicate);
- suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
- let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
- suggested = if let &[cand] = &impl_candidates[..] {
- let cand = cand.trait_ref;
- if let (ty::FnPtr(_), ty::FnDef(..)) =
- (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
- {
- err.span_suggestion(
- span.shrink_to_hi(),
- format!(
- "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
- cand.print_only_trait_path(),
- cand.self_ty(),
- ),
- format!(" as {}", cand.self_ty()),
- Applicability::MaybeIncorrect,
- );
- true
- } else {
- false
- }
- } else {
- false
- } || suggested;
- suggested |=
- self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
- suggested |= self.suggest_semicolon_removal(
- &obligation,
- &mut err,
- span,
- trait_predicate,
- );
- self.note_version_mismatch(&mut err, &trait_ref);
- self.suggest_remove_await(&obligation, &mut err);
- self.suggest_derive(&obligation, &mut err, trait_predicate);
-
- if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
- self.suggest_await_before_try(
- &mut err,
- &obligation,
- trait_predicate,
- span,
- );
- }
-
- if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
- err.emit();
- return;
- }
-
- if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
- err.emit();
- return;
- }
-
- if is_unsize {
- // If the obligation failed due to a missing implementation of the
- // `Unsize` trait, give a pointer to why that might be the case
- err.note(
- "all implementations of `Unsize` are provided \
- automatically by the compiler, see \
- <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> \
- for more information",
- );
- }
-
- let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id());
- let is_target_feature_fn = if let ty::FnDef(def_id, _) =
- *trait_ref.skip_binder().self_ty().kind()
- {
- !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
- } else {
- false
- };
- if is_fn_trait && is_target_feature_fn {
- err.note(
- "`#[target_feature]` functions do not implement the `Fn` traits",
- );
- }
-
- self.try_to_add_help_message(
- &obligation,
- trait_ref,
- &trait_predicate,
- &mut err,
- span,
- is_fn_trait,
- suggested,
- unsatisfied_const,
- );
-
- // Changing mutability doesn't make a difference to whether we have
- // an `Unsize` impl (Fixes ICE in #71036)
- if !is_unsize {
- self.suggest_change_mut(&obligation, &mut err, trait_predicate);
- }
-
- // If this error is due to `!: Trait` not implemented but `(): Trait` is
- // implemented, and fallback has occurred, then it could be due to a
- // variable that used to fallback to `()` now falling back to `!`. Issue a
- // note informing about the change in behaviour.
- if trait_predicate.skip_binder().self_ty().is_never()
- && self.fallback_has_occurred
- {
- let predicate = trait_predicate.map_bound(|trait_pred| {
- trait_pred.with_self_ty(self.tcx, Ty::new_unit(self.tcx))
- });
- let unit_obligation = obligation.with(tcx, predicate);
- if self.predicate_may_hold(&unit_obligation) {
- err.note(
- "this error might have been caused by changes to \
- Rust's type-inference algorithm (see issue #48950 \
- <https://github.com/rust-lang/rust/issues/48950> \
- for more information)",
- );
- err.help("did you intend to use the type `()` here instead?");
- }
- }
-
- self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause);
- self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref);
-
- // Return early if the trait is Debug or Display and the invocation
- // originates within a standard library macro, because the output
- // is otherwise overwhelming and unhelpful (see #85844 for an
- // example).
-
- let in_std_macro =
- match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {
- Some(macro_def_id) => {
- let crate_name = tcx.crate_name(macro_def_id.krate);
- crate_name == sym::std || crate_name == sym::core
- }
- None => false,
- };
-
- if in_std_macro
- && matches!(
- self.tcx.get_diagnostic_name(trait_ref.def_id()),
- Some(sym::Debug | sym::Display)
- )
- {
- err.emit();
- return;
- }
-
- err
- }
-
- ty::PredicateKind::Subtype(predicate) => {
- // Errors for Subtype predicates show up as
- // `FulfillmentErrorCode::CodeSubtypeError`,
- // not selection error.
- span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
- }
-
- ty::PredicateKind::Coerce(predicate) => {
- // Errors for Coerce predicates show up as
- // `FulfillmentErrorCode::CodeSubtypeError`,
- // not selection error.
- span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
- }
-
- ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
- | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => {
- span_bug!(
- span,
- "outlives clauses should not error outside borrowck. obligation: `{:?}`",
- obligation
- )
- }
-
- ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {
- span_bug!(
- span,
- "projection clauses should be implied from elsewhere. obligation: `{:?}`",
- obligation
- )
- }
-
- ty::PredicateKind::ObjectSafe(trait_def_id) => {
- let violations = self.tcx.object_safety_violations(trait_def_id);
- report_object_safety_error(self.tcx, span, trait_def_id, violations)
- }
-
- ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
- let found_kind = self.closure_kind(closure_args).unwrap();
- self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
- }
-
- ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
- let ty = self.resolve_vars_if_possible(ty);
- match self.tcx.sess.opts.unstable_opts.trait_solver {
- TraitSolver::Classic => {
- // WF predicates cannot themselves make
- // errors. They can only block due to
- // ambiguity; otherwise, they always
- // degenerate into other obligations
- // (which may fail).
- span_bug!(span, "WF predicate not satisfied for {:?}", ty);
- }
- TraitSolver::Next | TraitSolver::NextCoherence => {
- // FIXME: we'll need a better message which takes into account
- // which bounds actually failed to hold.
- self.tcx.sess.struct_span_err(
- span,
- format!("the type `{ty}` is not well-formed"),
- )
- }
- }
- }
-
- ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => {
- // Errors for `ConstEvaluatable` predicates show up as
- // `SelectionError::ConstEvalFailure`,
- // not `Unimplemented`.
- span_bug!(
- span,
- "const-evaluatable requirement gave wrong error: `{:?}`",
- obligation
- )
- }
-
- ty::PredicateKind::ConstEquate(..) => {
- // Errors for `ConstEquate` predicates show up as
- // `SelectionError::ConstEvalFailure`,
- // not `Unimplemented`.
- span_bug!(
- span,
- "const-equate requirement gave wrong error: `{:?}`",
- obligation
- )
- }
-
- ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
-
- ty::PredicateKind::AliasRelate(..) => span_bug!(
- span,
- "AliasRelate predicate should never be the predicate cause of a SelectionError"
- ),
-
- ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
- let mut diag = self.tcx.sess.struct_span_err(
- span,
- format!("the constant `{ct}` is not of type `{ty}`"),
- );
- self.note_type_err(
- &mut diag,
- &obligation.cause,
- None,
- None,
- TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())),
- false,
- false,
- );
- diag
- }
- }
- }
-
- OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
- found_trait_ref,
- expected_trait_ref,
- 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,
- }
- }
-
- SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => self.report_opaque_type_auto_trait_leakage(
- &obligation,
- def_id,
- ),
-
- TraitNotObjectSafe(did) => {
- let violations = self.tcx.object_safety_violations(did);
- report_object_safety_error(self.tcx, span, did, violations)
- }
-
- SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {
- bug!(
- "MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`"
- )
- }
- SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
- match self.report_not_const_evaluatable_error(&obligation, span) {
- Some(err) => err,
- None => return,
- }
- }
-
- // Already reported in the query.
- SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) |
- // Already reported.
- Overflow(OverflowError::Error(_)) => return,
-
- Overflow(_) => {
- bug!("overflow should be handled before the `report_selection_error` path");
- }
- SelectionError::ErrorReporting => {
- bug!("ErrorReporting Overflow should not reach `report_selection_err` call")
- }
- };
-
- self.note_obligation_cause(&mut err, &obligation);
- self.point_at_returns_when_relevant(&mut err, &obligation);
- err.emit();
- }
-
- fn report_const_param_not_wf(
- &self,
- ty: Ty<'tcx>,
- obligation: &PredicateObligation<'tcx>,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let span = obligation.cause.span;
-
- let mut diag = match ty.kind() {
- _ if ty.has_param() => {
- span_bug!(span, "const param tys cannot mention other generic parameters");
- }
- ty::Float(_) => {
- struct_span_err!(
- self.tcx.sess,
- span,
- E0741,
- "`{ty}` is forbidden as the type of a const generic parameter",
- )
- }
- ty::FnPtr(_) => {
- struct_span_err!(
- self.tcx.sess,
- span,
- E0741,
- "using function pointers as const generic parameters is forbidden",
- )
- }
- ty::RawPtr(_) => {
- struct_span_err!(
- self.tcx.sess,
- span,
- E0741,
- "using raw pointers as const generic parameters is forbidden",
- )
- }
- ty::Adt(def, _) => {
- // We should probably see if we're *allowed* to derive `ConstParamTy` on the type...
- let mut diag = struct_span_err!(
- self.tcx.sess,
- span,
- E0741,
- "`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter",
- );
- // Only suggest derive if this isn't a derived obligation,
- // and the struct is local.
- if let Some(span) = self.tcx.hir().span_if_local(def.did())
- && obligation.cause.code().parent().is_none()
- {
- if ty.is_structural_eq_shallow(self.tcx) {
- diag.span_suggestion(
- span,
- "add `#[derive(ConstParamTy)]` to the struct",
- "#[derive(ConstParamTy)]\n",
- Applicability::MachineApplicable,
- );
- } else {
- // FIXME(adt_const_params): We should check there's not already an
- // overlapping `Eq`/`PartialEq` impl.
- diag.span_suggestion(
- span,
- "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct",
- "#[derive(ConstParamTy, PartialEq, Eq)]\n",
- Applicability::MachineApplicable,
- );
- }
- }
- diag
- }
- _ => {
- struct_span_err!(
- self.tcx.sess,
- span,
- E0741,
- "`{ty}` can't be used as a const parameter type",
- )
- }
- };
-
- let mut code = obligation.cause.code();
- let mut pred = obligation.predicate.to_opt_poly_trait_pred();
- while let Some((next_code, next_pred)) = code.parent() {
- if let Some(pred) = pred {
- let pred = self.instantiate_binder_with_placeholders(pred);
- diag.note(format!(
- "`{}` must implement `{}`, but it does not",
- pred.self_ty(),
- pred.print_modifiers_and_trait_path()
- ));
- }
- code = next_code;
- pred = next_pred;
- }
-
- diag
- }
-}
-
-trait InferCtxtPrivExt<'tcx> {
- // returns if `cond` not occurring implies that `error` does not occur - i.e., that
- // `error` occurring implies that `cond` occurs.
- fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
-
- fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>);
-
- fn report_projection_error(
- &self,
- obligation: &PredicateObligation<'tcx>,
- error: &MismatchedProjectionTypes<'tcx>,
- );
-
- fn maybe_detailed_projection_msg(
- &self,
- pred: ty::ProjectionPredicate<'tcx>,
- normalized_ty: ty::Term<'tcx>,
- expected_ty: ty::Term<'tcx>,
- ) -> Option<String>;
-
- fn fuzzy_match_tys(
- &self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- ignoring_lifetimes: bool,
- ) -> Option<CandidateSimilarity>;
-
- fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>;
-
- fn find_similar_impl_candidates(
- &self,
- trait_pred: ty::PolyTraitPredicate<'tcx>,
- ) -> Vec<ImplCandidate<'tcx>>;
-
- fn report_similar_impl_candidates(
- &self,
- impl_candidates: &[ImplCandidate<'tcx>],
- trait_ref: ty::PolyTraitRef<'tcx>,
- body_def_id: LocalDefId,
- err: &mut Diagnostic,
- 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,
- code: &ObligationCauseCode<'tcx>,
- ) -> Option<(String, Option<Span>)>;
-
- /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
- /// with the same path as `trait_ref`, a help message about
- /// a probable version mismatch is added to `err`
- fn note_version_mismatch(
- &self,
- err: &mut Diagnostic,
- trait_ref: &ty::PolyTraitRef<'tcx>,
- ) -> bool;
-
- /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
- /// `trait_ref`.
- ///
- /// For this to work, `new_self_ty` must have no escaping bound variables.
- fn mk_trait_obligation_with_new_self_ty(
- &self,
- param_env: ty::ParamEnv<'tcx>,
- trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
- ) -> PredicateObligation<'tcx>;
-
- fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>);
-
- fn predicate_can_apply(
- &self,
- param_env: ty::ParamEnv<'tcx>,
- pred: ty::PolyTraitPredicate<'tcx>,
- ) -> bool;
-
- fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>);
-
- fn suggest_unsized_bound_if_applicable(
- &self,
- err: &mut Diagnostic,
- obligation: &PredicateObligation<'tcx>,
- );
-
- fn annotate_source_of_ambiguity(
- &self,
- err: &mut Diagnostic,
- impls: &[ambiguity::Ambiguity],
- predicate: ty::Predicate<'tcx>,
- );
-
- fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>);
-
- fn maybe_indirection_for_unsized(
- &self,
- err: &mut Diagnostic,
- item: &'tcx Item<'tcx>,
- param: &'tcx GenericParam<'tcx>,
- ) -> bool;
-
- fn is_recursive_obligation(
- &self,
- obligated_types: &mut Vec<Ty<'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,
- obligation: PredicateObligation<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
- span: Span,
- ) -> GetSafeTransmuteErrorAndReason;
-
- 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_opaque_type_auto_trait_leakage(
- &self,
- obligation: &PredicateObligation<'tcx>,
- def_id: DefId,
- ) -> 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> {
- // returns if `cond` not occurring implies that `error` does not occur - i.e., that
- // `error` occurring implies that `cond` occurs.
- fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
- if cond == error {
- return true;
- }
-
- // FIXME: It should be possible to deal with `ForAll` in a cleaner way.
- let bound_error = error.kind();
- let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) {
- (
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)),
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(error)),
- ) => (cond, bound_error.rebind(error)),
- _ => {
- // FIXME: make this work in other cases too.
- return false;
- }
- };
-
- for pred in super::elaborate(self.tcx, std::iter::once(cond)) {
- let bound_predicate = pred.kind();
- if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(implication)) =
- bound_predicate.skip_binder()
- {
- let error = error.to_poly_trait_ref();
- let implication = bound_predicate.rebind(implication.trait_ref);
- // FIXME: I'm just not taking associated types at all here.
- // Eventually I'll need to implement param-env-aware
- // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
- let param_env = ty::ParamEnv::empty();
- if self.can_sub(param_env, error, implication) {
- debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
- return true;
- }
- }
- }
-
- false
- }
-
- #[instrument(skip(self), level = "debug")]
- fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
- if self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError {
- dump_proof_tree(&error.root_obligation, self.infcx);
- }
-
- match error.code {
- FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
- self.report_selection_error(
- error.obligation.clone(),
- &error.root_obligation,
- selection_error,
- );
- }
- FulfillmentErrorCode::CodeProjectionError(ref e) => {
- self.report_projection_error(&error.obligation, e);
- }
- FulfillmentErrorCode::CodeAmbiguity { overflow: false } => {
- self.maybe_report_ambiguity(&error.obligation);
- }
- FulfillmentErrorCode::CodeAmbiguity { overflow: true } => {
- self.report_overflow_no_abort(error.obligation.clone());
- }
- FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
- self.report_mismatched_types(
- &error.obligation.cause,
- expected_found.expected,
- expected_found.found,
- *err,
- )
- .emit();
- }
- FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
- let mut diag = self.report_mismatched_consts(
- &error.obligation.cause,
- expected_found.expected,
- expected_found.found,
- *err,
- );
- let code = error.obligation.cause.code().peel_derives().peel_match_impls();
- if let ObligationCauseCode::BindingObligation(..)
- | ObligationCauseCode::ItemObligation(..)
- | ObligationCauseCode::ExprBindingObligation(..)
- | ObligationCauseCode::ExprItemObligation(..) = code
- {
- self.note_obligation_cause_code(
- error.obligation.cause.body_id,
- &mut diag,
- error.obligation.predicate,
- error.obligation.param_env,
- code,
- &mut vec![],
- &mut Default::default(),
- );
- }
- diag.emit();
- }
- FulfillmentErrorCode::CodeCycle(ref cycle) => {
- self.report_overflow_obligation_cycle(cycle);
- }
- }
- }
-
- #[instrument(level = "debug", skip_all)]
- fn report_projection_error(
- &self,
- obligation: &PredicateObligation<'tcx>,
- error: &MismatchedProjectionTypes<'tcx>,
- ) {
- let predicate = self.resolve_vars_if_possible(obligation.predicate);
-
- if predicate.references_error() {
- return;
- }
-
- self.probe(|_| {
- let ocx = ObligationCtxt::new(self);
-
- // try to find the mismatched types to report the error with.
- //
- // this can fail if the problem was higher-ranked, in which
- // cause I have no idea for a good error message.
- let bound_predicate = predicate.kind();
- let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) =
- bound_predicate.skip_binder()
- {
- let data = self.instantiate_binder_with_fresh_vars(
- obligation.cause.span,
- infer::LateBoundRegionConversionTime::HigherRankedType,
- bound_predicate.rebind(data),
- );
- let unnormalized_term = match data.term.unpack() {
- ty::TermKind::Ty(_) => Ty::new_projection(
- self.tcx,
- data.projection_ty.def_id,
- data.projection_ty.args,
- )
- .into(),
- ty::TermKind::Const(ct) => ty::Const::new_unevaluated(
- self.tcx,
- ty::UnevaluatedConst {
- def: data.projection_ty.def_id,
- args: data.projection_ty.args,
- },
- ct.ty(),
- )
- .into(),
- };
- // FIXME(-Ztrait-solver=next): For diagnostic purposes, it would be nice
- // to deeply normalize this type.
- let normalized_term =
- ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
-
- debug!(?obligation.cause, ?obligation.param_env);
-
- debug!(?normalized_term, data.ty = ?data.term);
-
- let is_normalized_term_expected = !matches!(
- obligation.cause.code().peel_derives(),
- ObligationCauseCode::ItemObligation(_)
- | ObligationCauseCode::BindingObligation(_, _)
- | ObligationCauseCode::ExprItemObligation(..)
- | ObligationCauseCode::ExprBindingObligation(..)
- | ObligationCauseCode::Coercion { .. }
- | ObligationCauseCode::OpaqueType
- );
-
- // constrain inference variables a bit more to nested obligations from normalize so
- // we can have more helpful errors.
- //
- // we intentionally drop errors from normalization here,
- // since the normalization is just done to improve the error message.
- let _ = ocx.select_where_possible();
-
- if let Err(new_err) = ocx.eq_exp(
- &obligation.cause,
- obligation.param_env,
- is_normalized_term_expected,
- normalized_term,
- data.term,
- ) {
- (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
- } else {
- (None, error.err)
- }
- } else {
- (None, error.err)
- };
-
- let msg = values
- .and_then(|(predicate, _, normalized_term, expected_term)| {
- self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
- })
- .unwrap_or_else(|| {
- 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(10),
- ))
- .unwrap()
- .into_buffer()
- ))
- });
- let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
-
- let secondary_span = (|| {
- let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
- predicate.kind().skip_binder()
- else {
- return None;
- };
-
- let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_ty.def_id)?;
- let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
-
- let mut associated_items = vec![];
- self.tcx.for_each_relevant_impl(
- self.tcx.trait_of_item(proj.projection_ty.def_id)?,
- proj.projection_ty.self_ty(),
- |impl_def_id| {
- associated_items.extend(
- self.tcx
- .associated_items(impl_def_id)
- .in_definition_order()
- .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident),
- );
- },
- );
-
- let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
- return None;
- };
- match self.tcx.hir().get_if_local(associated_item.def_id) {
- Some(
- hir::Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Type(_, Some(ty)),
- ..
- })
- | hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Type(ty),
- ..
- }),
- ) => Some((
- ty.span,
- with_forced_trimmed_paths!(Cow::from(format!(
- "type mismatch resolving `{}`",
- self.resolve_vars_if_possible(predicate)
- .print(FmtPrinter::new_with_limit(
- self.tcx,
- Namespace::TypeNS,
- rustc_session::Limit(5),
- ))
- .unwrap()
- .into_buffer()
- ))),
- )),
- _ => None,
- }
- })();
-
- self.note_type_err(
- &mut diag,
- &obligation.cause,
- secondary_span,
- values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
- infer::ValuePairs::Terms(ExpectedFound::new(
- is_normalized_ty_expected,
- normalized_ty,
- expected_ty,
- ))
- }),
- err,
- true,
- false,
- );
- self.note_obligation_cause(&mut diag, obligation);
- diag.emit();
- });
- }
-
- fn maybe_detailed_projection_msg(
- &self,
- pred: ty::ProjectionPredicate<'tcx>,
- normalized_ty: ty::Term<'tcx>,
- expected_ty: ty::Term<'tcx>,
- ) -> Option<String> {
- let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
- let self_ty = pred.projection_ty.self_ty();
-
- with_forced_trimmed_paths! {
- if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
- let fn_kind = self_ty.prefix_string(self.tcx);
- let item = match self_ty.kind() {
- ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
- _ => self_ty.to_string(),
- };
- Some(format!(
- "expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \
- returns `{normalized_ty}`",
- ))
- } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
- Some(format!(
- "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
- resolves to `{normalized_ty}`"
- ))
- } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
- Some(format!(
- "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
- yields `{normalized_ty}`"
- ))
- } else {
- None
- }
- }
- }
-
- fn fuzzy_match_tys(
- &self,
- mut a: Ty<'tcx>,
- mut b: Ty<'tcx>,
- ignoring_lifetimes: bool,
- ) -> Option<CandidateSimilarity> {
- /// returns the fuzzy category of a given type, or None
- /// if the type can be equated to any type.
- fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
- match t.kind() {
- ty::Bool => Some(0),
- ty::Char => Some(1),
- ty::Str => Some(2),
- ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => Some(2),
- ty::Int(..)
- | ty::Uint(..)
- | ty::Float(..)
- | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4),
- ty::Ref(..) | ty::RawPtr(..) => Some(5),
- ty::Array(..) | ty::Slice(..) => Some(6),
- ty::FnDef(..) | ty::FnPtr(..) => Some(7),
- ty::Dynamic(..) => Some(8),
- ty::Closure(..) => Some(9),
- ty::Tuple(..) => Some(10),
- ty::Param(..) => Some(11),
- ty::Alias(ty::Projection, ..) => Some(12),
- ty::Alias(ty::Inherent, ..) => Some(13),
- ty::Alias(ty::Opaque, ..) => Some(14),
- ty::Alias(ty::Weak, ..) => Some(15),
- ty::Never => Some(16),
- ty::Adt(..) => Some(17),
- ty::Generator(..) => Some(18),
- ty::Foreign(..) => Some(19),
- ty::GeneratorWitness(..) => Some(20),
- ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
- }
- }
-
- let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {
- loop {
- match t.kind() {
- ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => {
- t = *inner
- }
- _ => break t,
- }
- }
- };
-
- if !ignoring_lifetimes {
- a = strip_references(a);
- b = strip_references(b);
- }
-
- let cat_a = type_category(self.tcx, a)?;
- let cat_b = type_category(self.tcx, b)?;
- if a == b {
- Some(CandidateSimilarity::Exact { ignoring_lifetimes })
- } else if cat_a == cat_b {
- match (a.kind(), b.kind()) {
- (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,
- (ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b,
- // Matching on references results in a lot of unhelpful
- // suggestions, so let's just not do that for now.
- //
- // We still upgrade successful matches to `ignoring_lifetimes: true`
- // to prioritize that impl.
- (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => {
- self.fuzzy_match_tys(a, b, true).is_some()
- }
- _ => true,
- }
- .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes })
- } else if ignoring_lifetimes {
- None
- } else {
- self.fuzzy_match_tys(a, b, true)
- }
- }
-
- fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
- self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| match gen_kind {
- hir::GeneratorKind::Gen => "a generator",
- hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block",
- hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function",
- hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure",
- })
- }
-
- fn find_similar_impl_candidates(
- &self,
- trait_pred: ty::PolyTraitPredicate<'tcx>,
- ) -> Vec<ImplCandidate<'tcx>> {
- let mut candidates: Vec<_> = self
- .tcx
- .all_impls(trait_pred.def_id())
- .filter_map(|def_id| {
- if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
- || !self.tcx.is_user_visible_dep(def_id.krate)
- {
- return None;
- }
-
- let imp = self.tcx.impl_trait_ref(def_id).unwrap().skip_binder();
-
- self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
- .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
- })
- .collect();
- if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
- // If any of the candidates is a perfect match, we don't want to show all of them.
- // This is particularly relevant for the case of numeric types (as they all have the
- // same category).
- candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
- }
- candidates
- }
-
- fn report_similar_impl_candidates(
- &self,
- impl_candidates: &[ImplCandidate<'tcx>],
- trait_ref: ty::PolyTraitRef<'tcx>,
- body_def_id: LocalDefId,
- err: &mut Diagnostic,
- other: bool,
- ) -> bool {
- let other = if other { "other " } else { "" };
- let report = |candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
- if candidates.is_empty() {
- return false;
- }
- if let &[cand] = &candidates[..] {
- let (desc, mention_castable) =
- match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
- (ty::FnPtr(_), ty::FnDef(..)) => {
- (" implemented for fn pointer `", ", cast using `as`")
- }
- (ty::FnPtr(_), _) => (" implemented for fn pointer `", ""),
- _ => (" implemented for `", ""),
- };
- err.highlighted_help(vec![
- (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
- ("is".to_string(), Style::Highlight),
- (desc.to_string(), Style::NoStyle),
- (cand.self_ty().to_string(), Style::Highlight),
- ("`".to_string(), Style::NoStyle),
- (mention_castable.to_string(), Style::NoStyle),
- ]);
- return true;
- }
- let trait_ref = TraitRef::identity(self.tcx, candidates[0].def_id);
- // Check if the trait is the same in all cases. If so, we'll only show the type.
- let mut traits: Vec<_> =
- candidates.iter().map(|c| c.print_only_trait_path().to_string()).collect();
- traits.sort();
- traits.dedup();
- // FIXME: this could use a better heuristic, like just checking
- // that args[1..] is the same.
- let all_traits_equal = traits.len() == 1;
-
- let candidates: Vec<String> = candidates
- .into_iter()
- .map(|c| {
- if all_traits_equal {
- format!("\n {}", c.self_ty())
- } else {
- format!("\n {c}")
- }
- })
- .collect();
-
- let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
- err.help(format!(
- "the following {other}types implement trait `{}`:{}{}",
- trait_ref.print_only_trait_path(),
- candidates[..end].join(""),
- if candidates.len() > 9 {
- format!("\nand {} others", candidates.len() - 8)
- } else {
- String::new()
- }
- ));
- true
- };
-
- let def_id = trait_ref.def_id();
- if impl_candidates.is_empty() {
- if self.tcx.trait_is_auto(def_id)
- || self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
- || self.tcx.get_diagnostic_name(def_id).is_some()
- {
- // Mentioning implementers of `Copy`, `Debug` and friends is not useful.
- return false;
- }
- let mut impl_candidates: Vec<_> = self
- .tcx
- .all_impls(def_id)
- // Ignore automatically derived impls and `!Trait` impls.
- .filter(|&def_id| {
- self.tcx.impl_polarity(def_id) != ty::ImplPolarity::Negative
- || self.tcx.is_automatically_derived(def_id)
- })
- .filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
- .map(ty::EarlyBinder::instantiate_identity)
- .filter(|trait_ref| {
- let self_ty = trait_ref.self_ty();
- // Avoid mentioning type parameters.
- if let ty::Param(_) = self_ty.kind() {
- false
- }
- // Avoid mentioning types that are private to another crate
- else if let ty::Adt(def, _) = self_ty.peel_refs().kind() {
- // FIXME(compiler-errors): This could be generalized, both to
- // be more granular, and probably look past other `#[fundamental]`
- // types, too.
- self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx)
- } else {
- true
- }
- })
- .collect();
-
- impl_candidates.sort();
- impl_candidates.dedup();
- return report(impl_candidates, err);
- }
-
- // Sort impl candidates so that ordering is consistent for UI tests.
- // because the ordering of `impl_candidates` may not be deterministic:
- // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
- //
- // Prefer more similar candidates first, then sort lexicographically
- // by their normalized string representation.
- let mut impl_candidates: Vec<_> = impl_candidates
- .iter()
- .cloned()
- .map(|mut cand| {
- // Fold the consts so that they shows up as, e.g., `10`
- // instead of `core::::array::{impl#30}::{constant#0}`.
- cand.trait_ref = cand.trait_ref.fold_with(&mut BottomUpFolder {
- tcx: self.tcx,
- ty_op: |ty| ty,
- lt_op: |lt| lt,
- ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
- });
- cand
- })
- .collect();
- impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref));
- impl_candidates.dedup();
-
- report(impl_candidates.into_iter().map(|cand| cand.trait_ref).collect(), 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,
- code: &ObligationCauseCode<'tcx>,
- ) -> Option<(String, Option<Span>)> {
- match code {
- ObligationCauseCode::BuiltinDerivedObligation(data) => {
- let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
- match self.get_parent_trait_ref(&data.parent_code) {
- Some(t) => Some(t),
- None => {
- let ty = parent_trait_ref.skip_binder().self_ty();
- let span = TyCategory::from_ty(self.tcx, ty)
- .map(|(_, def_id)| self.tcx.def_span(def_id));
- Some((ty.to_string(), span))
- }
- }
- }
- ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
- self.get_parent_trait_ref(&parent_code)
- }
- _ => None,
- }
- }
-
- /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
- /// with the same path as `trait_ref`, a help message about
- /// a probable version mismatch is added to `err`
- fn note_version_mismatch(
- &self,
- err: &mut Diagnostic,
- trait_ref: &ty::PolyTraitRef<'tcx>,
- ) -> bool {
- let get_trait_impls = |trait_def_id| {
- let mut trait_impls = vec![];
- self.tcx.for_each_relevant_impl(
- trait_def_id,
- trait_ref.skip_binder().self_ty(),
- |impl_def_id| {
- trait_impls.push(impl_def_id);
- },
- );
- trait_impls
- };
-
- let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
- let traits_with_same_path: std::collections::BTreeSet<_> = self
- .tcx
- .all_traits()
- .filter(|trait_def_id| *trait_def_id != trait_ref.def_id())
- .filter(|trait_def_id| self.tcx.def_path_str(*trait_def_id) == required_trait_path)
- .collect();
- let mut suggested = false;
- for trait_with_same_path in traits_with_same_path {
- let trait_impls = get_trait_impls(trait_with_same_path);
- if trait_impls.is_empty() {
- continue;
- }
- let impl_spans: Vec<_> =
- trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect();
- err.span_help(
- impl_spans,
- format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
- );
- let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
- let crate_msg =
- format!("perhaps two different versions of crate `{trait_crate}` are being used?");
- err.note(crate_msg);
- suggested = true;
- }
- suggested
- }
-
- fn mk_trait_obligation_with_new_self_ty(
- &self,
- param_env: ty::ParamEnv<'tcx>,
- trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
- ) -> PredicateObligation<'tcx> {
- let trait_pred =
- trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty));
-
- Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
- }
-
- #[instrument(skip(self), level = "debug")]
- fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
- // Unable to successfully determine, probably means
- // insufficient type information, but could mean
- // ambiguous impls. The latter *ought* to be a
- // coherence violation, so we don't report it here.
-
- let predicate = self.resolve_vars_if_possible(obligation.predicate);
- let span = obligation.cause.span;
-
- debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
-
- // Ambiguity errors are often caused as fallout from earlier errors.
- // We ignore them if this `infcx` is tainted in some cases below.
-
- let bound_predicate = predicate.kind();
- let mut err = match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
- let trait_ref = bound_predicate.rebind(data.trait_ref);
- debug!(?trait_ref);
-
- if predicate.references_error() {
- return;
- }
-
- // This is kind of a hack: it frequently happens that some earlier
- // error prevents types from being fully inferred, and then we get
- // a bunch of uninteresting errors saying something like "<generic
- // #0> doesn't implement Sized". It may even be true that we
- // could just skip over all checks where the self-ty is an
- // inference variable, but I was afraid that there might be an
- // inference variable created, registered as an obligation, and
- // then never forced by writeback, and hence by skipping here we'd
- // be ignoring the fact that we don't KNOW the type works
- // out. Though even that would probably be harmless, given that
- // we're only talking about builtin traits, which are known to be
- // inhabited. We used to check for `self.tcx.sess.has_errors()` to
- // avoid inundating the user with unnecessary errors, but we now
- // check upstream for type errors and don't add the obligations to
- // begin with in those cases.
- if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
- if let None = self.tainted_by_errors() {
- self.emit_inference_failure_err(
- obligation.cause.body_id,
- span,
- trait_ref.self_ty().skip_binder().into(),
- ErrorCode::E0282,
- false,
- )
- .emit();
- }
- return;
- }
-
- // Typically, this ambiguity should only happen if
- // there are unresolved type inference variables
- // (otherwise it would suggest a coherence
- // failure). But given #21974 that is not necessarily
- // the case -- we can have multiple where clauses that
- // are only distinguished by a region, which results
- // in an ambiguity even when all types are fully
- // known, since we don't dispatch based on region
- // relationships.
-
- // Pick the first substitution that still contains inference variables as the one
- // we're going to emit an error for. If there are none (see above), fall back to
- // a more general error.
- let subst = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
-
- let mut err = if let Some(subst) = subst {
- self.emit_inference_failure_err(
- obligation.cause.body_id,
- span,
- subst,
- ErrorCode::E0283,
- true,
- )
- } else {
- struct_span_err!(
- self.tcx.sess,
- span,
- E0283,
- "type annotations needed: cannot satisfy `{}`",
- predicate,
- )
- };
-
- let ambiguities = ambiguity::recompute_applicable_impls(
- self.infcx,
- &obligation.with(self.tcx, trait_ref),
- );
- let has_non_region_infer =
- trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
- // It doesn't make sense to talk about applicable impls if there are more
- // than a handful of them.
- if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
- if self.tainted_by_errors().is_some() && subst.is_none() {
- // If `subst.is_none()`, then this is probably two param-env
- // candidates or impl candidates that are equal modulo lifetimes.
- // Therefore, if we've already emitted an error, just skip this
- // one, since it's not particularly actionable.
- err.cancel();
- return;
- }
- self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
- } else {
- if self.tainted_by_errors().is_some() {
- err.cancel();
- return;
- }
- err.note(format!("cannot satisfy `{predicate}`"));
- let impl_candidates = self
- .find_similar_impl_candidates(predicate.to_opt_poly_trait_pred().unwrap());
- if impl_candidates.len() < 10 {
- self.report_similar_impl_candidates(
- impl_candidates.as_slice(),
- trait_ref,
- obligation.cause.body_id,
- &mut err,
- false,
- );
- }
- }
-
- if let ObligationCauseCode::ItemObligation(def_id)
- | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code()
- {
- self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
- }
-
- if let Some(ty::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack())
- && let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
- {
- let mut expr_finder = FindExprBySpan::new(span);
- expr_finder.visit_expr(&self.tcx.hir().body(body_id).value);
-
- if let Some(hir::Expr {
- kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), .. }
- ) = expr_finder.result
- && let [
- ..,
- trait_path_segment @ hir::PathSegment {
- res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id),
- ..
- },
- hir::PathSegment {
- ident: assoc_item_name,
- res: rustc_hir::def::Res::Def(_, item_id),
- ..
- }
- ] = path.segments
- && data.trait_ref.def_id == *trait_id
- && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
- && let None = self.tainted_by_errors()
- {
- let (verb, noun) = match self.tcx.associated_item(item_id).kind {
- ty::AssocKind::Const => ("refer to the", "constant"),
- ty::AssocKind::Fn => ("call", "function"),
- ty::AssocKind::Type => ("refer to the", "type"), // this is already covered by E0223, but this single match arm doesn't hurt here
- };
-
- // Replace the more general E0283 with a more specific error
- err.cancel();
- err = self.tcx.sess.struct_span_err_with_code(
- span,
- format!(
- "cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type",
- ),
- rustc_errors::error_code!(E0790),
- );
-
- if let Some(local_def_id) = data.trait_ref.def_id.as_local()
- && let Some(hir::Node::Item(hir::Item { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. })) = self.tcx.hir().find_by_def_id(local_def_id)
- && let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) {
- err.span_label(method_ref.span, format!("`{trait_name}::{assoc_item_name}` defined here"));
- }
-
- err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
-
- let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
-
- if trait_impls.blanket_impls().is_empty()
- && let Some(impl_def_id) = trait_impls.non_blanket_impls().values().flatten().next()
- {
- let non_blanket_impl_count = trait_impls.non_blanket_impls().values().flatten().count();
- // If there is only one implementation of the trait, suggest using it.
- // Otherwise, use a placeholder comment for the implementation.
- let (message, impl_suggestion) = if non_blanket_impl_count == 1 {(
- "use the fully-qualified path to the only available implementation",
- format!("<{} as ", self.tcx.type_of(impl_def_id).instantiate_identity())
- )} else {
- ("use a fully-qualified path to a specific available implementation",
- "</* self type */ as ".to_string()
- )};
- let mut suggestions = vec![(
- path.span.shrink_to_lo(),
- impl_suggestion
- )];
- if let Some(generic_arg) = trait_path_segment.args {
- let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext);
- // get rid of :: between Trait and <type>
- // must be '::' between them, otherwise the parser won't accept the code
- suggestions.push((between_span, "".to_string(),));
- suggestions.push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
- } else {
- suggestions.push((trait_path_segment.ident.span.shrink_to_hi(), ">".to_string()));
- }
- err.multipart_suggestion(
- message,
- suggestions,
- Applicability::MaybeIncorrect
- );
- }
- }
- };
-
- err
- }
-
- ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
- // Same hacky approach as above to avoid deluging user
- // with error messages.
- if arg.references_error()
- || self.tcx.sess.has_errors().is_some()
- || self.tainted_by_errors().is_some()
- {
- return;
- }
-
- self.emit_inference_failure_err(
- obligation.cause.body_id,
- span,
- arg,
- ErrorCode::E0282,
- false,
- )
- }
-
- ty::PredicateKind::Subtype(data) => {
- if data.references_error()
- || self.tcx.sess.has_errors().is_some()
- || self.tainted_by_errors().is_some()
- {
- // no need to overload user in such cases
- return;
- }
- let SubtypePredicate { a_is_expected: _, a, b } = data;
- // both must be type variables, or the other would've been instantiated
- assert!(a.is_ty_var() && b.is_ty_var());
- self.emit_inference_failure_err(
- obligation.cause.body_id,
- span,
- a.into(),
- ErrorCode::E0282,
- true,
- )
- }
- ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
- if predicate.references_error() || self.tainted_by_errors().is_some() {
- return;
- }
- let subst = data
- .projection_ty
- .args
- .iter()
- .chain(Some(data.term.into_arg()))
- .find(|g| g.has_non_region_infer());
- if let Some(subst) = subst {
- let mut err = self.emit_inference_failure_err(
- obligation.cause.body_id,
- span,
- subst,
- ErrorCode::E0284,
- true,
- );
- err.note(format!("cannot satisfy `{predicate}`"));
- err
- } else {
- // If we can't find a substitution, just print a generic error
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0284,
- "type annotations needed: cannot satisfy `{}`",
- predicate,
- );
- err.span_label(span, format!("cannot satisfy `{predicate}`"));
- err
- }
- }
-
- ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
- if predicate.references_error() || self.tainted_by_errors().is_some() {
- return;
- }
- let subst = data.walk().find(|g| g.is_non_region_infer());
- if let Some(subst) = subst {
- let err = self.emit_inference_failure_err(
- obligation.cause.body_id,
- span,
- subst,
- ErrorCode::E0284,
- true,
- );
- err
- } else {
- // If we can't find a substitution, just print a generic error
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0284,
- "type annotations needed: cannot satisfy `{}`",
- predicate,
- );
- err.span_label(span, format!("cannot satisfy `{predicate}`"));
- err
- }
- }
- _ => {
- if self.tcx.sess.has_errors().is_some() || self.tainted_by_errors().is_some() {
- return;
- }
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0284,
- "type annotations needed: cannot satisfy `{}`",
- predicate,
- );
- err.span_label(span, format!("cannot satisfy `{predicate}`"));
- err
- }
- };
- self.note_obligation_cause(&mut err, obligation);
- err.emit();
- }
-
- fn annotate_source_of_ambiguity(
- &self,
- err: &mut Diagnostic,
- ambiguities: &[ambiguity::Ambiguity],
- predicate: ty::Predicate<'tcx>,
- ) {
- let mut spans = vec![];
- let mut crates = vec![];
- let mut post = vec![];
- let mut has_param_env = false;
- for ambiguity in ambiguities {
- match ambiguity {
- ambiguity::Ambiguity::DefId(impl_def_id) => {
- match self.tcx.span_of_impl(*impl_def_id) {
- Ok(span) => spans.push(span),
- Err(name) => {
- crates.push(name);
- if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
- post.push(header);
- }
- }
- }
- }
- ambiguity::Ambiguity::ParamEnv(span) => {
- has_param_env = true;
- spans.push(*span);
- }
- }
- }
- let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
- crate_names.sort();
- crate_names.dedup();
- post.sort();
- post.dedup();
-
- if self.tainted_by_errors().is_some()
- && (crate_names.len() == 1
- && spans.len() == 0
- && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
- || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
- {
- // Avoid complaining about other inference issues for expressions like
- // `42 >> 1`, where the types are still `{integer}`, but we want to
- // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
- // NOTE(eddyb) this was `.cancel()`, but `err`
- // is borrowed, so we can't fully defuse it.
- err.downgrade_to_delayed_bug();
- return;
- }
-
- let msg = format!(
- "multiple `impl`s{} satisfying `{}` found",
- if has_param_env { " or `where` clauses" } else { "" },
- predicate
- );
- let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
- format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
- } else if post.len() == 1 {
- format!(": `{}`", post[0])
- } else {
- String::new()
- };
-
- match (spans.len(), crates.len(), crate_names.len()) {
- (0, 0, 0) => {
- err.note(format!("cannot satisfy `{predicate}`"));
- }
- (0, _, 1) => {
- err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
- }
- (0, _, _) => {
- err.note(format!(
- "{} in the following crates: {}{}",
- msg,
- crate_names.join(", "),
- post,
- ));
- }
- (_, 0, 0) => {
- let span: MultiSpan = spans.into();
- err.span_note(span, msg);
- }
- (_, 1, 1) => {
- let span: MultiSpan = spans.into();
- err.span_note(span, msg);
- err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
- }
- _ => {
- let span: MultiSpan = spans.into();
- err.span_note(span, msg);
- err.note(format!(
- "and more `impl`s found in the following crates: {}{}",
- crate_names.join(", "),
- post,
- ));
- }
- }
- }
-
- /// Returns `true` if the trait predicate may apply for *some* assignment
- /// to the type parameters.
- fn predicate_can_apply(
- &self,
- param_env: ty::ParamEnv<'tcx>,
- pred: ty::PolyTraitPredicate<'tcx>,
- ) -> bool {
- struct ParamToVarFolder<'a, 'tcx> {
- infcx: &'a InferCtxt<'tcx>,
- var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
- }
-
- impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ParamToVarFolder<'a, 'tcx> {
- fn interner(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if let ty::Param(_) = *ty.kind() {
- let infcx = self.infcx;
- *self.var_map.entry(ty).or_insert_with(|| {
- infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: DUMMY_SP,
- })
- })
- } else {
- ty.super_fold_with(self)
- }
- }
- }
-
- self.probe(|_| {
- let cleaned_pred =
- pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
-
- let InferOk { value: cleaned_pred, .. } =
- self.infcx.at(&ObligationCause::dummy(), param_env).normalize(cleaned_pred);
-
- let obligation =
- Obligation::new(self.tcx, ObligationCause::dummy(), param_env, cleaned_pred);
-
- self.predicate_may_hold(&obligation)
- })
- }
-
- fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>) {
- // First, attempt to add note to this error with an async-await-specific
- // message, and fall back to regular note otherwise.
- if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
- self.note_obligation_cause_code(
- obligation.cause.body_id,
- err,
- obligation.predicate,
- obligation.param_env,
- obligation.cause.code(),
- &mut vec![],
- &mut Default::default(),
- );
- self.suggest_unsized_bound_if_applicable(err, obligation);
- }
- }
-
- #[instrument(level = "debug", skip_all)]
- fn suggest_unsized_bound_if_applicable(
- &self,
- err: &mut Diagnostic,
- obligation: &PredicateObligation<'tcx>,
- ) {
- let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
- obligation.predicate.kind().skip_binder()
- else {
- return;
- };
- let (ObligationCauseCode::BindingObligation(item_def_id, span)
- | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) =
- *obligation.cause.code().peel_derives()
- else {
- return;
- };
- debug!(?pred, ?item_def_id, ?span);
-
- let (Some(node), true) = (
- self.tcx.hir().get_if_local(item_def_id),
- Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
- ) else {
- return;
- };
- self.maybe_suggest_unsized_generics(err, span, node);
- }
-
- #[instrument(level = "debug", skip_all)]
- fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>) {
- let Some(generics) = node.generics() else {
- return;
- };
- let sized_trait = self.tcx.lang_items().sized_trait();
- debug!(?generics.params);
- debug!(?generics.predicates);
- let Some(param) = generics.params.iter().find(|param| param.span == span) else {
- return;
- };
- // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
- // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
- let explicitly_sized = generics
- .bounds_for_param(param.def_id)
- .flat_map(|bp| bp.bounds)
- .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
- if explicitly_sized {
- return;
- }
- debug!(?param);
- match node {
- hir::Node::Item(
- item @ hir::Item {
- // Only suggest indirection for uses of type parameters in ADTs.
- kind:
- hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
- ..
- },
- ) => {
- if self.maybe_indirection_for_unsized(err, item, param) {
- return;
- }
- }
- _ => {}
- };
- // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
- let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param.def_id)
- {
- (s, " +")
- } else {
- (span.shrink_to_hi(), ":")
- };
- err.span_suggestion_verbose(
- span,
- "consider relaxing the implicit `Sized` restriction",
- format!("{separator} ?Sized"),
- Applicability::MachineApplicable,
- );
- }
-
- fn maybe_indirection_for_unsized(
- &self,
- err: &mut Diagnostic,
- item: &Item<'tcx>,
- param: &GenericParam<'tcx>,
- ) -> bool {
- // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
- // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
- // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
- let mut visitor =
- FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
- visitor.visit_item(item);
- if visitor.invalid_spans.is_empty() {
- return false;
- }
- let mut multispan: MultiSpan = param.span.into();
- multispan.push_span_label(
- param.span,
- format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
- );
- for sp in visitor.invalid_spans {
- multispan.push_span_label(
- sp,
- format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
- );
- }
- err.span_help(
- multispan,
- format!(
- "you could relax the implicit `Sized` bound on `{T}` if it were \
- used through indirection like `&{T}` or `Box<{T}>`",
- T = param.name.ident(),
- ),
- );
- true
- }
-
- fn is_recursive_obligation(
- &self,
- obligated_types: &mut Vec<Ty<'tcx>>,
- cause_code: &ObligationCauseCode<'tcx>,
- ) -> bool {
- if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
- let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
- let self_ty = parent_trait_ref.skip_binder().self_ty();
- if obligated_types.iter().any(|ot| ot == &self_ty) {
- return true;
- }
- if let ty::Adt(def, args) = self_ty.kind()
- && let [arg] = &args[..]
- && let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Adt(inner_def, _) = ty.kind()
- && inner_def == def
- {
- return true;
- }
- }
- false
- }
-
- fn get_standard_error_message(
- &self,
- trait_predicate: &ty::PolyTraitPredicate<'tcx>,
- message: Option<String>,
- predicate_is_const: bool,
- append_const_msg: Option<AppendConstMessage>,
- post_message: String,
- ) -> String {
- message
- .and_then(|cannot_do_this| {
- match (predicate_is_const, append_const_msg) {
- // do nothing if predicate is not const
- (false, _) => Some(cannot_do_this),
- // suggested using default post message
- (true, Some(AppendConstMessage::Default)) => {
- Some(format!("{cannot_do_this} in const contexts"))
- }
- // overridden post message
- (true, Some(AppendConstMessage::Custom(custom_msg))) => {
- Some(format!("{cannot_do_this}{custom_msg}"))
- }
- // fallback to generic message
- (true, None) => None,
- }
- })
- .unwrap_or_else(|| {
- format!("the trait bound `{trait_predicate}` is not satisfied{post_message}")
- })
- }
-
- fn get_safe_transmute_error_and_reason(
- &self,
- obligation: PredicateObligation<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
- span: Span,
- ) -> GetSafeTransmuteErrorAndReason {
- use rustc_transmute::Answer;
-
- // Erase regions because layout code doesn't particularly care about regions.
- let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
-
- let src_and_dst = rustc_transmute::Types {
- dst: trait_ref.args.type_at(0),
- src: trait_ref.args.type_at(1),
- };
- let scope = trait_ref.args.type_at(2);
- let Some(assume) = rustc_transmute::Assume::from_const(
- self.infcx.tcx,
- obligation.param_env,
- trait_ref.args.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(
- obligation.cause,
- src_and_dst,
- scope,
- assume,
- ) {
- Answer::No(reason) => {
- let dst = trait_ref.args.type_at(0);
- let src = trait_ref.args.type_at(1);
- let err_msg = format!(
- "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
- );
- let safe_transmute_explanation = match reason {
- rustc_transmute::Reason::SrcIsUnspecified => {
- format!("`{src}` does not have a well-specified layout")
- }
-
- rustc_transmute::Reason::DstIsUnspecified => {
- 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}`")
- }
-
- rustc_transmute::Reason::DstIsPrivate => format!(
- "`{dst}` is or contains a type or field that is not visible in that scope"
- ),
- rustc_transmute::Reason::DstIsTooBig => {
- format!("The size of `{src}` is smaller than the size of `{dst}`")
- }
- rustc_transmute::Reason::SrcSizeOverflow => {
- format!(
- "values of the type `{src}` are too big for the current architecture"
- )
- }
- rustc_transmute::Reason::DstSizeOverflow => {
- format!(
- "values of the type `{dst}` are too big for the current architecture"
- )
- }
- rustc_transmute::Reason::DstHasStricterAlignment {
- src_min_align,
- dst_min_align,
- } => {
- format!(
- "The minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
- )
- }
- rustc_transmute::Reason::DstIsMoreUnique => {
- format!("`{src}` is a shared reference, but `{dst}` is a unique reference")
- }
- // Already reported by rustc
- rustc_transmute::Reason::TypeError => {
- return GetSafeTransmuteErrorAndReason::Silent;
- }
- rustc_transmute::Reason::SrcLayoutUnknown => {
- format!("`{src}` has an unknown layout")
- }
- rustc_transmute::Reason::DstLayoutUnknown => {
- format!("`{dst}` has an unknown layout")
- }
- };
- GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation }
- }
- // Should never get a Yes at this point! We already ran it before, and did not get a Yes.
- Answer::Yes => span_bug!(
- span,
- "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
- ),
- other => span_bug!(span, "Unsupported rustc_transmute::Answer variant: `{other:?}`"),
- }
- }
-
- 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;
- let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } =
- obligation.cause.code()
- {
- *rhs_span
- } else {
- span
- };
-
- // Try to report a help message
- if is_fn_trait
- && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
- obligation.param_env,
- trait_ref.self_ty(),
- trait_predicate.skip_binder().polarity,
- )
- {
- self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
- } else if !trait_ref.has_non_region_infer()
- && self.predicate_can_apply(obligation.param_env, *trait_predicate)
- {
- // If a where-clause may be useful, remind the
- // user that they can add it.
- //
- // don't display an on-unimplemented note, as
- // these notes will often be of the form
- // "the type `T` can't be frobnicated"
- // which is somewhat confusing.
- self.suggest_restricting_param_bound(
- err,
- *trait_predicate,
- None,
- obligation.cause.body_id,
- );
- } else if trait_ref.def_id().is_local()
- && self.tcx.trait_impls_of(trait_ref.def_id()).is_empty()
- && !self.tcx.trait_is_auto(trait_ref.def_id())
- && !self.tcx.trait_is_alias(trait_ref.def_id())
- {
- err.span_help(
- self.tcx.def_span(trait_ref.def_id()),
- crate::fluent_generated::trait_selection_trait_has_no_impls,
- );
- } else if !suggested && !unsatisfied_const {
- // Can't show anything else useful, try to find similar impls.
- let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
- if !self.report_similar_impl_candidates(
- &impl_candidates,
- trait_ref,
- body_def_id,
- err,
- true,
- ) {
- self.report_similar_impl_candidates_for_root_obligation(
- &obligation,
- *trait_predicate,
- body_def_id,
- err,
- );
- }
-
- self.suggest_convert_to_slice(
- err,
- obligation,
- trait_ref,
- impl_candidates.as_slice(),
- span,
- );
- }
- }
-
- fn add_help_message_for_fn_trait(
- &self,
- trait_ref: ty::PolyTraitRef<'tcx>,
- err: &mut 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().args.type_at(1);
- if let ty::Tuple(given) = given_ty.kind()
- && let ty::Tuple(expected) = expected_ty.kind()
- {
- if expected.len() != given.len() {
- // Note number of types that were expected and given
- err.note(
- format!(
- "expected a closure taking {} argument{}, but one taking {} argument{} was given",
- given.len(),
- pluralize!(given.len()),
- expected.len(),
- pluralize!(expected.len()),
- )
- );
- } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
- // Print type mismatch
- let (expected_args, given_args) =
- self.cmp(given_ty, expected_ty);
- err.note_expected_found(
- &"a closure with arguments",
- expected_args,
- &"a closure with arguments",
- given_args,
- );
- }
- }
- }
-
- fn maybe_add_note_for_unsatisfied_const(
- &self,
- _obligation: &PredicateObligation<'tcx>,
- _trait_ref: ty::PolyTraitRef<'tcx>,
- _trait_predicate: &ty::PolyTraitPredicate<'tcx>,
- _err: &mut Diagnostic,
- _span: Span,
- ) -> UnsatisfiedConst {
- let unsatisfied_const = UnsatisfiedConst(false);
- // FIXME(effects)
- unsatisfied_const
- }
-
- fn report_closure_error(
- &self,
- obligation: &PredicateObligation<'tcx>,
- closure_def_id: DefId,
- found_kind: ty::ClosureKind,
- kind: ty::ClosureKind,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let closure_span = self.tcx.def_span(closure_def_id);
-
- let mut err = ClosureKindMismatch {
- closure_span,
- expected: kind,
- found: found_kind,
- cause_span: obligation.cause.span,
- fn_once_label: None,
- fn_mut_label: None,
- };
-
- // Additional context information explaining why the closure only implements
- // a particular trait.
- if let Some(typeck_results) = &self.typeck_results {
- let hir_id = self.tcx.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.fn_once_label = Some(ClosureFnOnceLabel {
- span: *span,
- place: ty::place_to_string_for_capture(self.tcx, &place),
- })
- }
- (ty::ClosureKind::FnMut, Some((span, place))) => {
- err.fn_mut_label = Some(ClosureFnMutLabel {
- span: *span,
- place: ty::place_to_string_for_capture(self.tcx, &place),
- })
- }
- _ => {}
- }
- }
-
- self.tcx.sess.create_err(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_opaque_type_auto_trait_leakage(
- &self,
- obligation: &PredicateObligation<'tcx>,
- def_id: DefId,
- ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
- hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
- "opaque type".to_string()
- }
- hir::OpaqueTyOrigin::TyAlias { .. } => {
- format!("`{}`", self.tcx.def_path_debug_str(def_id))
- }
- };
- let mut err = self.tcx.sess.struct_span_err(
- obligation.cause.span,
- format!("cannot check whether the hidden type of {name} satisfies auto traits"),
- );
- err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");
- match self.defining_use_anchor {
- DefiningAnchor::Bubble | DefiningAnchor::Error => {}
- DefiningAnchor::Bind(bind) => {
- err.span_note(
- self.tcx.def_ident_span(bind).unwrap_or_else(|| self.tcx.def_span(bind)),
- "this item depends on auto traits of the hidden type, \
- but may also be registering the hidden type. \
- This is not supported right now. \
- You can try moving the opaque type and the item that actually registers a hidden type into a new submodule".to_string(),
- );
- }
- };
- err
- }
-
- 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().args.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().args.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::Clause(ty::ClauseKind::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,
@@ -3552,7 +173,7 @@ pub fn dump_proof_tree<'tcx>(o: &Obligation<'tcx, ty::Predicate<'tcx>>, infcx: &
infcx.probe(|_| {
let goal = Goal { predicate: o.predicate, param_env: o.param_env };
let tree = infcx
- .evaluate_root_goal(goal, GenerateProofTree::Yes(UseGlobalCache::No))
+ .evaluate_root_goal(goal, GenerateProofTree::Yes)
.1
.expect("proof tree should have been generated");
let mut lock = std::io::stdout().lock();
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 d645dc033..5fbfedd3e 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
@@ -1,6 +1,9 @@
use super::{ObligationCauseCode, PredicateObligation};
use crate::infer::error_reporting::TypeErrCtxt;
-use rustc_ast::{MetaItem, NestedMetaItem};
+use rustc_ast::AttrArgs;
+use rustc_ast::AttrArgsEq;
+use rustc_ast::AttrKind;
+use rustc_ast::{Attribute, MetaItem, NestedMetaItem};
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, ErrorGuaranteed};
@@ -18,7 +21,7 @@ use crate::errors::{
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
};
-use super::InferCtxtPrivExt;
+use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
pub trait TypeErrCtxtExt<'tcx> {
/*private*/
@@ -50,6 +53,7 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
sym::float,
sym::_Self,
sym::crate_local,
+ sym::Trait,
];
impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
@@ -102,7 +106,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let node = hir.find(hir_id)?;
match &node {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
- self.describe_generator(*body_id).or_else(|| {
+ self.describe_coroutine(*body_id).or_else(|| {
Some(match sig.header {
hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => {
"an async function"
@@ -114,11 +118,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)),
..
- }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")),
+ }) => self.describe_coroutine(*body_id).or_else(|| Some("a trait method")),
hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(sig, body_id),
..
- }) => self.describe_generator(*body_id).or_else(|| {
+ }) => self.describe_coroutine(*body_id).or_else(|| {
Some(match sig.header {
hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => "an async method",
_ => "a method",
@@ -127,7 +131,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }),
..
- }) => self.describe_generator(*body).or_else(|| {
+ }) => self.describe_coroutine(*body).or_else(|| {
Some(if movability.is_some() { "an async closure" } else { "a closure" })
}),
hir::Node::Expr(hir::Expr { .. }) => {
@@ -180,8 +184,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
flags.push((sym::cause, Some("MainFunctionType".to_string())));
}
- // Add all types without trimmed paths.
- ty::print::with_no_trimmed_paths!({
+ if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id)
+ && let ty::Tuple(args) = trait_ref.args.type_at(1).kind()
+ {
+ let args = args
+ .iter()
+ .map(|ty| ty.to_string())
+ .collect::<Vec<_>>()
+ .join(", ");
+ flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str()))));
+ } else {
+ flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string())));
+ }
+
+ // Add all types without trimmed paths or visible paths, ensuring they end up with
+ // their "canonical" def path.
+ ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_ref.self_ty();
// This is also included through the generics list as `Self`,
@@ -296,7 +314,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
}
- });
+ }));
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
command.evaluate(self.tcx, trait_ref, &flags)
@@ -315,7 +333,7 @@ pub struct OnUnimplementedDirective {
pub subcommands: Vec<OnUnimplementedDirective>,
pub message: Option<OnUnimplementedFormatString>,
pub label: Option<OnUnimplementedFormatString>,
- pub note: Option<OnUnimplementedFormatString>,
+ pub notes: Vec<OnUnimplementedFormatString>,
pub parent_label: Option<OnUnimplementedFormatString>,
pub append_const_msg: Option<AppendConstMessage>,
}
@@ -325,7 +343,7 @@ pub struct OnUnimplementedDirective {
pub struct OnUnimplementedNote {
pub message: Option<String>,
pub label: Option<String>,
- pub note: Option<String>,
+ pub notes: Vec<String>,
pub parent_label: Option<String>,
// If none, should fall back to a generic message
pub append_const_msg: Option<AppendConstMessage>,
@@ -341,7 +359,22 @@ pub enum AppendConstMessage {
#[derive(LintDiagnostic)]
#[diag(trait_selection_malformed_on_unimplemented_attr)]
-pub struct NoValueInOnUnimplementedLint;
+#[help]
+pub struct MalformedOnUnimplementedAttrLint {
+ #[label]
+ pub span: Span,
+}
+
+impl MalformedOnUnimplementedAttrLint {
+ fn new(span: Span) -> Self {
+ Self { span }
+ }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
+#[help]
+pub struct MissingOptionsForOnUnimplementedAttr;
impl<'tcx> OnUnimplementedDirective {
fn parse(
@@ -368,7 +401,9 @@ impl<'tcx> OnUnimplementedDirective {
.meta_item()
.ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
- if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
+ if let Some(value) = cfg.value
+ && let Err(guar) = parse_value(value)
+ {
errored = Some(guar);
}
true
@@ -378,7 +413,7 @@ impl<'tcx> OnUnimplementedDirective {
let mut message = None;
let mut label = None;
- let mut note = None;
+ let mut notes = Vec::new();
let mut parent_label = None;
let mut subcommands = vec![];
let mut append_const_msg = None;
@@ -394,10 +429,12 @@ impl<'tcx> OnUnimplementedDirective {
label = parse_value(label_)?;
continue;
}
- } else if item.has_name(sym::note) && note.is_none() {
+ } else if item.has_name(sym::note) {
if let Some(note_) = item.value_str() {
- note = parse_value(note_)?;
- continue;
+ if let Some(note) = parse_value(note_)? {
+ notes.push(note);
+ continue;
+ }
}
} else if item.has_name(sym::parent_label)
&& parent_label.is_none()
@@ -411,7 +448,7 @@ impl<'tcx> OnUnimplementedDirective {
&& is_root
&& message.is_none()
&& label.is_none()
- && note.is_none()
+ && notes.is_empty()
&& !is_diagnostic_namespace_variant
// FIXME(diagnostic_namespace): disallow filters for now
{
@@ -450,7 +487,7 @@ impl<'tcx> OnUnimplementedDirective {
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
vec![item.span()],
- NoValueInOnUnimplementedLint,
+ MalformedOnUnimplementedAttrLint::new(item.span()),
);
} else {
// nothing found
@@ -466,7 +503,7 @@ impl<'tcx> OnUnimplementedDirective {
subcommands,
message,
label,
- note,
+ notes,
parent_label,
append_const_msg,
}))
@@ -474,18 +511,42 @@ impl<'tcx> OnUnimplementedDirective {
}
pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
- let mut is_diagnostic_namespace_variant = false;
- let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented).or_else(|| {
- if tcx.features().diagnostic_namespace {
- is_diagnostic_namespace_variant = true;
- tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]).next()
- } else {
- None
- }
- }) else {
- return Ok(None);
- };
+ if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) {
+ return Self::parse_attribute(attr, false, tcx, item_def_id);
+ } else if tcx.features().diagnostic_namespace {
+ tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented])
+ .filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose())
+ .try_fold(None, |aggr: Option<Self>, directive| {
+ let directive = directive?;
+ if let Some(aggr) = aggr {
+ let mut subcommands = aggr.subcommands;
+ subcommands.extend(directive.subcommands);
+ let mut notes = aggr.notes;
+ notes.extend(directive.notes);
+ Ok(Some(Self {
+ condition: aggr.condition.or(directive.condition),
+ subcommands,
+ message: aggr.message.or(directive.message),
+ label: aggr.label.or(directive.label),
+ notes,
+ parent_label: aggr.parent_label.or(directive.parent_label),
+ append_const_msg: aggr.append_const_msg.or(directive.append_const_msg),
+ }))
+ } else {
+ Ok(Some(directive))
+ }
+ })
+ } else {
+ Ok(None)
+ }
+ }
+ fn parse_attribute(
+ attr: &Attribute,
+ is_diagnostic_namespace_variant: bool,
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ ) -> Result<Option<Self>, ErrorGuaranteed> {
let result = if let Some(items) = attr.meta_item_list() {
Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant)
} else if let Some(value) = attr.value_str() {
@@ -500,26 +561,45 @@ impl<'tcx> OnUnimplementedDirective {
value,
attr.span,
)?),
- note: None,
+ notes: Vec::new(),
parent_label: None,
append_const_msg: None,
}))
} else {
+ let item = attr.get_normal_item();
+ let report_span = match &item.args {
+ AttrArgs::Empty => item.path.span,
+ AttrArgs::Delimited(args) => args.dspan.entire(),
+ AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => eq_span.to(expr.span),
+ AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span),
+ };
+
tcx.emit_spanned_lint(
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
- attr.span,
- NoValueInOnUnimplementedLint,
+ report_span,
+ MalformedOnUnimplementedAttrLint::new(report_span),
);
Ok(None)
}
} else if is_diagnostic_namespace_variant {
- tcx.emit_spanned_lint(
- UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
- attr.span,
- NoValueInOnUnimplementedLint,
- );
+ match &attr.kind {
+ AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => {
+ tcx.emit_spanned_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+ attr.span,
+ MalformedOnUnimplementedAttrLint::new(attr.span),
+ );
+ }
+ _ => tcx.emit_spanned_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()),
+ attr.span,
+ MissingOptionsForOnUnimplementedAttr,
+ ),
+ };
+
Ok(None)
} else {
let reported =
@@ -538,7 +618,7 @@ impl<'tcx> OnUnimplementedDirective {
) -> OnUnimplementedNote {
let mut message = None;
let mut label = None;
- let mut note = None;
+ let mut notes = Vec::new();
let mut parent_label = None;
let mut append_const_msg = None;
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
@@ -547,18 +627,22 @@ impl<'tcx> OnUnimplementedDirective {
options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect();
for command in self.subcommands.iter().chain(Some(self)).rev() {
- if let Some(ref condition) = command.condition && !attr::eval_condition(
- condition,
- &tcx.sess.parse_sess,
- Some(tcx.features()),
- &mut |cfg| {
- let value = cfg.value.map(|v| {
- OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
- });
-
- options.contains(&(cfg.name, value))
- },
- ) {
+ if let Some(ref condition) = command.condition
+ && !attr::eval_condition(
+ condition,
+ &tcx.sess.parse_sess,
+ Some(tcx.features()),
+ &mut |cfg| {
+ let value = cfg.value.map(|v| {
+ // `with_no_visible_paths` is also used when generating the options,
+ // so we need to match it here.
+ ty::print::with_no_visible_paths!(OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map))
+ });
+
+ options.contains(&(cfg.name, value))
+ },
+ )
+ {
debug!("evaluate: skipping {:?} due to condition", command);
continue;
}
@@ -571,9 +655,7 @@ impl<'tcx> OnUnimplementedDirective {
label = Some(label_.clone());
}
- if let Some(ref note_) = command.note {
- note = Some(note_.clone());
- }
+ notes.extend(command.notes.clone());
if let Some(ref parent_label_) = command.parent_label {
parent_label = Some(parent_label_.clone());
@@ -585,7 +667,7 @@ impl<'tcx> OnUnimplementedDirective {
OnUnimplementedNote {
label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
- note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
+ notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, &options_map)).collect(),
parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
append_const_msg,
}
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 15f2ba809..6b09bc898 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -22,12 +22,13 @@ use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::is_range_literal;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_hir::{CoroutineKind, CoroutineSource, 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::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime};
use rustc_middle::hir::map;
+use rustc_middle::traits::IsConstable;
use rustc_middle::ty::error::TypeError::{self, Sorts};
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs,
@@ -41,43 +42,43 @@ use rustc_target::spec::abi;
use std::borrow::Cow;
use std::iter;
-use super::InferCtxtPrivExt;
use crate::infer::InferCtxtExt as _;
+use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
#[derive(Debug)]
-pub enum GeneratorInteriorOrUpvar {
+pub enum CoroutineInteriorOrUpvar {
// span of interior type
Interior(Span, Option<(Span, Option<Span>)>),
// span of upvar
Upvar(Span),
}
-// This type provides a uniform interface to retrieve data on generators, whether it originated from
+// This type provides a uniform interface to retrieve data on coroutines, whether it originated from
// the local crate being compiled or from a foreign crate.
#[derive(Debug)]
-struct GeneratorData<'tcx, 'a>(&'a TypeckResults<'tcx>);
+struct CoroutineData<'tcx, 'a>(&'a TypeckResults<'tcx>);
-impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
- /// Try to get information about variables captured by the generator that matches a type we are
+impl<'tcx, 'a> CoroutineData<'tcx, 'a> {
+ /// Try to get information about variables captured by the coroutine that matches a type we are
/// looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
/// meet an obligation
fn try_get_upvar_span<F>(
&self,
infer_context: &InferCtxt<'tcx>,
- generator_did: DefId,
+ coroutine_did: DefId,
ty_matches: F,
- ) -> Option<GeneratorInteriorOrUpvar>
+ ) -> Option<CoroutineInteriorOrUpvar>
where
F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
{
- infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
+ infer_context.tcx.upvars_mentioned(coroutine_did).and_then(|upvars| {
upvars.iter().find_map(|(upvar_id, upvar)| {
let upvar_ty = self.0.node_type(*upvar_id);
let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
ty_matches(ty::Binder::dummy(upvar_ty))
- .then(|| GeneratorInteriorOrUpvar::Upvar(upvar.span))
+ .then(|| CoroutineInteriorOrUpvar::Upvar(upvar.span))
})
})
}
@@ -244,9 +245,9 @@ pub trait TypeErrCtxtExt<'tcx> {
fn note_obligation_cause_for_async_await(
&self,
err: &mut Diagnostic,
- interior_or_upvar_span: GeneratorInteriorOrUpvar,
+ interior_or_upvar_span: CoroutineInteriorOrUpvar,
is_async: bool,
- outer_generator: Option<DefId>,
+ outer_coroutine: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
obligation: &PredicateObligation<'tcx>,
@@ -313,6 +314,18 @@ pub trait TypeErrCtxtExt<'tcx> {
predicate: ty::Predicate<'tcx>,
call_hir_id: HirId,
);
+
+ fn look_for_iterator_item_mistakes(
+ &self,
+ assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>],
+ typeck_results: &TypeckResults<'tcx>,
+ type_diffs: &[TypeError<'tcx>],
+ param_env: ty::ParamEnv<'tcx>,
+ path_segment: &hir::PathSegment<'_>,
+ args: &[hir::Expr<'_>],
+ err: &mut Diagnostic,
+ );
+
fn point_at_chain(
&self,
expr: &hir::Expr<'_>,
@@ -321,6 +334,7 @@ pub trait TypeErrCtxtExt<'tcx> {
param_env: ty::ParamEnv<'tcx>,
err: &mut Diagnostic,
);
+
fn probe_assoc_types_at_expr(
&self,
type_diffs: &[TypeError<'tcx>],
@@ -364,7 +378,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -
/// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but
/// it can also be an `impl Trait` param that needs to be decomposed to a type
/// param for cleaner code.
-fn suggest_restriction<'tcx>(
+pub fn suggest_restriction<'tcx>(
tcx: TyCtxt<'tcx>,
item_id: LocalDefId,
hir_generics: &hir::Generics<'tcx>,
@@ -884,7 +898,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return false;
}
- if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder()
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
+ obligation.predicate.kind().skip_binder()
&& Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait()
{
// Don't suggest calling to turn an unsized type into a sized type
@@ -1156,15 +1171,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be args[1]
&& let ty::Tuple(args) = proj.projection_ty.args.type_at(1).kind()
- {
- Some((
- DefIdOrName::DefId(def_id),
- pred.kind().rebind(proj.term.ty().unwrap()),
- pred.kind().rebind(args.as_slice()),
- ))
- } else {
- None
- }
+ {
+ Some((
+ DefIdOrName::DefId(def_id),
+ pred.kind().rebind(proj.term.ty().unwrap()),
+ pred.kind().rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
},
)
}
@@ -1174,43 +1189,43 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& Some(proj.def_id) == self.tcx.lang_items().fn_once_output()
// for existential projection, args are shifted over by 1
&& let ty::Tuple(args) = proj.args.type_at(0).kind()
- {
- Some((
- DefIdOrName::Name("trait object"),
- pred.rebind(proj.term.ty().unwrap()),
- pred.rebind(args.as_slice()),
- ))
- } else {
- None
- }
+ {
+ Some((
+ DefIdOrName::Name("trait object"),
+ pred.rebind(proj.term.ty().unwrap()),
+ pred.rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
})
}
ty::Param(param) => {
let generics = self.tcx.generics_of(body_id);
let name = if generics.count() > param.index as usize
- && let def = generics.param_at(param.index as usize, self.tcx)
- && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
- && def.name == param.name
- {
- DefIdOrName::DefId(def.def_id)
- } else {
- DefIdOrName::Name("type parameter")
- };
+ && let def = generics.param_at(param.index as usize, self.tcx)
+ && matches!(def.kind, ty::GenericParamDefKind::Type { .. })
+ && def.name == param.name
+ {
+ DefIdOrName::DefId(def.def_id)
+ } else {
+ DefIdOrName::Name("type parameter")
+ };
param_env.caller_bounds().iter().find_map(|pred| {
if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
&& Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
&& proj.projection_ty.self_ty() == found
// args tuple will always be args[1]
&& let ty::Tuple(args) = proj.projection_ty.args.type_at(1).kind()
- {
- Some((
- name,
- pred.kind().rebind(proj.term.ty().unwrap()),
- pred.kind().rebind(args.as_slice()),
- ))
- } else {
- None
- }
+ {
+ Some((
+ name,
+ pred.kind().rebind(proj.term.ty().unwrap()),
+ pred.kind().rebind(args.as_slice()),
+ ))
+ } else {
+ None
+ }
})
}
_ => None,
@@ -1316,7 +1331,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) =
- if let ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code()
+ if let ObligationCauseCode::ItemObligation(_)
+ | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code()
&& let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
{
(
@@ -1618,7 +1634,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {
let hir = self.tcx.hir();
- if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = obligation.cause.code().peel_derives()
+ 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 `()`
@@ -1628,9 +1645,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// 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 Some(expr_span) = expr.span.find_ancestor_inside_same_ctxt(await_expr.span)
{
- let removal_span = self.tcx
+ let removal_span = self
+ .tcx
.sess
.source_map()
.span_extend_while(expr_span, char::is_whitespace)
@@ -1654,30 +1672,28 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
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, _args) = 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 {ident}` asynchronous"
+ && let ty = typeck_results.expr_ty_adjusted(base)
+ && let ty::FnDef(def_id, _args) = 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 {ident}` asynchronous");
+ 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,
- );
- }
}
+ }
}
}
}
@@ -1791,13 +1807,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"this expression has type `{}`, which implements `{}`",
ty,
trait_pred.print_modifiers_and_trait_path()
- )
+ ),
);
err.span_suggestion(
self.tcx.sess.source_map().end_point(stmt.span),
"remove this semicolon",
"",
- Applicability::MachineApplicable
+ Applicability::MachineApplicable,
);
return true;
}
@@ -1856,14 +1872,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
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);
+ 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())
+ && 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![]
@@ -1963,7 +1983,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let argument_kind = match expected.skip_binder().self_ty().kind() {
ty::Closure(..) => "closure",
- ty::Generator(..) => "generator",
+ ty::Coroutine(..) => "coroutine",
_ => "function",
};
let mut err = struct_span_err!(
@@ -2013,15 +2033,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
let expected_self =
self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.self_ty()));
- let expected_args = self
- .tcx
- .anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.args));
+ let expected_args =
+ self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.args));
// Find another predicate whose self-type is equal to the expected self type,
// but whose args don't match.
- let other_pred = predicates.into_iter()
- .enumerate()
- .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
+ let other_pred = predicates.into_iter().enumerate().find(|(other_idx, (pred, _))| {
+ match pred.kind().skip_binder() {
ty::ClauseKind::Trait(trait_pred)
if self.tcx.is_fn_trait(trait_pred.def_id())
&& other_idx != idx
@@ -2040,7 +2058,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
true
}
_ => false,
- });
+ }
+ });
// If we found one, then it's very likely the cause of the error.
if let Some((_, (_, other_pred_span))) = other_pred {
err.span_note(
@@ -2126,33 +2145,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let hir = self.tcx.hir();
// Attempt to detect an async-await error by looking at the obligation causes, looking
- // for a generator to be present.
+ // for a coroutine to be present.
//
// When a future does not implement a trait because of a captured type in one of the
- // generators somewhere in the call stack, then the result is a chain of obligations.
+ // coroutines somewhere in the call stack, then the result is a chain of obligations.
//
// Given an `async fn` A that calls an `async fn` B which captures a non-send type and that
// future is passed as an argument to a function C which requires a `Send` type, then the
// chain looks something like this:
//
- // - `BuiltinDerivedObligation` with a generator witness (B)
- // - `BuiltinDerivedObligation` with a generator (B)
+ // - `BuiltinDerivedObligation` with a coroutine witness (B)
+ // - `BuiltinDerivedObligation` with a coroutine (B)
// - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
- // - `BuiltinDerivedObligation` with a generator witness (A)
- // - `BuiltinDerivedObligation` with a generator (A)
+ // - `BuiltinDerivedObligation` with a coroutine witness (A)
+ // - `BuiltinDerivedObligation` with a coroutine (A)
// - `BuiltinDerivedObligation` with `impl std::future::Future` (A)
// - `BindingObligation` with `impl_send` (Send requirement)
//
- // The first obligation in the chain is the most useful and has the generator that captured
- // the type. The last generator (`outer_generator` below) has information about where the
- // bound was introduced. At least one generator should be present for this diagnostic to be
+ // The first obligation in the chain is the most useful and has the coroutine that captured
+ // the type. The last coroutine (`outer_coroutine` below) has information about where the
+ // bound was introduced. At least one coroutine should be present for this diagnostic to be
// modified.
let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(p)) => (Some(p), Some(p.self_ty())),
_ => (None, None),
};
- let mut generator = None;
- let mut outer_generator = None;
+ let mut coroutine = None;
+ let mut outer_coroutine = None;
let mut next_code = Some(obligation.cause.code());
let mut seen_upvar_tys_infer_tuple = false;
@@ -2172,18 +2191,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
match *ty.kind() {
- ty::Generator(did, ..) | ty::GeneratorWitness(did, _) => {
- generator = generator.or(Some(did));
- outer_generator = Some(did);
+ ty::Coroutine(did, ..) | ty::CoroutineWitness(did, _) => {
+ coroutine = coroutine.or(Some(did));
+ outer_coroutine = Some(did);
}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations
- // of a generator, the first non-generator item is now the tuple itself,
+ // of a coroutine, the first non-coroutine item is now the tuple itself,
// we shall ignore this.
seen_upvar_tys_infer_tuple = true;
}
- _ if generator.is_none() => {
+ _ if coroutine.is_none() => {
trait_ref = Some(cause.derived.parent_trait_pred.skip_binder());
target_ty = Some(ty);
}
@@ -2201,18 +2220,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
match *ty.kind() {
- ty::Generator(did, ..) | ty::GeneratorWitness(did, ..) => {
- generator = generator.or(Some(did));
- outer_generator = Some(did);
+ ty::Coroutine(did, ..) | ty::CoroutineWitness(did, ..) => {
+ coroutine = coroutine.or(Some(did));
+ outer_coroutine = Some(did);
}
ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
// By introducing a tuple of upvar types into the chain of obligations
- // of a generator, the first non-generator item is now the tuple itself,
+ // of a coroutine, the first non-coroutine item is now the tuple itself,
// we shall ignore this.
seen_upvar_tys_infer_tuple = true;
}
- _ if generator.is_none() => {
+ _ if coroutine.is_none() => {
trait_ref = Some(derived_obligation.parent_trait_pred.skip_binder());
target_ty = Some(ty);
}
@@ -2225,48 +2244,48 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- // Only continue if a generator was found.
- debug!(?generator, ?trait_ref, ?target_ty);
- let (Some(generator_did), Some(trait_ref), Some(target_ty)) =
- (generator, trait_ref, target_ty)
+ // Only continue if a coroutine was found.
+ debug!(?coroutine, ?trait_ref, ?target_ty);
+ let (Some(coroutine_did), Some(trait_ref), Some(target_ty)) =
+ (coroutine, trait_ref, target_ty)
else {
return false;
};
- let span = self.tcx.def_span(generator_did);
+ let span = self.tcx.def_span(coroutine_did);
- let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
+ let coroutine_did_root = self.tcx.typeck_root_def_id(coroutine_did);
debug!(
- ?generator_did,
- ?generator_did_root,
+ ?coroutine_did,
+ ?coroutine_did_root,
typeck_results.hir_owner = ?self.typeck_results.as_ref().map(|t| t.hir_owner),
?span,
);
- let generator_body = generator_did
+ let coroutine_body = coroutine_did
.as_local()
.and_then(|def_id| hir.maybe_body_owned_by(def_id))
.map(|body_id| hir.body(body_id));
let mut visitor = AwaitsVisitor::default();
- if let Some(body) = generator_body {
+ if let Some(body) = coroutine_body {
visitor.visit_body(body);
}
debug!(awaits = ?visitor.awaits);
- // Look for a type inside the generator interior that matches the target type to get
+ // Look for a type inside the coroutine interior that matches the target type to get
// a span.
let target_ty_erased = self.tcx.erase_regions(target_ty);
let ty_matches = |ty| -> bool {
// Careful: the regions for types that appear in the
- // generator interior are not generally known, so we
+ // coroutine interior are not generally known, so we
// want to erase them when comparing (and anyway,
// `Send` and other bounds are generally unaffected by
// the choice of region). When erasing regions, we
// also have to erase late-bound regions. This is
- // because the types that appear in the generator
+ // because the types that appear in the coroutine
// interior generally contain "bound regions" to
// represent regions that are part of the suspended
- // generator frame. Bound regions are preserved by
+ // coroutine frame. Bound regions are preserved by
// `erase_regions` and so we must also call
// `erase_late_bound_regions`.
let ty_erased = self.tcx.erase_late_bound_regions(ty);
@@ -2276,44 +2295,44 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
eq
};
- // Get the typeck results from the infcx if the generator is the function we are currently
+ // Get the typeck results from the infcx if the coroutine is the function we are currently
// type-checking; otherwise, get them by performing a query. This is needed to avoid
- // cycles. If we can't use resolved types because the generator comes from another crate,
+ // cycles. If we can't use resolved types because the coroutine comes from another crate,
// we still provide a targeted error but without all the relevant spans.
- let generator_data = match &self.typeck_results {
- Some(t) if t.hir_owner.to_def_id() == generator_did_root => GeneratorData(&t),
- _ if generator_did.is_local() => {
- GeneratorData(self.tcx.typeck(generator_did.expect_local()))
+ let coroutine_data = match &self.typeck_results {
+ Some(t) if t.hir_owner.to_def_id() == coroutine_did_root => CoroutineData(&t),
+ _ if coroutine_did.is_local() => {
+ CoroutineData(self.tcx.typeck(coroutine_did.expect_local()))
}
_ => return false,
};
- let generator_within_in_progress_typeck = match &self.typeck_results {
- Some(t) => t.hir_owner.to_def_id() == generator_did_root,
+ let coroutine_within_in_progress_typeck = match &self.typeck_results {
+ Some(t) => t.hir_owner.to_def_id() == coroutine_did_root,
_ => false,
};
let mut interior_or_upvar_span = None;
- let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
+ let from_awaited_ty = coroutine_data.get_from_await_ty(visitor, hir, ty_matches);
debug!(?from_awaited_ty);
// Avoid disclosing internal information to downstream crates.
- if generator_did.is_local()
+ if coroutine_did.is_local()
// Try to avoid cycles.
- && !generator_within_in_progress_typeck
- && let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did)
+ && !coroutine_within_in_progress_typeck
+ && let Some(coroutine_info) = self.tcx.mir_coroutine_witnesses(coroutine_did)
{
- debug!(?generator_info);
+ debug!(?coroutine_info);
'find_source: for (variant, source_info) in
- generator_info.variant_fields.iter().zip(&generator_info.variant_source_info)
+ coroutine_info.variant_fields.iter().zip(&coroutine_info.variant_source_info)
{
debug!(?variant);
for &local in variant {
- let decl = &generator_info.field_tys[local];
+ let decl = &coroutine_info.field_tys[local];
debug!(?decl);
if ty_matches(ty::Binder::dummy(decl.ty)) && !decl.ignore_for_traits {
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(
+ interior_or_upvar_span = Some(CoroutineInteriorOrUpvar::Interior(
decl.source_info.span,
Some((source_info.span, from_awaited_ty)),
));
@@ -2325,21 +2344,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if interior_or_upvar_span.is_none() {
interior_or_upvar_span =
- generator_data.try_get_upvar_span(&self, generator_did, ty_matches);
+ coroutine_data.try_get_upvar_span(&self, coroutine_did, ty_matches);
}
- if interior_or_upvar_span.is_none() && !generator_did.is_local() {
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span, None));
+ if interior_or_upvar_span.is_none() && !coroutine_did.is_local() {
+ interior_or_upvar_span = Some(CoroutineInteriorOrUpvar::Interior(span, None));
}
debug!(?interior_or_upvar_span);
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
- let is_async = self.tcx.generator_is_async(generator_did);
+ let is_async = self.tcx.coroutine_is_async(coroutine_did);
self.note_obligation_cause_for_async_await(
err,
interior_or_upvar_span,
is_async,
- outer_generator,
+ outer_coroutine,
trait_ref,
target_ty,
obligation,
@@ -2357,9 +2376,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn note_obligation_cause_for_async_await(
&self,
err: &mut Diagnostic,
- interior_or_upvar_span: GeneratorInteriorOrUpvar,
+ interior_or_upvar_span: CoroutineInteriorOrUpvar,
is_async: bool,
- outer_generator: Option<DefId>,
+ outer_coroutine: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
obligation: &PredicateObligation<'tcx>,
@@ -2369,7 +2388,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let (await_or_yield, an_await_or_yield) =
if is_async { ("await", "an await") } else { ("yield", "a yield") };
- let future_or_generator = if is_async { "future" } else { "generator" };
+ let future_or_coroutine = if is_async { "future" } else { "coroutine" };
// Special case the primary error message when send or sync is the trait that was
// not implemented.
@@ -2382,34 +2401,49 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.clear_code();
err.set_primary_message(format!(
- "{future_or_generator} cannot be {trait_verb} between threads safely"
+ "{future_or_coroutine} cannot be {trait_verb} between threads safely"
));
let original_span = err.span.primary_span().unwrap();
let mut span = MultiSpan::from_span(original_span);
- let message = outer_generator
- .and_then(|generator_did| {
- Some(match self.tcx.generator_kind(generator_did).unwrap() {
- GeneratorKind::Gen => format!("generator is not {trait_name}"),
- GeneratorKind::Async(AsyncGeneratorKind::Fn) => self
+ let message = outer_coroutine
+ .and_then(|coroutine_did| {
+ Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() {
+ CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"),
+ CoroutineKind::Async(CoroutineSource::Fn) => self
.tcx
- .parent(generator_did)
+ .parent(coroutine_did)
.as_local()
.map(|parent_did| hir.local_def_id_to_hir_id(parent_did))
.and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
.map(|name| {
format!("future returned by `{name}` is not {trait_name}")
})?,
- GeneratorKind::Async(AsyncGeneratorKind::Block) => {
+ CoroutineKind::Async(CoroutineSource::Block) => {
format!("future created by async block is not {trait_name}")
}
- GeneratorKind::Async(AsyncGeneratorKind::Closure) => {
+ CoroutineKind::Async(CoroutineSource::Closure) => {
format!("future created by async closure is not {trait_name}")
}
+ CoroutineKind::Gen(CoroutineSource::Fn) => self
+ .tcx
+ .parent(coroutine_did)
+ .as_local()
+ .map(|parent_did| hir.local_def_id_to_hir_id(parent_did))
+ .and_then(|parent_hir_id| hir.opt_name(parent_hir_id))
+ .map(|name| {
+ format!("iterator returned by `{name}` is not {trait_name}")
+ })?,
+ CoroutineKind::Gen(CoroutineSource::Block) => {
+ format!("iterator created by gen block is not {trait_name}")
+ }
+ CoroutineKind::Gen(CoroutineSource::Closure) => {
+ format!("iterator created by gen closure is not {trait_name}")
+ }
})
})
- .unwrap_or_else(|| format!("{future_or_generator} is not {trait_name}"));
+ .unwrap_or_else(|| format!("{future_or_coroutine} is not {trait_name}"));
span.push_span_label(original_span, message);
err.set_span(span);
@@ -2453,11 +2487,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
err.span_note(
span,
- format!("{future_or_generator} {trait_explanation} as this value is used across {an_await_or_yield}"),
+ format!("{future_or_coroutine} {trait_explanation} as this value is used across {an_await_or_yield}"),
);
};
match interior_or_upvar_span {
- GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => {
+ CoroutineInteriorOrUpvar::Interior(interior_span, interior_extra_info) => {
if let Some((yield_span, from_awaited_ty)) = interior_extra_info {
if let Some(await_span) = from_awaited_ty {
// The type causing this obligation is one being awaited at await_span.
@@ -2480,7 +2514,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
}
- GeneratorInteriorOrUpvar::Upvar(upvar_span) => {
+ CoroutineInteriorOrUpvar::Upvar(upvar_span) => {
// `Some((ref_ty, is_mut))` if `target_ty` is `&T` or `&mut T` and fails to impl `Send`
let non_send = match target_ty.kind() {
ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(&obligation) {
@@ -2647,9 +2681,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Check for foreign traits being reachable.
self.tcx.visible_parent_map(()).get(&def_id).is_some()
};
- if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item {
- // FIXME(estebank): extend this to search for all the types that do
- // implement this trait and list them.
+ if Some(def_id) == self.tcx.lang_items().sized_trait()
+ && let Some(hir::Node::TraitItem(hir::TraitItem {
+ ident,
+ kind: hir::TraitItemKind::Type(bounds, None),
+ ..
+ })) = tcx.hir().get_if_local(item_def_id)
+ // Do not suggest relaxing if there is an explicit `Sized` obligation.
+ && !bounds.iter()
+ .filter_map(|bound| bound.trait_ref())
+ .any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait())
+ {
+ let (span, separator) = if let [.., last] = bounds {
+ (last.span().shrink_to_hi(), " +")
+ } else {
+ (ident.span.shrink_to_hi(), ":")
+ };
+ err.span_suggestion_verbose(
+ span,
+ "consider relaxing the implicit `Sized` restriction",
+ format!("{separator} ?Sized"),
+ Applicability::MachineApplicable,
+ );
+ }
+ if let DefKind::Trait = tcx.def_kind(item_def_id)
+ && !visible_item
+ {
err.note(format!(
"`{short_item_name}` is a \"sealed trait\", because to implement \
it you also need to implement `{}`, which is not accessible; \
@@ -2657,6 +2714,34 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
types that already implement it",
with_no_trimmed_paths!(tcx.def_path_str(def_id)),
));
+ let impls_of = tcx.trait_impls_of(def_id);
+ let impls = impls_of
+ .non_blanket_impls()
+ .values()
+ .flatten()
+ .chain(impls_of.blanket_impls().iter())
+ .collect::<Vec<_>>();
+ if !impls.is_empty() {
+ let len = impls.len();
+ let mut types = impls.iter()
+ .map(|t| with_no_trimmed_paths!(format!(
+ " {}",
+ tcx.type_of(*t).instantiate_identity(),
+ )))
+ .collect::<Vec<_>>();
+ let post = if types.len() > 9 {
+ types.truncate(8);
+ format!("\nand {} others", len - 8)
+ } else {
+ String::new()
+ };
+ err.help(format!(
+ "the following type{} implement{} the trait:\n{}{post}",
+ pluralize!(len),
+ if len == 1 { "s" } else { "" },
+ types.join("\n"),
+ ));
+ }
}
}
} else {
@@ -2684,20 +2769,30 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
));
}
}
- ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
+ ObligationCauseCode::RepeatElementCopy { is_constable, elt_type, elt_span, elt_stmt_span } => {
err.note(
"the `Copy` trait is required because this value will be copied for each element of the array",
);
-
- if is_const_fn {
- err.help(
- "consider creating a new `const` item and initializing it with the result \
- of the function call to be used in the repeat position, like \
- `const VAL: Type = const_fn();` and `let x = [VAL; 42];`",
- );
+ let value_kind = match is_constable {
+ IsConstable::Fn => Some("the result of the function call"),
+ IsConstable::Ctor => Some("the result of the constructor"),
+ _ => None
+ };
+ let sm = tcx.sess.source_map();
+ if let Some(value_kind) = value_kind &&
+ let Ok(snip) = sm.span_to_snippet(elt_span)
+ {
+ let help_msg = format!(
+ "consider creating a new `const` item and initializing it with {value_kind} \
+ to be used in the repeat position");
+ let indentation = sm.indentation_before(elt_stmt_span).unwrap_or_default();
+ err.multipart_suggestion(help_msg, vec![
+ (elt_stmt_span.shrink_to_lo(), format!("const ARRAY_REPEAT_VALUE: {elt_type} = {snip};\n{indentation}")),
+ (elt_span, "ARRAY_REPEAT_VALUE".to_string())
+ ], Applicability::MachineApplicable);
}
- if self.tcx.sess.is_nightly_build() && is_const_fn {
+ if self.tcx.sess.is_nightly_build() && matches!(is_constable, IsConstable::Fn|IsConstable::Ctor) {
err.help(
"create an inline `const` block, see RFC #2920 \
<https://github.com/rust-lang/rfcs/pull/2920> for more information",
@@ -2754,7 +2849,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& let ty::ClauseKind::Trait(trait_pred) = clause
&& let ty::Dynamic(..) = trait_pred.self_ty().kind()
{
- let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+ let span = if let Ok(snippet) =
+ self.tcx.sess.source_map().span_to_snippet(span)
&& snippet.starts_with("dyn ")
{
let pos = snippet.len() - snippet[3..].trim_start().len();
@@ -2789,7 +2885,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.note("the return type of a function must have a statically known size");
}
ObligationCauseCode::SizedYieldType => {
- err.note("the yield type of a generator must have a statically known size");
+ err.note("the yield type of a coroutine must have a statically known size");
}
ObligationCauseCode::AssignmentLhsSized => {
err.note("the left-hand-side of an assignment must have a statically known size");
@@ -2845,22 +2941,28 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.note("all inline asm arguments must have a statically known size");
}
ObligationCauseCode::SizedClosureCapture(closure_def_id) => {
- err.note("all values captured by value by a closure must have a statically known size");
- let hir::ExprKind::Closure(closure) = self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind else {
+ err.note(
+ "all values captured by value by a closure must have a statically known size",
+ );
+ let hir::ExprKind::Closure(closure) =
+ self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind
+ else {
bug!("expected closure in SizedClosureCapture obligation");
};
- if let hir::CaptureBy::Value = closure.capture_clause
+ if let hir::CaptureBy::Value { .. } = closure.capture_clause
&& let Some(span) = closure.fn_arg_span
{
err.span_label(span, "this closure captures all values by move");
}
}
- ObligationCauseCode::SizedGeneratorInterior(generator_def_id) => {
- let what = match self.tcx.generator_kind(generator_def_id) {
- None | Some(hir::GeneratorKind::Gen) => "yield",
- Some(hir::GeneratorKind::Async(..)) => "await",
+ ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
+ let what = match self.tcx.coroutine_kind(coroutine_def_id) {
+ None | Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) => "yield",
+ Some(hir::CoroutineKind::Async(..)) => "await",
};
- err.note(format!("all values live across `{what}` must have a statically known size"));
+ err.note(format!(
+ "all values live across `{what}` must have a statically known size"
+ ));
}
ObligationCauseCode::ConstPatternStructural => {
err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
@@ -2878,7 +2980,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return;
}
- // If the obligation for a tuple is set directly by a Generator or Closure,
+ // If the obligation for a tuple is set directly by a Coroutine or Closure,
// then the tuple must be the one containing capture types.
let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
false
@@ -2888,7 +2990,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let parent_trait_ref =
self.resolve_vars_if_possible(data.parent_trait_pred);
let nested_ty = parent_trait_ref.skip_binder().self_ty();
- matches!(nested_ty.kind(), ty::Generator(..))
+ matches!(nested_ty.kind(), ty::Coroutine(..))
|| matches!(nested_ty.kind(), ty::Closure(..))
} else {
false
@@ -2908,7 +3010,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
},
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.
- // Avoid printing it twice (it was already printed in the `ty::Generator` arm below).
+ // Avoid printing it twice (it was already printed in the `ty::Coroutine` arm below).
let is_future = tcx.ty_is_opaque_future(ty);
debug!(
?obligated_types,
@@ -2917,8 +3019,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
if is_future
&& obligated_types.last().is_some_and(|ty| match ty.kind() {
- ty::Generator(last_def_id, ..) => {
- tcx.generator_is_async(*last_def_id)
+ ty::Coroutine(last_def_id, ..) => {
+ tcx.coroutine_is_async(*last_def_id)
}
_ => false,
})
@@ -2927,7 +3029,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
err.span_note(self.tcx.def_span(def_id), msg)
}
- ty::GeneratorWitness(def_id, args) => {
+ ty::CoroutineWitness(def_id, args) => {
use std::fmt::Write;
// FIXME: this is kind of an unusual format for rustc, can we make it more clear?
@@ -2935,21 +3037,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// FIXME: only print types which don't meet the trait requirement
let mut msg =
"required because it captures the following types: ".to_owned();
- for bty in tcx.generator_hidden_types(*def_id) {
+ for bty in tcx.coroutine_hidden_types(*def_id) {
let ty = bty.instantiate(tcx, args);
write!(msg, "`{ty}`, ").unwrap();
}
err.note(msg.trim_end_matches(", ").to_string())
}
- ty::Generator(def_id, _, _) => {
+ ty::Coroutine(def_id, _, _) => {
let sp = self.tcx.def_span(def_id);
- // Special-case this to say "async block" instead of `[static generator]`.
- let kind = tcx.generator_kind(def_id).unwrap().descr();
+ // Special-case this to say "async block" instead of `[static coroutine]`.
+ let kind = tcx.coroutine_kind(def_id).unwrap();
err.span_note(
sp,
with_forced_trimmed_paths!(format!(
- "required because it's used within this {kind}",
+ "required because it's used within this {kind:#}",
)),
)
}
@@ -3244,7 +3346,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) {
if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) {
let body = self.tcx.hir().body(body_id);
- if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
+ if let Some(hir::CoroutineKind::Async(_)) = body.coroutine_kind {
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
@@ -3385,15 +3487,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
trait_pred: ty::PolyTraitPredicate<'tcx>,
) {
if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code()
- && self.tcx.is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id)
+ && self
+ .tcx
+ .is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id)
&& let ty::Slice(_) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
&& let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind()
&& let ty::Uint(ty::UintTy::Usize) = inner_ty.kind()
{
err.span_suggestion_verbose(
obligation.cause.span.shrink_to_lo(),
- "dereference this index",
- '*',
+ "dereference this index",
+ '*',
Applicability::MachineApplicable,
);
}
@@ -3413,10 +3517,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let Some(Node::Expr(expr)) = hir.find(arg_hir_id)
&& let Some(typeck_results) = &self.typeck_results
{
- if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr {
- let expr = expr.peel_blocks();
- let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx,));
- let span = expr.span;
+ if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr {
+ let inner_expr = expr.peel_blocks();
+ let ty = typeck_results.expr_ty_adjusted_opt(inner_expr)
+ .unwrap_or(Ty::new_misc_error(tcx));
+ let span = inner_expr.span;
if Some(span) != err.span.primary_span() {
err.span_label(
span,
@@ -3427,6 +3532,49 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
format!("this tail expression is of type `{ty}`")
},
);
+ if let ty::PredicateKind::Clause(clause) = failed_pred.kind().skip_binder()
+ && let ty::ClauseKind::Trait(pred) = clause
+ && [
+ tcx.lang_items().fn_once_trait(),
+ tcx.lang_items().fn_mut_trait(),
+ tcx.lang_items().fn_trait(),
+ ].contains(&Some(pred.def_id()))
+ {
+ if let [stmt, ..] = block.stmts
+ && let hir::StmtKind::Semi(value) = stmt.kind
+ && let hir::ExprKind::Closure(hir::Closure {
+ body,
+ fn_decl_span,
+ ..
+ }) = value.kind
+ && let body = hir.body(*body)
+ && !matches!(body.value.kind, hir::ExprKind::Block(..))
+ {
+ // Check if the failed predicate was an expectation of a closure type
+ // and if there might have been a `{ |args|` typo instead of `|args| {`.
+ err.multipart_suggestion(
+ "you might have meant to open the closure body instead of placing \
+ a closure within a block",
+ vec![
+ (expr.span.with_hi(value.span.lo()), String::new()),
+ (fn_decl_span.shrink_to_hi(), " {".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ // Maybe the bare block was meant to be a closure.
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "you might have meant to create the closure instead of a block",
+ format!(
+ "|{}| ",
+ (0..pred.trait_ref.args.len() - 1).map(|_| "_")
+ .collect::<Vec<_>>()
+ .join(", ")),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
}
}
@@ -3437,7 +3585,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut type_diffs = vec![];
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code
&& let Some(node_args) = typeck_results.node_args_opt(call_hir_id)
- && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args)
+ && let where_clauses =
+ self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args)
&& let Some(where_pred) = where_clauses.predicates.get(*idx)
{
if let Some(where_pred) = where_pred.as_trait_clause()
@@ -3447,32 +3596,34 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let failed_pred = self.instantiate_binder_with_fresh_vars(
expr.span,
LateBoundRegionConversionTime::FnCall,
- failed_pred
+ failed_pred,
);
- let zipped =
- iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args);
+ let zipped = iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args);
for (expected, actual) in zipped {
self.probe(|_| {
- match self
- .at(&ObligationCause::misc(expr.span, body_id), param_env)
- .eq(DefineOpaqueTypes::No, expected, actual)
- {
+ 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),
}
})
- };
+ }
} else if let Some(where_pred) = where_pred.as_projection_clause()
&& let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
&& let Some(found) = failed_pred.skip_binder().term.ty()
{
- type_diffs = vec![
- Sorts(ty::error::ExpectedFound {
- expected: Ty::new_alias(self.tcx,ty::Projection, where_pred.skip_binder().projection_ty),
- found,
- }),
- ];
+ type_diffs = vec![Sorts(ty::error::ExpectedFound {
+ expected: Ty::new_alias(
+ self.tcx,
+ ty::Projection,
+ where_pred.skip_binder().projection_ty,
+ ),
+ found,
+ })];
}
}
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
@@ -3586,12 +3737,115 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
msg,
sugg,
Applicability::MaybeIncorrect,
- SuggestionStyle::ShowAlways
+ SuggestionStyle::ShowAlways,
);
}
}
}
+ fn look_for_iterator_item_mistakes(
+ &self,
+ assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>],
+ typeck_results: &TypeckResults<'tcx>,
+ type_diffs: &[TypeError<'tcx>],
+ param_env: ty::ParamEnv<'tcx>,
+ path_segment: &hir::PathSegment<'_>,
+ args: &[hir::Expr<'_>],
+ err: &mut Diagnostic,
+ ) {
+ let tcx = self.tcx;
+ // Special case for iterator chains, we look at potential failures of `Iterator::Item`
+ // not being `: Clone` and `Iterator::map` calls with spurious trailing `;`.
+ for entry in assocs_in_this_method {
+ let Some((_span, (def_id, ty))) = entry else {
+ continue;
+ };
+ for diff in type_diffs {
+ let Sorts(expected_found) = diff else {
+ continue;
+ };
+ if tcx.is_diagnostic_item(sym::IteratorItem, *def_id)
+ && path_segment.ident.name == sym::map
+ && self.can_eq(param_env, expected_found.found, *ty)
+ && let [arg] = args
+ && let hir::ExprKind::Closure(closure) = arg.kind
+ {
+ let body = tcx.hir().body(closure.body);
+ if let hir::ExprKind::Block(block, None) = body.value.kind
+ && let None = block.expr
+ && let [.., stmt] = block.stmts
+ && let hir::StmtKind::Semi(expr) = stmt.kind
+ // FIXME: actually check the expected vs found types, but right now
+ // the expected is a projection that we need to resolve.
+ // && let Some(tail_ty) = typeck_results.expr_ty_opt(expr)
+ && expected_found.found.is_unit()
+ {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi().with_hi(stmt.span.hi()),
+ "consider removing this semicolon",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ }
+ let expr = if let hir::ExprKind::Block(block, None) = body.value.kind
+ && let Some(expr) = block.expr
+ {
+ expr
+ } else {
+ body.value
+ };
+ if let hir::ExprKind::MethodCall(path_segment, rcvr, [], span) = expr.kind
+ && path_segment.ident.name == sym::clone
+ && let Some(expr_ty) = typeck_results.expr_ty_opt(expr)
+ && let Some(rcvr_ty) = typeck_results.expr_ty_opt(rcvr)
+ && self.can_eq(param_env, expr_ty, rcvr_ty)
+ && let ty::Ref(_, ty, _) = expr_ty.kind()
+ {
+ err.span_label(
+ span,
+ format!(
+ "this method call is cloning the reference `{expr_ty}`, not \
+ `{ty}` which doesn't implement `Clone`",
+ ),
+ );
+ let ty::Param(..) = ty.kind() else {
+ continue;
+ };
+ let hir = tcx.hir();
+ let node = hir.get_by_def_id(hir.get_parent_item(expr.hir_id).def_id);
+
+ let pred = ty::Binder::dummy(ty::TraitPredicate {
+ trait_ref: ty::TraitRef::from_lang_item(
+ tcx,
+ LangItem::Clone,
+ span,
+ [*ty],
+ ),
+ polarity: ty::ImplPolarity::Positive,
+ });
+ let Some(generics) = node.generics() else {
+ continue;
+ };
+ let Some(body_id) = node.body_id() else {
+ continue;
+ };
+ suggest_restriction(
+ tcx,
+ hir.body_owner_def_id(body_id),
+ &generics,
+ &format!("type parameter `{ty}`"),
+ err,
+ node.fn_sig(),
+ None,
+ pred,
+ None,
+ );
+ }
+ }
+ }
+ }
+ }
+
fn point_at_chain(
&self,
expr: &hir::Expr<'_>,
@@ -3611,13 +3865,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut prev_ty = self.resolve_vars_if_possible(
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
);
- while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind {
+ while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {
// Point at every method call in the chain with the resulting type.
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
// ^^^^^^ ^^^^^^^^^^^
expr = rcvr_expr;
let assocs_in_this_method =
self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
+ self.look_for_iterator_item_mistakes(
+ &assocs_in_this_method,
+ typeck_results,
+ &type_diffs,
+ param_env,
+ path_segment,
+ args,
+ err,
+ );
assocs.push(assocs_in_this_method);
prev_ty = self.resolve_vars_if_possible(
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
@@ -3638,9 +3901,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let hir::Node::Param(param) = parent {
// ...and it is a an fn argument.
let prev_ty = self.resolve_vars_if_possible(
- typeck_results.node_type_opt(param.hir_id).unwrap_or(Ty::new_misc_error(tcx,)),
+ typeck_results
+ .node_type_opt(param.hir_id)
+ .unwrap_or(Ty::new_misc_error(tcx)),
+ );
+ let assocs_in_this_method = self.probe_assoc_types_at_expr(
+ &type_diffs,
+ param.ty_span,
+ prev_ty,
+ param.hir_id,
+ param_env,
);
- let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env);
if assocs_in_this_method.iter().any(|a| a.is_some()) {
assocs.push(assocs_in_this_method);
print_root_expr = false;
@@ -3651,7 +3922,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
// We want the type before deref coercions, otherwise we talk about `&[_]`
// instead of `Vec<_>`.
- if let Some(ty) = typeck_results.expr_ty_opt(expr) && print_root_expr {
+ if let Some(ty) = typeck_results.expr_ty_opt(expr)
+ && print_root_expr
+ {
let ty = with_forced_trimmed_paths!(self.ty_to_string(ty));
// Point at the root expression
// vec![1, 2, 3].iter().map(mapper).sum<i32>()
@@ -3782,7 +4055,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// This corresponds to `<ExprTy as Iterator>::Item = _`.
let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
ty::ClauseKind::Projection(ty::ProjectionPredicate {
- projection_ty: self.tcx.mk_alias_ty(proj.def_id, args),
+ projection_ty: ty::AliasTy::new(self.tcx, proj.def_id, args),
term: ty_var.into(),
}),
));
@@ -4000,14 +4273,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// ... whose signature is `async` (i.e. this is an AFIT)
let (sig, body) = item.expect_fn();
- let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
- return;
- };
- let Ok(async_span) =
- self.tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace())
- else {
- return;
- };
let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
sig.decl.output
else {
@@ -4021,55 +4286,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return;
}
- let future = self.tcx.hir().item(*def).expect_opaque_ty();
- let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else {
- // `async fn` should always lower to a lang item bound... but don't ICE.
- return;
- };
- let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) =
- generics.bindings.get(0).map(|binding| binding.kind)
- else {
- // Also should never happen.
+ let Some(sugg) = suggest_desugaring_async_fn_to_impl_future_in_trait(
+ self.tcx,
+ *sig,
+ *body,
+ opaque_def_id.expect_local(),
+ &format!(" + {auto_trait}"),
+ ) else {
return;
};
let function_name = self.tcx.def_path_str(fn_def_id);
-
- let mut sugg = if future_output_ty.span.is_empty() {
- vec![
- (async_span, String::new()),
- (
- future_output_ty.span,
- format!(" -> impl std::future::Future<Output = ()> + {auto_trait}"),
- ),
- ]
- } else {
- vec![
- (
- future_output_ty.span.shrink_to_lo(),
- "impl std::future::Future<Output = ".to_owned(),
- ),
- (future_output_ty.span.shrink_to_hi(), format!("> + {auto_trait}")),
- (async_span, String::new()),
- ]
- };
-
- // If there's a body, we also need to wrap it in `async {}`
- if let hir::TraitFn::Provided(body) = body {
- let body = self.tcx.hir().body(*body);
- let body_span = body.value.span;
- let body_span_without_braces =
- body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
- if body_span_without_braces.is_empty() {
- sugg.push((body_span_without_braces, " async {} ".to_owned()));
- } else {
- sugg.extend([
- (body_span_without_braces.shrink_to_lo(), "async {".to_owned()),
- (body_span_without_braces.shrink_to_hi(), "} ".to_owned()),
- ]);
- }
- }
-
err.multipart_suggestion(
format!(
"`{auto_trait}` can be made part of the associated future's \
@@ -4150,7 +4377,9 @@ fn hint_missing_borrow<'tcx>(
let mut span = arg.span.shrink_to_lo();
let mut left = found_refs.len() - expected_refs.len();
let mut ty = arg;
- while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 {
+ while let hir::TyKind::Ref(_, mut_ty) = &ty.kind
+ && left > 0
+ {
span = span.with_hi(mut_ty.ty.span.lo());
ty = mut_ty.ty;
left -= 1;
@@ -4221,7 +4450,7 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
assert!(!self.in_block_tail);
- if body.generator_kind().is_none() {
+ if body.coroutine_kind().is_none() {
if let hir::ExprKind::Block(block, None) = body.value.kind {
if block.expr.is_some() {
self.in_block_tail = true;
@@ -4300,6 +4529,39 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
}
}
+pub(super) 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(),
+ ),
+ }
+ }
+}
+
// Replace `param` with `replace_ty`
struct ReplaceImplTraitFolder<'tcx> {
tcx: TyCtxt<'tcx>,
@@ -4321,3 +4583,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceImplTraitFolder<'tcx> {
self.tcx
}
}
+
+pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ sig: hir::FnSig<'tcx>,
+ body: hir::TraitFn<'tcx>,
+ opaque_def_id: LocalDefId,
+ add_bounds: &str,
+) -> Option<Vec<(Span, String)>> {
+ let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
+ return None;
+ };
+ let Ok(async_span) = tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace())
+ else {
+ return None;
+ };
+
+ let future = tcx.hir().get_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
+ let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else {
+ // `async fn` should always lower to a lang item bound... but don't ICE.
+ return None;
+ };
+ let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) =
+ generics.bindings.get(0).map(|binding| binding.kind)
+ else {
+ // Also should never happen.
+ return None;
+ };
+
+ let mut sugg = if future_output_ty.span.is_empty() {
+ vec![
+ (async_span, String::new()),
+ (
+ future_output_ty.span,
+ format!(" -> impl std::future::Future<Output = ()>{add_bounds}"),
+ ),
+ ]
+ } else {
+ vec![
+ (future_output_ty.span.shrink_to_lo(), "impl std::future::Future<Output = ".to_owned()),
+ (future_output_ty.span.shrink_to_hi(), format!(">{add_bounds}")),
+ (async_span, String::new()),
+ ]
+ };
+
+ // If there's a body, we also need to wrap it in `async {}`
+ if let hir::TraitFn::Provided(body) = body {
+ let body = tcx.hir().body(body);
+ let body_span = body.value.span;
+ let body_span_without_braces =
+ body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
+ if body_span_without_braces.is_empty() {
+ sugg.push((body_span_without_braces, " async {} ".to_owned()));
+ } else {
+ sugg.extend([
+ (body_span_without_braces.shrink_to_lo(), "async {".to_owned()),
+ (body_span_without_braces.shrink_to_hi(), "} ".to_owned()),
+ ]);
+ }
+ }
+
+ Some(sugg)
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
new file mode 100644
index 000000000..ba2e3d1ae
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -0,0 +1,3278 @@
+use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
+use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
+use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch};
+use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::{self, InferCtxt};
+use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt;
+use crate::traits::error_reporting::{ambiguity, ambiguity::Ambiguity::*};
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
+use crate::traits::NormalizeExt;
+use crate::traits::{
+ elaborate, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation,
+ ObligationCause, ObligationCauseCode, ObligationCtxt, OutputTypeParameterMismatch, Overflow,
+ PredicateObligation, SelectionError, TraitNotObjectSafe,
+};
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_errors::{
+ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ MultiSpan, StashKey, Style,
+};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{GenericParam, Item, Node};
+use rustc_infer::infer::error_reporting::TypeErrCtxt;
+use rustc_infer::infer::{InferOk, TypeTrace};
+use rustc_middle::traits::select::OverflowError;
+use rustc_middle::traits::{DefiningAnchor, SelectionOutputTypeParameterMismatch};
+use rustc_middle::ty::abstract_const::NotConstEvaluatable;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
+use rustc_middle::ty::{
+ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
+ TypeVisitable, TypeVisitableExt,
+};
+use rustc_session::config::{DumpSolverProofTree, TraitSolver};
+use rustc_session::Limit;
+use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::symbol::sym;
+use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use std::borrow::Cow;
+use std::fmt;
+use std::iter;
+
+use super::{
+ dump_proof_tree, ArgKind, CandidateSimilarity, FindExprBySpan, FindTypeParam,
+ GetSafeTransmuteErrorAndReason, HasNumericInferVisitor, ImplCandidate, UnsatisfiedConst,
+};
+
+pub use rustc_infer::traits::error_reporting::*;
+
+pub trait TypeErrCtxtExt<'tcx> {
+ fn build_overflow_error<T>(
+ &self,
+ predicate: &T,
+ span: Span,
+ suggest_increasing_limit: bool,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
+ where
+ T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>;
+
+ fn report_overflow_error<T>(
+ &self,
+ predicate: &T,
+ span: Span,
+ suggest_increasing_limit: bool,
+ mutate: impl FnOnce(&mut Diagnostic),
+ ) -> !
+ where
+ T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>;
+
+ fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed;
+
+ fn report_fulfillment_errors(&self, errors: Vec<FulfillmentError<'tcx>>) -> ErrorGuaranteed;
+
+ fn report_overflow_obligation<T>(
+ &self,
+ obligation: &Obligation<'tcx, T>,
+ suggest_increasing_limit: bool,
+ ) -> !
+ where
+ T: ToPredicate<'tcx> + Clone;
+
+ fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
+
+ fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !;
+
+ /// The `root_obligation` parameter should be the `root_obligation` field
+ /// from a `FulfillmentError`. If no `FulfillmentError` is available,
+ /// then it should be the same as `obligation`.
+ fn report_selection_error(
+ &self,
+ obligation: PredicateObligation<'tcx>,
+ root_obligation: &PredicateObligation<'tcx>,
+ error: &SelectionError<'tcx>,
+ );
+
+ fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool;
+
+ fn report_const_param_not_wf(
+ &self,
+ ty: Ty<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+}
+
+impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
+ fn report_fulfillment_errors(
+ &self,
+ mut errors: Vec<FulfillmentError<'tcx>>,
+ ) -> ErrorGuaranteed {
+ #[derive(Debug)]
+ struct ErrorDescriptor<'tcx> {
+ predicate: ty::Predicate<'tcx>,
+ index: Option<usize>, // None if this is an old error
+ }
+
+ let mut error_map: FxIndexMap<_, Vec<_>> = self
+ .reported_trait_errors
+ .borrow()
+ .iter()
+ .map(|(&span, predicates)| {
+ (
+ span,
+ predicates
+ .iter()
+ .map(|&predicate| ErrorDescriptor { predicate, index: None })
+ .collect(),
+ )
+ })
+ .collect();
+
+ // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
+ // with more relevant type information and hide redundant E0282 errors.
+ errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
+ if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() =>
+ {
+ 1
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
+ ty::PredicateKind::Coerce(_) => 2,
+ _ => 0,
+ });
+
+ for (index, error) in errors.iter().enumerate() {
+ // We want to ignore desugarings here: spans are equivalent even
+ // if one is the result of a desugaring and the other is not.
+ let mut span = error.obligation.cause.span;
+ let expn_data = span.ctxt().outer_expn_data();
+ if let ExpnKind::Desugaring(_) = expn_data.kind {
+ span = expn_data.call_site;
+ }
+
+ error_map.entry(span).or_default().push(ErrorDescriptor {
+ predicate: error.obligation.predicate,
+ index: Some(index),
+ });
+ }
+
+ // We do this in 2 passes because we want to display errors in order, though
+ // maybe it *is* better to sort errors by span or something.
+ let mut is_suppressed = vec![false; errors.len()];
+ for (_, error_set) in error_map.iter() {
+ // We want to suppress "duplicate" errors with the same span.
+ for error in error_set {
+ if let Some(index) = error.index {
+ // Suppress errors that are either:
+ // 1) strictly implied by another error.
+ // 2) implied by an error with a smaller index.
+ for error2 in error_set {
+ if error2.index.is_some_and(|index2| is_suppressed[index2]) {
+ // Avoid errors being suppressed by already-suppressed
+ // errors, to prevent all errors from being suppressed
+ // at once.
+ continue;
+ }
+
+ if self.error_implies(error2.predicate, error.predicate)
+ && !(error2.index >= error.index
+ && self.error_implies(error.predicate, error2.predicate))
+ {
+ info!("skipping {:?} (implied by {:?})", error, error2);
+ is_suppressed[index] = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for from_expansion in [false, true] {
+ for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
+ if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
+ self.report_fulfillment_error(error);
+ // We want to ignore desugarings here: spans are equivalent even
+ // if one is the result of a desugaring and the other is not.
+ let mut span = error.obligation.cause.span;
+ let expn_data = span.ctxt().outer_expn_data();
+ if let ExpnKind::Desugaring(_) = expn_data.kind {
+ span = expn_data.call_site;
+ }
+ self.reported_trait_errors
+ .borrow_mut()
+ .entry(span)
+ .or_default()
+ .push(error.obligation.predicate);
+ }
+ }
+ }
+
+ self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors")
+ }
+
+ /// Reports that an overflow has occurred and halts compilation. We
+ /// halt compilation unconditionally because it is important that
+ /// overflows never be masked -- they basically represent computations
+ /// whose result could not be truly determined and thus we can't say
+ /// if the program type checks or not -- and they are unusual
+ /// occurrences in any case.
+ fn report_overflow_error<T>(
+ &self,
+ predicate: &T,
+ span: Span,
+ suggest_increasing_limit: bool,
+ mutate: impl FnOnce(&mut Diagnostic),
+ ) -> !
+ where
+ T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
+ {
+ let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit);
+ mutate(&mut err);
+ err.emit();
+
+ self.tcx.sess.abort_if_errors();
+ bug!();
+ }
+
+ fn build_overflow_error<T>(
+ &self,
+ predicate: &T,
+ span: Span,
+ suggest_increasing_limit: bool,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>
+ where
+ T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
+ {
+ let predicate = self.resolve_vars_if_possible(predicate.clone());
+ let mut pred_str = predicate.to_string();
+
+ if pred_str.len() > 50 {
+ // We don't need to save the type to a file, we will be talking about this type already
+ // in a separate note when we explain the obligation, so it will be available that way.
+ let mut cx: FmtPrinter<'_, '_> =
+ FmtPrinter::new_with_limit(self.tcx, Namespace::TypeNS, rustc_session::Limit(6));
+ predicate.print(&mut cx).unwrap();
+ pred_str = cx.into_buffer();
+ }
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0275,
+ "overflow evaluating the requirement `{}`",
+ pred_str,
+ );
+
+ if suggest_increasing_limit {
+ self.suggest_new_overflow_limit(&mut err);
+ }
+
+ err
+ }
+
+ /// Reports that an overflow has occurred and halts compilation. We
+ /// halt compilation unconditionally because it is important that
+ /// overflows never be masked -- they basically represent computations
+ /// whose result could not be truly determined and thus we can't say
+ /// if the program type checks or not -- and they are unusual
+ /// occurrences in any case.
+ fn report_overflow_obligation<T>(
+ &self,
+ obligation: &Obligation<'tcx, T>,
+ suggest_increasing_limit: bool,
+ ) -> !
+ where
+ T: ToPredicate<'tcx> + Clone,
+ {
+ let predicate = obligation.predicate.clone().to_predicate(self.tcx);
+ let predicate = self.resolve_vars_if_possible(predicate);
+ self.report_overflow_error(
+ &predicate,
+ obligation.cause.span,
+ suggest_increasing_limit,
+ |err| {
+ self.note_obligation_cause_code(
+ obligation.cause.body_id,
+ err,
+ predicate,
+ obligation.param_env,
+ obligation.cause.code(),
+ &mut vec![],
+ &mut Default::default(),
+ );
+ },
+ );
+ }
+
+ fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) {
+ let suggested_limit = match self.tcx.recursion_limit() {
+ Limit(0) => Limit(2),
+ limit => limit * 2,
+ };
+ err.help(format!(
+ "consider increasing the recursion limit by adding a \
+ `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
+ suggested_limit,
+ self.tcx.crate_name(LOCAL_CRATE),
+ ));
+ }
+
+ /// Reports that a cycle was detected which led to overflow and halts
+ /// compilation. This is equivalent to `report_overflow_obligation` except
+ /// that we can give a more helpful error message (and, in particular,
+ /// we do not suggest increasing the overflow limit, which is not
+ /// going to help).
+ fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
+ let cycle = self.resolve_vars_if_possible(cycle.to_owned());
+ assert!(!cycle.is_empty());
+
+ debug!(?cycle, "report_overflow_error_cycle");
+
+ // The 'deepest' obligation is most likely to have a useful
+ // cause 'backtrace'
+ self.report_overflow_obligation(
+ cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
+ false,
+ );
+ }
+
+ fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
+ let obligation = self.resolve_vars_if_possible(obligation);
+ let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true);
+ self.note_obligation_cause(&mut err, &obligation);
+ self.point_at_returns_when_relevant(&mut err, &obligation);
+ err.emit()
+ }
+
+ fn report_selection_error(
+ &self,
+ mut obligation: PredicateObligation<'tcx>,
+ root_obligation: &PredicateObligation<'tcx>,
+ error: &SelectionError<'tcx>,
+ ) {
+ let tcx = self.tcx;
+
+ if tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError {
+ dump_proof_tree(root_obligation, self.infcx);
+ }
+
+ let mut span = obligation.cause.span;
+ // FIXME: statically guarantee this by tainting after the diagnostic is emitted
+ self.set_tainted_by_errors(
+ tcx.sess.delay_span_bug(span, "`report_selection_error` did not emit an error"),
+ );
+
+ let mut err = match *error {
+ SelectionError::Unimplemented => {
+ // If this obligation was generated as a result of well-formedness checking, see if we
+ // can get a better error message by performing HIR-based well-formedness checking.
+ if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
+ root_obligation.cause.code().peel_derives()
+ && !obligation.predicate.has_non_region_infer()
+ {
+ if let Some(cause) = self
+ .tcx
+ .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc))
+ {
+ obligation.cause = cause.clone();
+ span = obligation.cause.span;
+ }
+ }
+
+ if let ObligationCauseCode::CompareImplItemObligation {
+ impl_item_def_id,
+ trait_item_def_id,
+ kind: _,
+ } = *obligation.cause.code()
+ {
+ self.report_extra_impl_obligation(
+ span,
+ impl_item_def_id,
+ trait_item_def_id,
+ &format!("`{}`", obligation.predicate),
+ )
+ .emit();
+ return;
+ }
+
+ // Report a const-param specific error
+ if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()
+ {
+ self.report_const_param_not_wf(ty, &obligation).emit();
+ return;
+ }
+
+ let bound_predicate = obligation.predicate.kind();
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
+ let trait_predicate = bound_predicate.rebind(trait_predicate);
+ let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+
+ // FIXME(effects)
+ let predicate_is_const = false;
+
+ if self.tcx.sess.has_errors().is_some()
+ && trait_predicate.references_error()
+ {
+ return;
+ }
+ if self.fn_arg_obligation(&obligation) {
+ // Silence redundant errors on binding acccess that are already
+ // reported on the binding definition (#56607).
+ return;
+ }
+ let trait_ref = trait_predicate.to_poly_trait_ref();
+ let (post_message, pre_message, type_def, file_note) = self
+ .get_parent_trait_ref(obligation.cause.code())
+ .map(|(t, s)| {
+ let (t, file) = self.tcx.short_ty_string(t);
+ (
+ format!(" in `{t}`"),
+ format!("within `{t}`, "),
+ s.map(|s| (format!("within this `{t}`"), s)),
+ file.map(|file| format!(
+ "the full trait has been written to '{}'",
+ file.display(),
+ ))
+ )
+ })
+ .unwrap_or_default();
+
+ let OnUnimplementedNote {
+ message,
+ label,
+ notes,
+ parent_label,
+ append_const_msg,
+ } = self.on_unimplemented_note(trait_ref, &obligation);
+ let have_alt_message = message.is_some() || label.is_some();
+ let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
+ let is_unsize =
+ Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
+ let (message, notes, append_const_msg) = if is_try_conversion {
+ (
+ Some(format!(
+ "`?` couldn't convert the error to `{}`",
+ trait_ref.skip_binder().self_ty(),
+ )),
+ vec![
+ "the question mark operation (`?`) implicitly performs a \
+ conversion on the error value using the `From` trait"
+ .to_owned(),
+ ],
+ Some(AppendConstMessage::Default),
+ )
+ } else {
+ (message, notes, append_const_msg)
+ };
+
+ let err_msg = self.get_standard_error_message(
+ &trait_predicate,
+ message,
+ predicate_is_const,
+ append_const_msg,
+ post_message,
+ );
+
+ let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id())
+ == self.tcx.lang_items().transmute_trait()
+ {
+ // Recompute the safe transmute reason and use that for the error reporting
+ match self.get_safe_transmute_error_and_reason(
+ obligation.clone(),
+ trait_ref,
+ span,
+ ) {
+ GetSafeTransmuteErrorAndReason::Silent => return,
+ GetSafeTransmuteErrorAndReason::Error {
+ err_msg,
+ safe_transmute_explanation,
+ } => (err_msg, Some(safe_transmute_explanation)),
+ }
+ } else {
+ (err_msg, None)
+ };
+
+ let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg);
+
+ if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
+ err.span_label(
+ ret_span,
+ format!(
+ "expected `{}` because of this",
+ trait_ref.skip_binder().self_ty()
+ ),
+ );
+ }
+
+ if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
+ self.add_tuple_trait_message(
+ &obligation.cause.code().peel_derives(),
+ &mut err,
+ );
+ }
+
+ if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
+ && predicate_is_const
+ {
+ err.note("`~const Drop` was renamed to `~const Destruct`");
+ err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
+ }
+
+ let explanation = get_explanation_based_on_obligation(
+ &obligation,
+ trait_ref,
+ &trait_predicate,
+ pre_message,
+ );
+
+ self.check_for_binding_assigned_block_without_tail_expression(
+ &obligation,
+ &mut err,
+ trait_predicate,
+ );
+ if self.suggest_add_reference_to_arg(
+ &obligation,
+ &mut err,
+ trait_predicate,
+ have_alt_message,
+ ) {
+ self.note_obligation_cause(&mut err, &obligation);
+ err.emit();
+ return;
+ }
+
+ file_note.map(|note| err.note(note));
+ if let Some(s) = label {
+ // If it has a custom `#[rustc_on_unimplemented]`
+ // error message, let's display it as the label!
+ err.span_label(span, s);
+ if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
+ // When the self type is a type param We don't need to "the trait
+ // `std::marker::Sized` is not implemented for `T`" as we will point
+ // at the type param with a label to suggest constraining it.
+ err.help(explanation);
+ }
+ } else if let Some(custom_explanation) = safe_transmute_explanation {
+ err.span_label(span, custom_explanation);
+ } else {
+ err.span_label(span, explanation);
+ }
+
+ if let ObligationCauseCode::Coercion { source, target } =
+ *obligation.cause.code().peel_derives()
+ {
+ if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
+ self.suggest_borrowing_for_object_cast(
+ &mut err,
+ &root_obligation,
+ source,
+ target,
+ );
+ }
+ }
+
+ let UnsatisfiedConst(unsatisfied_const) = self
+ .maybe_add_note_for_unsatisfied_const(
+ &obligation,
+ trait_ref,
+ &trait_predicate,
+ &mut err,
+ span,
+ );
+
+ if let Some((msg, span)) = type_def {
+ err.span_label(span, msg);
+ }
+ for note in notes {
+ // If it has a custom `#[rustc_on_unimplemented]` note, let's display it
+ err.note(note);
+ }
+ if let Some(s) = parent_label {
+ let body = obligation.cause.body_id;
+ err.span_label(tcx.def_span(body), s);
+ }
+
+ self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref);
+ self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate);
+ let mut suggested =
+ self.suggest_dereferences(&obligation, &mut err, trait_predicate);
+ suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate);
+ let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
+ suggested = if let &[cand] = &impl_candidates[..] {
+ let cand = cand.trait_ref;
+ if let (ty::FnPtr(_), ty::FnDef(..)) =
+ (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind())
+ {
+ err.span_suggestion(
+ span.shrink_to_hi(),
+ format!(
+ "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`",
+ cand.print_only_trait_path(),
+ cand.self_ty(),
+ ),
+ format!(" as {}", cand.self_ty()),
+ Applicability::MaybeIncorrect,
+ );
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ } || suggested;
+ suggested |=
+ self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
+ suggested |= self.suggest_semicolon_removal(
+ &obligation,
+ &mut err,
+ span,
+ trait_predicate,
+ );
+ self.note_version_mismatch(&mut err, &trait_ref);
+ self.suggest_remove_await(&obligation, &mut err);
+ self.suggest_derive(&obligation, &mut err, trait_predicate);
+
+ if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
+ self.suggest_await_before_try(
+ &mut err,
+ &obligation,
+ trait_predicate,
+ span,
+ );
+ }
+
+ if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
+ err.emit();
+ return;
+ }
+
+ if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
+ err.emit();
+ return;
+ }
+
+ if is_unsize {
+ // If the obligation failed due to a missing implementation of the
+ // `Unsize` trait, give a pointer to why that might be the case
+ err.note(
+ "all implementations of `Unsize` are provided \
+ automatically by the compiler, see \
+ <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> \
+ for more information",
+ );
+ }
+
+ let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id());
+ let is_target_feature_fn = if let ty::FnDef(def_id, _) =
+ *trait_ref.skip_binder().self_ty().kind()
+ {
+ !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+ } else {
+ false
+ };
+ if is_fn_trait && is_target_feature_fn {
+ err.note(
+ "`#[target_feature]` functions do not implement the `Fn` traits",
+ );
+ }
+
+ self.try_to_add_help_message(
+ &obligation,
+ trait_ref,
+ &trait_predicate,
+ &mut err,
+ span,
+ is_fn_trait,
+ suggested,
+ unsatisfied_const,
+ );
+
+ // Changing mutability doesn't make a difference to whether we have
+ // an `Unsize` impl (Fixes ICE in #71036)
+ if !is_unsize {
+ self.suggest_change_mut(&obligation, &mut err, trait_predicate);
+ }
+
+ // If this error is due to `!: Trait` not implemented but `(): Trait` is
+ // implemented, and fallback has occurred, then it could be due to a
+ // variable that used to fallback to `()` now falling back to `!`. Issue a
+ // note informing about the change in behaviour.
+ if trait_predicate.skip_binder().self_ty().is_never()
+ && self.fallback_has_occurred
+ {
+ let predicate = trait_predicate.map_bound(|trait_pred| {
+ trait_pred.with_self_ty(self.tcx, Ty::new_unit(self.tcx))
+ });
+ let unit_obligation = obligation.with(tcx, predicate);
+ if self.predicate_may_hold(&unit_obligation) {
+ err.note(
+ "this error might have been caused by changes to \
+ Rust's type-inference algorithm (see issue #48950 \
+ <https://github.com/rust-lang/rust/issues/48950> \
+ for more information)",
+ );
+ err.help("did you intend to use the type `()` here instead?");
+ }
+ }
+
+ self.explain_hrtb_projection(&mut err, trait_predicate, obligation.param_env, &obligation.cause);
+ self.suggest_desugaring_async_fn_in_trait(&mut err, trait_ref);
+
+ // Return early if the trait is Debug or Display and the invocation
+ // originates within a standard library macro, because the output
+ // is otherwise overwhelming and unhelpful (see #85844 for an
+ // example).
+
+ let in_std_macro =
+ match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {
+ Some(macro_def_id) => {
+ let crate_name = tcx.crate_name(macro_def_id.krate);
+ crate_name == sym::std || crate_name == sym::core
+ }
+ None => false,
+ };
+
+ if in_std_macro
+ && matches!(
+ self.tcx.get_diagnostic_name(trait_ref.def_id()),
+ Some(sym::Debug | sym::Display)
+ )
+ {
+ err.emit();
+ return;
+ }
+
+ err
+ }
+
+ ty::PredicateKind::Subtype(predicate) => {
+ // Errors for Subtype predicates show up as
+ // `FulfillmentErrorCode::CodeSubtypeError`,
+ // not selection error.
+ span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
+ }
+
+ ty::PredicateKind::Coerce(predicate) => {
+ // Errors for Coerce predicates show up as
+ // `FulfillmentErrorCode::CodeSubtypeError`,
+ // not selection error.
+ span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
+ }
+
+ ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
+ | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => {
+ span_bug!(
+ span,
+ "outlives clauses should not error outside borrowck. obligation: `{:?}`",
+ obligation
+ )
+ }
+
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {
+ span_bug!(
+ span,
+ "projection clauses should be implied from elsewhere. obligation: `{:?}`",
+ obligation
+ )
+ }
+
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
+ let violations = self.tcx.object_safety_violations(trait_def_id);
+ report_object_safety_error(self.tcx, span, trait_def_id, violations)
+ }
+
+ ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
+ let found_kind = self.closure_kind(closure_args).unwrap();
+ self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
+ }
+
+ ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
+ let ty = self.resolve_vars_if_possible(ty);
+ match self.tcx.sess.opts.unstable_opts.trait_solver {
+ TraitSolver::Classic => {
+ // WF predicates cannot themselves make
+ // errors. They can only block due to
+ // ambiguity; otherwise, they always
+ // degenerate into other obligations
+ // (which may fail).
+ span_bug!(span, "WF predicate not satisfied for {:?}", ty);
+ }
+ TraitSolver::Next | TraitSolver::NextCoherence => {
+ // FIXME: we'll need a better message which takes into account
+ // which bounds actually failed to hold.
+ self.tcx.sess.struct_span_err(
+ span,
+ format!("the type `{ty}` is not well-formed"),
+ )
+ }
+ }
+ }
+
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => {
+ // Errors for `ConstEvaluatable` predicates show up as
+ // `SelectionError::ConstEvalFailure`,
+ // not `Unimplemented`.
+ span_bug!(
+ span,
+ "const-evaluatable requirement gave wrong error: `{:?}`",
+ obligation
+ )
+ }
+
+ ty::PredicateKind::ConstEquate(..) => {
+ // Errors for `ConstEquate` predicates show up as
+ // `SelectionError::ConstEvalFailure`,
+ // not `Unimplemented`.
+ span_bug!(
+ span,
+ "const-equate requirement gave wrong error: `{:?}`",
+ obligation
+ )
+ }
+
+ ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
+
+ ty::PredicateKind::AliasRelate(..) => span_bug!(
+ span,
+ "AliasRelate predicate should never be the predicate cause of a SelectionError"
+ ),
+
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
+ let mut diag = self.tcx.sess.struct_span_err(
+ span,
+ format!("the constant `{ct}` is not of type `{ty}`"),
+ );
+ self.note_type_err(
+ &mut diag,
+ &obligation.cause,
+ None,
+ None,
+ TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())),
+ false,
+ false,
+ );
+ diag
+ }
+ }
+ }
+
+ OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
+ found_trait_ref,
+ expected_trait_ref,
+ 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,
+ }
+ }
+
+ SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id) => self.report_opaque_type_auto_trait_leakage(
+ &obligation,
+ def_id,
+ ),
+
+ TraitNotObjectSafe(did) => {
+ let violations = self.tcx.object_safety_violations(did);
+ report_object_safety_error(self.tcx, span, did, violations)
+ }
+
+ SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {
+ bug!(
+ "MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`"
+ )
+ }
+ SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
+ match self.report_not_const_evaluatable_error(&obligation, span) {
+ Some(err) => err,
+ None => return,
+ }
+ }
+
+ // Already reported in the query.
+ SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) |
+ // Already reported.
+ Overflow(OverflowError::Error(_)) => return,
+
+ Overflow(_) => {
+ bug!("overflow should be handled before the `report_selection_error` path");
+ }
+ SelectionError::ErrorReporting => {
+ bug!("ErrorReporting Overflow should not reach `report_selection_err` call")
+ }
+ };
+
+ self.note_obligation_cause(&mut err, &obligation);
+ self.point_at_returns_when_relevant(&mut err, &obligation);
+ err.emit();
+ }
+
+ fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool {
+ if let ObligationCauseCode::FunctionArgumentObligation {
+ arg_hir_id,
+ ..
+ } = obligation.cause.code()
+ && let Some(Node::Expr(arg)) = self.tcx.hir().find(*arg_hir_id)
+ && let arg = arg.peel_borrows()
+ && let hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { res: hir::def::Res::Local(hir_id), .. },
+ )) = arg.kind
+ && let Some(Node::Pat(pat)) = self.tcx.hir().find(*hir_id)
+ && let Some(preds) = self.reported_trait_errors.borrow().get(&pat.span)
+ && preds.contains(&obligation.predicate)
+ {
+ return true;
+ }
+ false
+ }
+
+ fn report_const_param_not_wf(
+ &self,
+ ty: Ty<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let span = obligation.cause.span;
+
+ let mut diag = match ty.kind() {
+ _ if ty.has_param() => {
+ span_bug!(span, "const param tys cannot mention other generic parameters");
+ }
+ ty::Float(_) => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "`{ty}` is forbidden as the type of a const generic parameter",
+ )
+ }
+ ty::FnPtr(_) => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "using function pointers as const generic parameters is forbidden",
+ )
+ }
+ ty::RawPtr(_) => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "using raw pointers as const generic parameters is forbidden",
+ )
+ }
+ ty::Adt(def, _) => {
+ // We should probably see if we're *allowed* to derive `ConstParamTy` on the type...
+ let mut diag = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter",
+ );
+ // Only suggest derive if this isn't a derived obligation,
+ // and the struct is local.
+ if let Some(span) = self.tcx.hir().span_if_local(def.did())
+ && obligation.cause.code().parent().is_none()
+ {
+ if ty.is_structural_eq_shallow(self.tcx) {
+ diag.span_suggestion(
+ span,
+ "add `#[derive(ConstParamTy)]` to the struct",
+ "#[derive(ConstParamTy)]\n",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ // FIXME(adt_const_params): We should check there's not already an
+ // overlapping `Eq`/`PartialEq` impl.
+ diag.span_suggestion(
+ span,
+ "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct",
+ "#[derive(ConstParamTy, PartialEq, Eq)]\n",
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ diag
+ }
+ _ => {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0741,
+ "`{ty}` can't be used as a const parameter type",
+ )
+ }
+ };
+
+ let mut code = obligation.cause.code();
+ let mut pred = obligation.predicate.to_opt_poly_trait_pred();
+ while let Some((next_code, next_pred)) = code.parent() {
+ if let Some(pred) = pred {
+ let pred = self.instantiate_binder_with_placeholders(pred);
+ diag.note(format!(
+ "`{}` must implement `{}`, but it does not",
+ pred.self_ty(),
+ pred.print_modifiers_and_trait_path()
+ ));
+ }
+ code = next_code;
+ pred = next_pred;
+ }
+
+ diag
+ }
+}
+
+pub(super) trait InferCtxtPrivExt<'tcx> {
+ // returns if `cond` not occurring implies that `error` does not occur - i.e., that
+ // `error` occurring implies that `cond` occurs.
+ fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
+
+ fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>);
+
+ fn report_projection_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ error: &MismatchedProjectionTypes<'tcx>,
+ );
+
+ fn maybe_detailed_projection_msg(
+ &self,
+ pred: ty::ProjectionPredicate<'tcx>,
+ normalized_ty: ty::Term<'tcx>,
+ expected_ty: ty::Term<'tcx>,
+ ) -> Option<String>;
+
+ fn fuzzy_match_tys(
+ &self,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ ignoring_lifetimes: bool,
+ ) -> Option<CandidateSimilarity>;
+
+ fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str>;
+
+ fn find_similar_impl_candidates(
+ &self,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> Vec<ImplCandidate<'tcx>>;
+
+ fn report_similar_impl_candidates(
+ &self,
+ impl_candidates: &[ImplCandidate<'tcx>],
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ body_def_id: LocalDefId,
+ err: &mut Diagnostic,
+ other: bool,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> 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,
+ code: &ObligationCauseCode<'tcx>,
+ ) -> Option<(Ty<'tcx>, Option<Span>)>;
+
+ /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
+ /// with the same path as `trait_ref`, a help message about
+ /// a probable version mismatch is added to `err`
+ fn note_version_mismatch(
+ &self,
+ err: &mut Diagnostic,
+ trait_ref: &ty::PolyTraitRef<'tcx>,
+ ) -> bool;
+
+ /// Creates a `PredicateObligation` with `new_self_ty` replacing the existing type in the
+ /// `trait_ref`.
+ ///
+ /// For this to work, `new_self_ty` must have no escaping bound variables.
+ fn mk_trait_obligation_with_new_self_ty(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
+ ) -> PredicateObligation<'tcx>;
+
+ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>);
+
+ fn predicate_can_apply(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool;
+
+ fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>);
+
+ fn suggest_unsized_bound_if_applicable(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ );
+
+ fn annotate_source_of_ambiguity(
+ &self,
+ err: &mut Diagnostic,
+ impls: &[ambiguity::Ambiguity],
+ predicate: ty::Predicate<'tcx>,
+ );
+
+ fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>);
+
+ fn maybe_indirection_for_unsized(
+ &self,
+ err: &mut Diagnostic,
+ item: &'tcx Item<'tcx>,
+ param: &'tcx GenericParam<'tcx>,
+ ) -> bool;
+
+ fn is_recursive_obligation(
+ &self,
+ obligated_types: &mut Vec<Ty<'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,
+ obligation: PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ span: Span,
+ ) -> GetSafeTransmuteErrorAndReason;
+
+ 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_opaque_type_auto_trait_leakage(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ def_id: DefId,
+ ) -> 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> {
+ // returns if `cond` not occurring implies that `error` does not occur - i.e., that
+ // `error` occurring implies that `cond` occurs.
+ fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool {
+ if cond == error {
+ return true;
+ }
+
+ // FIXME: It should be possible to deal with `ForAll` in a cleaner way.
+ let bound_error = error.kind();
+ let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) {
+ (
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)),
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(error)),
+ ) => (cond, bound_error.rebind(error)),
+ _ => {
+ // FIXME: make this work in other cases too.
+ return false;
+ }
+ };
+
+ for pred in elaborate(self.tcx, std::iter::once(cond)) {
+ let bound_predicate = pred.kind();
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(implication)) =
+ bound_predicate.skip_binder()
+ {
+ let error = error.to_poly_trait_ref();
+ let implication = bound_predicate.rebind(implication.trait_ref);
+ // FIXME: I'm just not taking associated types at all here.
+ // Eventually I'll need to implement param-env-aware
+ // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
+ let param_env = ty::ParamEnv::empty();
+ if self.can_sub(param_env, error, implication) {
+ debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
+ return true;
+ }
+ }
+ }
+
+ false
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
+ if self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError {
+ dump_proof_tree(&error.root_obligation, self.infcx);
+ }
+
+ match error.code {
+ FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
+ self.report_selection_error(
+ error.obligation.clone(),
+ &error.root_obligation,
+ selection_error,
+ );
+ }
+ FulfillmentErrorCode::CodeProjectionError(ref e) => {
+ self.report_projection_error(&error.obligation, e);
+ }
+ FulfillmentErrorCode::CodeAmbiguity { overflow: false } => {
+ self.maybe_report_ambiguity(&error.obligation);
+ }
+ FulfillmentErrorCode::CodeAmbiguity { overflow: true } => {
+ self.report_overflow_no_abort(error.obligation.clone());
+ }
+ FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
+ self.report_mismatched_types(
+ &error.obligation.cause,
+ expected_found.expected,
+ expected_found.found,
+ *err,
+ )
+ .emit();
+ }
+ FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
+ let mut diag = self.report_mismatched_consts(
+ &error.obligation.cause,
+ expected_found.expected,
+ expected_found.found,
+ *err,
+ );
+ let code = error.obligation.cause.code().peel_derives().peel_match_impls();
+ if let ObligationCauseCode::BindingObligation(..)
+ | ObligationCauseCode::ItemObligation(..)
+ | ObligationCauseCode::ExprBindingObligation(..)
+ | ObligationCauseCode::ExprItemObligation(..) = code
+ {
+ self.note_obligation_cause_code(
+ error.obligation.cause.body_id,
+ &mut diag,
+ error.obligation.predicate,
+ error.obligation.param_env,
+ code,
+ &mut vec![],
+ &mut Default::default(),
+ );
+ }
+ diag.emit();
+ }
+ FulfillmentErrorCode::CodeCycle(ref cycle) => {
+ self.report_overflow_obligation_cycle(cycle);
+ }
+ }
+ }
+
+ #[instrument(level = "debug", skip_all)]
+ fn report_projection_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ error: &MismatchedProjectionTypes<'tcx>,
+ ) {
+ let predicate = self.resolve_vars_if_possible(obligation.predicate);
+
+ if predicate.references_error() {
+ return;
+ }
+
+ self.probe(|_| {
+ let ocx = ObligationCtxt::new(self);
+
+ // try to find the mismatched types to report the error with.
+ //
+ // this can fail if the problem was higher-ranked, in which
+ // cause I have no idea for a good error message.
+ let bound_predicate = predicate.kind();
+ let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) =
+ bound_predicate.skip_binder()
+ {
+ let data = self.instantiate_binder_with_fresh_vars(
+ obligation.cause.span,
+ infer::LateBoundRegionConversionTime::HigherRankedType,
+ bound_predicate.rebind(data),
+ );
+ let unnormalized_term = match data.term.unpack() {
+ ty::TermKind::Ty(_) => Ty::new_projection(
+ self.tcx,
+ data.projection_ty.def_id,
+ data.projection_ty.args,
+ )
+ .into(),
+ ty::TermKind::Const(ct) => ty::Const::new_unevaluated(
+ self.tcx,
+ ty::UnevaluatedConst {
+ def: data.projection_ty.def_id,
+ args: data.projection_ty.args,
+ },
+ ct.ty(),
+ )
+ .into(),
+ };
+ // FIXME(-Ztrait-solver=next): For diagnostic purposes, it would be nice
+ // to deeply normalize this type.
+ let normalized_term =
+ ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
+
+ debug!(?obligation.cause, ?obligation.param_env);
+
+ debug!(?normalized_term, data.ty = ?data.term);
+
+ let is_normalized_term_expected = !matches!(
+ obligation.cause.code().peel_derives(),
+ ObligationCauseCode::ItemObligation(_)
+ | ObligationCauseCode::BindingObligation(_, _)
+ | ObligationCauseCode::ExprItemObligation(..)
+ | ObligationCauseCode::ExprBindingObligation(..)
+ | ObligationCauseCode::Coercion { .. }
+ | ObligationCauseCode::OpaqueType
+ );
+
+ // constrain inference variables a bit more to nested obligations from normalize so
+ // we can have more helpful errors.
+ //
+ // we intentionally drop errors from normalization here,
+ // since the normalization is just done to improve the error message.
+ let _ = ocx.select_where_possible();
+
+ if let Err(new_err) = ocx.eq_exp(
+ &obligation.cause,
+ obligation.param_env,
+ is_normalized_term_expected,
+ normalized_term,
+ data.term,
+ ) {
+ (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
+ } else {
+ (None, error.err)
+ }
+ } else {
+ (None, error.err)
+ };
+
+ let msg = values
+ .and_then(|(predicate, _, normalized_term, expected_term)| {
+ self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
+ })
+ .unwrap_or_else(|| {
+ let mut cx = FmtPrinter::new_with_limit(
+ self.tcx,
+ Namespace::TypeNS,
+ rustc_session::Limit(10),
+ );
+ with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", {
+ self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
+ cx.into_buffer()
+ }))
+ });
+ let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
+
+ let secondary_span = (|| {
+ let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
+ predicate.kind().skip_binder()
+ else {
+ return None;
+ };
+
+ let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_ty.def_id)?;
+ let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
+
+ let mut associated_items = vec![];
+ self.tcx.for_each_relevant_impl(
+ self.tcx.trait_of_item(proj.projection_ty.def_id)?,
+ proj.projection_ty.self_ty(),
+ |impl_def_id| {
+ associated_items.extend(
+ self.tcx
+ .associated_items(impl_def_id)
+ .in_definition_order()
+ .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident),
+ );
+ },
+ );
+
+ let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
+ return None;
+ };
+ match self.tcx.hir().get_if_local(associated_item.def_id) {
+ Some(
+ hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Type(_, Some(ty)),
+ ..
+ })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Type(ty),
+ ..
+ }),
+ ) => Some((
+ ty.span,
+ with_forced_trimmed_paths!(Cow::from(format!(
+ "type mismatch resolving `{}`",
+ {
+ let mut cx = FmtPrinter::new_with_limit(
+ self.tcx,
+ Namespace::TypeNS,
+ rustc_session::Limit(5),
+ );
+ self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
+ cx.into_buffer()
+ }
+ ))),
+ )),
+ _ => None,
+ }
+ })();
+
+ self.note_type_err(
+ &mut diag,
+ &obligation.cause,
+ secondary_span,
+ values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
+ infer::ValuePairs::Terms(ExpectedFound::new(
+ is_normalized_ty_expected,
+ normalized_ty,
+ expected_ty,
+ ))
+ }),
+ err,
+ true,
+ false,
+ );
+ self.note_obligation_cause(&mut diag, obligation);
+ diag.emit();
+ });
+ }
+
+ fn maybe_detailed_projection_msg(
+ &self,
+ pred: ty::ProjectionPredicate<'tcx>,
+ normalized_ty: ty::Term<'tcx>,
+ expected_ty: ty::Term<'tcx>,
+ ) -> Option<String> {
+ let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
+ let self_ty = pred.projection_ty.self_ty();
+
+ with_forced_trimmed_paths! {
+ if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
+ let fn_kind = self_ty.prefix_string(self.tcx);
+ let item = match self_ty.kind() {
+ ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
+ _ => self_ty.to_string(),
+ };
+ Some(format!(
+ "expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \
+ returns `{normalized_ty}`",
+ ))
+ } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
+ Some(format!(
+ "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
+ resolves to `{normalized_ty}`"
+ ))
+ } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
+ Some(format!(
+ "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
+ yields `{normalized_ty}`"
+ ))
+ } else {
+ None
+ }
+ }
+ }
+
+ fn fuzzy_match_tys(
+ &self,
+ mut a: Ty<'tcx>,
+ mut b: Ty<'tcx>,
+ ignoring_lifetimes: bool,
+ ) -> Option<CandidateSimilarity> {
+ /// returns the fuzzy category of a given type, or None
+ /// if the type can be equated to any type.
+ fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
+ match t.kind() {
+ ty::Bool => Some(0),
+ ty::Char => Some(1),
+ ty::Str => Some(2),
+ ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => Some(2),
+ ty::Int(..)
+ | ty::Uint(..)
+ | ty::Float(..)
+ | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4),
+ ty::Ref(..) | ty::RawPtr(..) => Some(5),
+ ty::Array(..) | ty::Slice(..) => Some(6),
+ ty::FnDef(..) | ty::FnPtr(..) => Some(7),
+ ty::Dynamic(..) => Some(8),
+ ty::Closure(..) => Some(9),
+ ty::Tuple(..) => Some(10),
+ ty::Param(..) => Some(11),
+ ty::Alias(ty::Projection, ..) => Some(12),
+ ty::Alias(ty::Inherent, ..) => Some(13),
+ ty::Alias(ty::Opaque, ..) => Some(14),
+ ty::Alias(ty::Weak, ..) => Some(15),
+ ty::Never => Some(16),
+ ty::Adt(..) => Some(17),
+ ty::Coroutine(..) => Some(18),
+ ty::Foreign(..) => Some(19),
+ ty::CoroutineWitness(..) => Some(20),
+ ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
+ }
+ }
+
+ let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {
+ loop {
+ match t.kind() {
+ ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => {
+ t = *inner
+ }
+ _ => break t,
+ }
+ }
+ };
+
+ if !ignoring_lifetimes {
+ a = strip_references(a);
+ b = strip_references(b);
+ }
+
+ let cat_a = type_category(self.tcx, a)?;
+ let cat_b = type_category(self.tcx, b)?;
+ if a == b {
+ Some(CandidateSimilarity::Exact { ignoring_lifetimes })
+ } else if cat_a == cat_b {
+ match (a.kind(), b.kind()) {
+ (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,
+ (ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b,
+ // Matching on references results in a lot of unhelpful
+ // suggestions, so let's just not do that for now.
+ //
+ // We still upgrade successful matches to `ignoring_lifetimes: true`
+ // to prioritize that impl.
+ (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => {
+ self.fuzzy_match_tys(a, b, true).is_some()
+ }
+ _ => true,
+ }
+ .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes })
+ } else if ignoring_lifetimes {
+ None
+ } else {
+ self.fuzzy_match_tys(a, b, true)
+ }
+ }
+
+ fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> {
+ self.tcx.hir().body(body_id).coroutine_kind.map(|coroutine_source| match coroutine_source {
+ hir::CoroutineKind::Coroutine => "a coroutine",
+ hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block",
+ hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function",
+ hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure",
+ hir::CoroutineKind::Gen(hir::CoroutineSource::Block) => "a gen block",
+ hir::CoroutineKind::Gen(hir::CoroutineSource::Fn) => "a gen function",
+ hir::CoroutineKind::Gen(hir::CoroutineSource::Closure) => "a gen closure",
+ })
+ }
+
+ fn find_similar_impl_candidates(
+ &self,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> Vec<ImplCandidate<'tcx>> {
+ let mut candidates: Vec<_> = self
+ .tcx
+ .all_impls(trait_pred.def_id())
+ .filter_map(|def_id| {
+ if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
+ || !self.tcx.is_user_visible_dep(def_id.krate)
+ {
+ return None;
+ }
+
+ let imp = self.tcx.impl_trait_ref(def_id).unwrap().skip_binder();
+
+ self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false).map(
+ |similarity| ImplCandidate { trait_ref: imp, similarity, impl_def_id: def_id },
+ )
+ })
+ .collect();
+ if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
+ // If any of the candidates is a perfect match, we don't want to show all of them.
+ // This is particularly relevant for the case of numeric types (as they all have the
+ // same category).
+ candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
+ }
+ candidates
+ }
+
+ fn report_similar_impl_candidates(
+ &self,
+ impl_candidates: &[ImplCandidate<'tcx>],
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ body_def_id: LocalDefId,
+ err: &mut Diagnostic,
+ other: bool,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> bool {
+ // If we have a single implementation, try to unify it with the trait ref
+ // that failed. This should uncover a better hint for what *is* implemented.
+ if let [single] = &impl_candidates {
+ if self.probe(|_| {
+ let ocx = ObligationCtxt::new(self);
+ let obligation_trait_ref = self.instantiate_binder_with_placeholders(trait_ref);
+ let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id);
+ let impl_trait_ref = ocx.normalize(
+ &ObligationCause::dummy(),
+ param_env,
+ ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args),
+ );
+
+ ocx.register_obligations(
+ self.tcx
+ .predicates_of(single.impl_def_id)
+ .instantiate(self.tcx, impl_args)
+ .into_iter()
+ .map(|(clause, _)| {
+ Obligation::new(self.tcx, ObligationCause::dummy(), param_env, clause)
+ }),
+ );
+ if !ocx.select_where_possible().is_empty() {
+ return false;
+ }
+
+ let mut terrs = vec![];
+ for (obligation_arg, impl_arg) in
+ std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args)
+ {
+ if let Err(terr) =
+ ocx.eq(&ObligationCause::dummy(), param_env, impl_arg, obligation_arg)
+ {
+ terrs.push(terr);
+ }
+ if !ocx.select_where_possible().is_empty() {
+ return false;
+ }
+ }
+
+ // Literally nothing unified, just give up.
+ if terrs.len() == impl_trait_ref.args.len() {
+ return false;
+ }
+
+ let cand =
+ self.resolve_vars_if_possible(impl_trait_ref).fold_with(&mut BottomUpFolder {
+ tcx: self.tcx,
+ ty_op: |ty| ty,
+ lt_op: |lt| lt,
+ ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
+ });
+ err.highlighted_help(vec![
+ (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
+ ("is".to_string(), Style::Highlight),
+ (" implemented for `".to_string(), Style::NoStyle),
+ (cand.self_ty().to_string(), Style::Highlight),
+ ("`".to_string(), Style::NoStyle),
+ ]);
+
+ if let [TypeError::Sorts(exp_found)] = &terrs[..] {
+ let exp_found = self.resolve_vars_if_possible(*exp_found);
+ err.help(format!(
+ "for that trait implementation, expected `{}`, found `{}`",
+ exp_found.expected, exp_found.found
+ ));
+ }
+
+ true
+ }) {
+ return true;
+ }
+ }
+
+ let other = if other { "other " } else { "" };
+ let report = |candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
+ if candidates.is_empty() {
+ return false;
+ }
+ if let &[cand] = &candidates[..] {
+ let (desc, mention_castable) =
+ match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
+ (ty::FnPtr(_), ty::FnDef(..)) => {
+ (" implemented for fn pointer `", ", cast using `as`")
+ }
+ (ty::FnPtr(_), _) => (" implemented for fn pointer `", ""),
+ _ => (" implemented for `", ""),
+ };
+ err.highlighted_help(vec![
+ (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle),
+ ("is".to_string(), Style::Highlight),
+ (desc.to_string(), Style::NoStyle),
+ (cand.self_ty().to_string(), Style::Highlight),
+ ("`".to_string(), Style::NoStyle),
+ (mention_castable.to_string(), Style::NoStyle),
+ ]);
+ return true;
+ }
+ let trait_ref = TraitRef::identity(self.tcx, candidates[0].def_id);
+ // Check if the trait is the same in all cases. If so, we'll only show the type.
+ let mut traits: Vec<_> =
+ candidates.iter().map(|c| c.print_only_trait_path().to_string()).collect();
+ traits.sort();
+ traits.dedup();
+ // FIXME: this could use a better heuristic, like just checking
+ // that args[1..] is the same.
+ let all_traits_equal = traits.len() == 1;
+
+ let candidates: Vec<String> = candidates
+ .into_iter()
+ .map(|c| {
+ if all_traits_equal {
+ format!("\n {}", c.self_ty())
+ } else {
+ format!("\n {c}")
+ }
+ })
+ .collect();
+
+ let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
+ err.help(format!(
+ "the following {other}types implement trait `{}`:{}{}",
+ trait_ref.print_only_trait_path(),
+ candidates[..end].join(""),
+ if candidates.len() > 9 {
+ format!("\nand {} others", candidates.len() - 8)
+ } else {
+ String::new()
+ }
+ ));
+ true
+ };
+
+ let def_id = trait_ref.def_id();
+ if impl_candidates.is_empty() {
+ if self.tcx.trait_is_auto(def_id)
+ || self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
+ || self.tcx.get_diagnostic_name(def_id).is_some()
+ {
+ // Mentioning implementers of `Copy`, `Debug` and friends is not useful.
+ return false;
+ }
+ let mut impl_candidates: Vec<_> = self
+ .tcx
+ .all_impls(def_id)
+ // Ignore automatically derived impls and `!Trait` impls.
+ .filter(|&def_id| {
+ self.tcx.impl_polarity(def_id) != ty::ImplPolarity::Negative
+ || self.tcx.is_automatically_derived(def_id)
+ })
+ .filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
+ .map(ty::EarlyBinder::instantiate_identity)
+ .filter(|trait_ref| {
+ let self_ty = trait_ref.self_ty();
+ // Avoid mentioning type parameters.
+ if let ty::Param(_) = self_ty.kind() {
+ false
+ }
+ // Avoid mentioning types that are private to another crate
+ else if let ty::Adt(def, _) = self_ty.peel_refs().kind() {
+ // FIXME(compiler-errors): This could be generalized, both to
+ // be more granular, and probably look past other `#[fundamental]`
+ // types, too.
+ self.tcx.visibility(def.did()).is_accessible_from(body_def_id, self.tcx)
+ } else {
+ true
+ }
+ })
+ .collect();
+
+ impl_candidates.sort();
+ impl_candidates.dedup();
+ return report(impl_candidates, err);
+ }
+
+ // Sort impl candidates so that ordering is consistent for UI tests.
+ // because the ordering of `impl_candidates` may not be deterministic:
+ // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
+ //
+ // Prefer more similar candidates first, then sort lexicographically
+ // by their normalized string representation.
+ let mut impl_candidates: Vec<_> = impl_candidates
+ .iter()
+ .cloned()
+ .map(|mut cand| {
+ // Fold the consts so that they shows up as, e.g., `10`
+ // instead of `core::::array::{impl#30}::{constant#0}`.
+ cand.trait_ref = cand.trait_ref.fold_with(&mut BottomUpFolder {
+ tcx: self.tcx,
+ ty_op: |ty| ty,
+ lt_op: |lt| lt,
+ ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
+ });
+ cand
+ })
+ .collect();
+ impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref));
+ let mut impl_candidates: Vec<_> =
+ impl_candidates.into_iter().map(|cand| cand.trait_ref).collect();
+ impl_candidates.dedup();
+
+ report(impl_candidates, err)
+ }
+
+ fn report_similar_impl_candidates_for_root_obligation(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ body_def_id: LocalDefId,
+ err: &mut 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,
+ obligation.param_env,
+ );
+ }
+ }
+
+ /// Gets the parent trait chain start
+ fn get_parent_trait_ref(
+ &self,
+ code: &ObligationCauseCode<'tcx>,
+ ) -> Option<(Ty<'tcx>, Option<Span>)> {
+ match code {
+ ObligationCauseCode::BuiltinDerivedObligation(data) => {
+ let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
+ match self.get_parent_trait_ref(&data.parent_code) {
+ Some(t) => Some(t),
+ None => {
+ let ty = parent_trait_ref.skip_binder().self_ty();
+ let span = TyCategory::from_ty(self.tcx, ty)
+ .map(|(_, def_id)| self.tcx.def_span(def_id));
+ Some((ty, span))
+ }
+ }
+ }
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ self.get_parent_trait_ref(&parent_code)
+ }
+ _ => None,
+ }
+ }
+
+ /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait
+ /// with the same path as `trait_ref`, a help message about
+ /// a probable version mismatch is added to `err`
+ fn note_version_mismatch(
+ &self,
+ err: &mut Diagnostic,
+ trait_ref: &ty::PolyTraitRef<'tcx>,
+ ) -> bool {
+ let get_trait_impls = |trait_def_id| {
+ let mut trait_impls = vec![];
+ self.tcx.for_each_relevant_impl(
+ trait_def_id,
+ trait_ref.skip_binder().self_ty(),
+ |impl_def_id| {
+ trait_impls.push(impl_def_id);
+ },
+ );
+ trait_impls
+ };
+
+ let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
+ let traits_with_same_path: std::collections::BTreeSet<_> = self
+ .tcx
+ .all_traits()
+ .filter(|trait_def_id| *trait_def_id != trait_ref.def_id())
+ .filter(|trait_def_id| self.tcx.def_path_str(*trait_def_id) == required_trait_path)
+ .collect();
+ let mut suggested = false;
+ for trait_with_same_path in traits_with_same_path {
+ let trait_impls = get_trait_impls(trait_with_same_path);
+ if trait_impls.is_empty() {
+ continue;
+ }
+ let impl_spans: Vec<_> =
+ trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect();
+ err.span_help(
+ impl_spans,
+ format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
+ );
+ let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
+ let crate_msg =
+ format!("perhaps two different versions of crate `{trait_crate}` are being used?");
+ err.note(crate_msg);
+ suggested = true;
+ }
+ suggested
+ }
+
+ fn mk_trait_obligation_with_new_self_ty(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
+ ) -> PredicateObligation<'tcx> {
+ let trait_pred =
+ trait_ref_and_ty.map_bound(|(tr, new_self_ty)| tr.with_self_ty(self.tcx, new_self_ty));
+
+ Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
+ // Unable to successfully determine, probably means
+ // insufficient type information, but could mean
+ // ambiguous impls. The latter *ought* to be a
+ // coherence violation, so we don't report it here.
+
+ let predicate = self.resolve_vars_if_possible(obligation.predicate);
+ let span = obligation.cause.span;
+
+ debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
+
+ // Ambiguity errors are often caused as fallout from earlier errors.
+ // We ignore them if this `infcx` is tainted in some cases below.
+
+ let bound_predicate = predicate.kind();
+ let mut err = match bound_predicate.skip_binder() {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
+ let trait_ref = bound_predicate.rebind(data.trait_ref);
+ debug!(?trait_ref);
+
+ if predicate.references_error() {
+ return;
+ }
+
+ // This is kind of a hack: it frequently happens that some earlier
+ // error prevents types from being fully inferred, and then we get
+ // a bunch of uninteresting errors saying something like "<generic
+ // #0> doesn't implement Sized". It may even be true that we
+ // could just skip over all checks where the self-ty is an
+ // inference variable, but I was afraid that there might be an
+ // inference variable created, registered as an obligation, and
+ // then never forced by writeback, and hence by skipping here we'd
+ // be ignoring the fact that we don't KNOW the type works
+ // out. Though even that would probably be harmless, given that
+ // we're only talking about builtin traits, which are known to be
+ // inhabited. We used to check for `self.tcx.sess.has_errors()` to
+ // avoid inundating the user with unnecessary errors, but we now
+ // check upstream for type errors and don't add the obligations to
+ // begin with in those cases.
+ if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
+ if let None = self.tainted_by_errors() {
+ let err = self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ trait_ref.self_ty().skip_binder().into(),
+ ErrorCode::E0282,
+ false,
+ );
+ err.stash(span, StashKey::MaybeForgetReturn);
+ }
+ return;
+ }
+
+ // Typically, this ambiguity should only happen if
+ // there are unresolved type inference variables
+ // (otherwise it would suggest a coherence
+ // failure). But given #21974 that is not necessarily
+ // the case -- we can have multiple where clauses that
+ // are only distinguished by a region, which results
+ // in an ambiguity even when all types are fully
+ // known, since we don't dispatch based on region
+ // relationships.
+
+ // Pick the first substitution that still contains inference variables as the one
+ // we're going to emit an error for. If there are none (see above), fall back to
+ // a more general error.
+ let subst = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
+
+ let mut err = if let Some(subst) = subst {
+ self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ subst,
+ ErrorCode::E0283,
+ true,
+ )
+ } else {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0283,
+ "type annotations needed: cannot satisfy `{}`",
+ predicate,
+ )
+ };
+
+ let mut ambiguities = ambiguity::recompute_applicable_impls(
+ self.infcx,
+ &obligation.with(self.tcx, trait_ref),
+ );
+ let has_non_region_infer =
+ trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
+ // It doesn't make sense to talk about applicable impls if there are more than a
+ // handful of them. If there are a lot of them, but only a few of them have no type
+ // params, we only show those, as they are more likely to be useful/intended.
+ if ambiguities.len() > 5 {
+ let infcx = self.infcx;
+ if !ambiguities.iter().all(|option| match option {
+ DefId(did) => infcx.fresh_args_for_item(DUMMY_SP, *did).is_empty(),
+ ParamEnv(_) => true,
+ }) {
+ // If not all are blanket impls, we filter blanked impls out.
+ ambiguities.retain(|option| match option {
+ DefId(did) => infcx.fresh_args_for_item(DUMMY_SP, *did).is_empty(),
+ ParamEnv(_) => true,
+ });
+ }
+ }
+ if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
+ if self.tainted_by_errors().is_some() && subst.is_none() {
+ // If `subst.is_none()`, then this is probably two param-env
+ // candidates or impl candidates that are equal modulo lifetimes.
+ // Therefore, if we've already emitted an error, just skip this
+ // one, since it's not particularly actionable.
+ err.cancel();
+ return;
+ }
+ self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
+ } else {
+ if self.tainted_by_errors().is_some() {
+ err.cancel();
+ return;
+ }
+ err.note(format!("cannot satisfy `{predicate}`"));
+ let impl_candidates = self
+ .find_similar_impl_candidates(predicate.to_opt_poly_trait_pred().unwrap());
+ if impl_candidates.len() < 40 {
+ self.report_similar_impl_candidates(
+ impl_candidates.as_slice(),
+ trait_ref,
+ obligation.cause.body_id,
+ &mut err,
+ false,
+ obligation.param_env,
+ );
+ }
+ }
+
+ if let ObligationCauseCode::ItemObligation(def_id)
+ | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code()
+ {
+ self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
+ }
+
+ if let Some(ty::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack())
+ && let Some(body_id) =
+ self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
+ {
+ let mut expr_finder = FindExprBySpan::new(span);
+ expr_finder.visit_expr(&self.tcx.hir().body(body_id).value);
+
+ if let Some(hir::Expr {
+ kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
+ ..
+ }) = expr_finder.result
+ && let [
+ ..,
+ trait_path_segment @ hir::PathSegment {
+ res: Res::Def(DefKind::Trait, trait_id),
+ ..
+ },
+ hir::PathSegment {
+ ident: assoc_item_name,
+ res: Res::Def(_, item_id),
+ ..
+ },
+ ] = path.segments
+ && data.trait_ref.def_id == *trait_id
+ && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
+ && let None = self.tainted_by_errors()
+ {
+ let (verb, noun) = match self.tcx.associated_item(item_id).kind {
+ ty::AssocKind::Const => ("refer to the", "constant"),
+ ty::AssocKind::Fn => ("call", "function"),
+ // This is already covered by E0223, but this following single match
+ // arm doesn't hurt here.
+ ty::AssocKind::Type => ("refer to the", "type"),
+ };
+
+ // Replace the more general E0283 with a more specific error
+ err.cancel();
+ err = self.tcx.sess.struct_span_err_with_code(
+ span,
+ format!(
+ "cannot {verb} associated {noun} on trait without specifying the \
+ corresponding `impl` type",
+ ),
+ rustc_errors::error_code!(E0790),
+ );
+
+ if let Some(local_def_id) = data.trait_ref.def_id.as_local()
+ && let Some(hir::Node::Item(hir::Item {
+ ident: trait_name,
+ kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
+ ..
+ })) = self.tcx.hir().find_by_def_id(local_def_id)
+ && let Some(method_ref) = trait_item_refs
+ .iter()
+ .find(|item_ref| item_ref.ident == *assoc_item_name)
+ {
+ err.span_label(
+ method_ref.span,
+ format!("`{trait_name}::{assoc_item_name}` defined here"),
+ );
+ }
+
+ err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
+
+ let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
+
+ if let Some(impl_def_id) =
+ trait_impls.non_blanket_impls().values().flatten().next()
+ {
+ let non_blanket_impl_count =
+ trait_impls.non_blanket_impls().values().flatten().count();
+ // If there is only one implementation of the trait, suggest using it.
+ // Otherwise, use a placeholder comment for the implementation.
+ let (message, self_type) = if non_blanket_impl_count == 1 {
+ (
+ "use the fully-qualified path to the only available \
+ implementation",
+ format!(
+ "{}",
+ self.tcx.type_of(impl_def_id).instantiate_identity()
+ ),
+ )
+ } else {
+ (
+ "use a fully-qualified path to a specific available \
+ implementation",
+ "/* self type */".to_string(),
+ )
+ };
+ let mut suggestions =
+ vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
+ if let Some(generic_arg) = trait_path_segment.args {
+ let between_span =
+ trait_path_segment.ident.span.between(generic_arg.span_ext);
+ // get rid of :: between Trait and <type>
+ // must be '::' between them, otherwise the parser won't accept the code
+ suggestions.push((between_span, "".to_string()));
+ suggestions
+ .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
+ } else {
+ suggestions.push((
+ trait_path_segment.ident.span.shrink_to_hi(),
+ ">".to_string(),
+ ));
+ }
+ err.multipart_suggestion(
+ message,
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ };
+
+ err
+ }
+
+ ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+ // Same hacky approach as above to avoid deluging user
+ // with error messages.
+ if arg.references_error()
+ || self.tcx.sess.has_errors().is_some()
+ || self.tainted_by_errors().is_some()
+ {
+ return;
+ }
+
+ self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ arg,
+ ErrorCode::E0282,
+ false,
+ )
+ }
+
+ ty::PredicateKind::Subtype(data) => {
+ if data.references_error()
+ || self.tcx.sess.has_errors().is_some()
+ || self.tainted_by_errors().is_some()
+ {
+ // no need to overload user in such cases
+ return;
+ }
+ let SubtypePredicate { a_is_expected: _, a, b } = data;
+ // both must be type variables, or the other would've been instantiated
+ assert!(a.is_ty_var() && b.is_ty_var());
+ self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ a.into(),
+ ErrorCode::E0282,
+ true,
+ )
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
+ if predicate.references_error() || self.tainted_by_errors().is_some() {
+ return;
+ }
+ let subst = data
+ .projection_ty
+ .args
+ .iter()
+ .chain(Some(data.term.into_arg()))
+ .find(|g| g.has_non_region_infer());
+ if let Some(subst) = subst {
+ let mut err = self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ subst,
+ ErrorCode::E0284,
+ true,
+ );
+ err.note(format!("cannot satisfy `{predicate}`"));
+ err
+ } else {
+ // If we can't find a substitution, just print a generic error
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0284,
+ "type annotations needed: cannot satisfy `{}`",
+ predicate,
+ );
+ err.span_label(span, format!("cannot satisfy `{predicate}`"));
+ err
+ }
+ }
+
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
+ if predicate.references_error() || self.tainted_by_errors().is_some() {
+ return;
+ }
+ let subst = data.walk().find(|g| g.is_non_region_infer());
+ if let Some(subst) = subst {
+ let err = self.emit_inference_failure_err(
+ obligation.cause.body_id,
+ span,
+ subst,
+ ErrorCode::E0284,
+ true,
+ );
+ err
+ } else {
+ // If we can't find a substitution, just print a generic error
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0284,
+ "type annotations needed: cannot satisfy `{}`",
+ predicate,
+ );
+ err.span_label(span, format!("cannot satisfy `{predicate}`"));
+ err
+ }
+ }
+ _ => {
+ if self.tcx.sess.has_errors().is_some() || self.tainted_by_errors().is_some() {
+ return;
+ }
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0284,
+ "type annotations needed: cannot satisfy `{}`",
+ predicate,
+ );
+ err.span_label(span, format!("cannot satisfy `{predicate}`"));
+ err
+ }
+ };
+ self.note_obligation_cause(&mut err, obligation);
+ err.emit();
+ }
+
+ fn annotate_source_of_ambiguity(
+ &self,
+ err: &mut Diagnostic,
+ ambiguities: &[ambiguity::Ambiguity],
+ predicate: ty::Predicate<'tcx>,
+ ) {
+ let mut spans = vec![];
+ let mut crates = vec![];
+ let mut post = vec![];
+ let mut has_param_env = false;
+ for ambiguity in ambiguities {
+ match ambiguity {
+ ambiguity::Ambiguity::DefId(impl_def_id) => {
+ match self.tcx.span_of_impl(*impl_def_id) {
+ Ok(span) => spans.push(span),
+ Err(name) => {
+ crates.push(name);
+ if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
+ post.push(header);
+ }
+ }
+ }
+ }
+ ambiguity::Ambiguity::ParamEnv(span) => {
+ has_param_env = true;
+ spans.push(*span);
+ }
+ }
+ }
+ let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
+ crate_names.sort();
+ crate_names.dedup();
+ post.sort();
+ post.dedup();
+
+ if self.tainted_by_errors().is_some()
+ && (crate_names.len() == 1
+ && spans.len() == 0
+ && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
+ || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
+ {
+ // Avoid complaining about other inference issues for expressions like
+ // `42 >> 1`, where the types are still `{integer}`, but we want to
+ // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
+ // NOTE(eddyb) this was `.cancel()`, but `err`
+ // is borrowed, so we can't fully defuse it.
+ err.downgrade_to_delayed_bug();
+ return;
+ }
+
+ let msg = format!(
+ "multiple `impl`s{} satisfying `{}` found",
+ if has_param_env { " or `where` clauses" } else { "" },
+ predicate
+ );
+ let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+ format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
+ } else if post.len() == 1 {
+ format!(": `{}`", post[0])
+ } else {
+ String::new()
+ };
+
+ match (spans.len(), crates.len(), crate_names.len()) {
+ (0, 0, 0) => {
+ err.note(format!("cannot satisfy `{predicate}`"));
+ }
+ (0, _, 1) => {
+ err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
+ }
+ (0, _, _) => {
+ err.note(format!(
+ "{} in the following crates: {}{}",
+ msg,
+ crate_names.join(", "),
+ post,
+ ));
+ }
+ (_, 0, 0) => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, msg);
+ }
+ (_, 1, 1) => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, msg);
+ err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
+ }
+ _ => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, msg);
+ err.note(format!(
+ "and more `impl`s found in the following crates: {}{}",
+ crate_names.join(", "),
+ post,
+ ));
+ }
+ }
+ }
+
+ /// Returns `true` if the trait predicate may apply for *some* assignment
+ /// to the type parameters.
+ fn predicate_can_apply(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool {
+ struct ParamToVarFolder<'a, 'tcx> {
+ infcx: &'a InferCtxt<'tcx>,
+ var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
+ }
+
+ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ParamToVarFolder<'a, 'tcx> {
+ fn interner(&self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ if let ty::Param(_) = *ty.kind() {
+ let infcx = self.infcx;
+ *self.var_map.entry(ty).or_insert_with(|| {
+ infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::MiscVariable,
+ span: DUMMY_SP,
+ })
+ })
+ } else {
+ ty.super_fold_with(self)
+ }
+ }
+ }
+
+ self.probe(|_| {
+ let cleaned_pred =
+ pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
+
+ let InferOk { value: cleaned_pred, .. } =
+ self.infcx.at(&ObligationCause::dummy(), param_env).normalize(cleaned_pred);
+
+ let obligation =
+ Obligation::new(self.tcx, ObligationCause::dummy(), param_env, cleaned_pred);
+
+ self.predicate_may_hold(&obligation)
+ })
+ }
+
+ fn note_obligation_cause(&self, err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>) {
+ // First, attempt to add note to this error with an async-await-specific
+ // message, and fall back to regular note otherwise.
+ if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
+ self.note_obligation_cause_code(
+ obligation.cause.body_id,
+ err,
+ obligation.predicate,
+ obligation.param_env,
+ obligation.cause.code(),
+ &mut vec![],
+ &mut Default::default(),
+ );
+ self.suggest_unsized_bound_if_applicable(err, obligation);
+ }
+ }
+
+ #[instrument(level = "debug", skip_all)]
+ fn suggest_unsized_bound_if_applicable(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ ) {
+ let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
+ obligation.predicate.kind().skip_binder()
+ else {
+ return;
+ };
+ let (ObligationCauseCode::BindingObligation(item_def_id, span)
+ | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) =
+ *obligation.cause.code().peel_derives()
+ else {
+ return;
+ };
+ debug!(?pred, ?item_def_id, ?span);
+
+ let (Some(node), true) = (
+ self.tcx.hir().get_if_local(item_def_id),
+ Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
+ ) else {
+ return;
+ };
+ self.maybe_suggest_unsized_generics(err, span, node);
+ }
+
+ #[instrument(level = "debug", skip_all)]
+ fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'tcx>) {
+ let Some(generics) = node.generics() else {
+ return;
+ };
+ let sized_trait = self.tcx.lang_items().sized_trait();
+ debug!(?generics.params);
+ debug!(?generics.predicates);
+ let Some(param) = generics.params.iter().find(|param| param.span == span) else {
+ return;
+ };
+ // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+ // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+ let explicitly_sized = generics
+ .bounds_for_param(param.def_id)
+ .flat_map(|bp| bp.bounds)
+ .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
+ if explicitly_sized {
+ return;
+ }
+ debug!(?param);
+ match node {
+ hir::Node::Item(
+ item @ hir::Item {
+ // Only suggest indirection for uses of type parameters in ADTs.
+ kind:
+ hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
+ ..
+ },
+ ) => {
+ if self.maybe_indirection_for_unsized(err, item, param) {
+ return;
+ }
+ }
+ _ => {}
+ };
+ // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
+ let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param.def_id)
+ {
+ (s, " +")
+ } else {
+ (span.shrink_to_hi(), ":")
+ };
+ err.span_suggestion_verbose(
+ span,
+ "consider relaxing the implicit `Sized` restriction",
+ format!("{separator} ?Sized"),
+ Applicability::MachineApplicable,
+ );
+ }
+
+ fn maybe_indirection_for_unsized(
+ &self,
+ err: &mut Diagnostic,
+ item: &Item<'tcx>,
+ param: &GenericParam<'tcx>,
+ ) -> bool {
+ // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
+ // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
+ // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
+ let mut visitor =
+ FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
+ visitor.visit_item(item);
+ if visitor.invalid_spans.is_empty() {
+ return false;
+ }
+ let mut multispan: MultiSpan = param.span.into();
+ multispan.push_span_label(
+ param.span,
+ format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
+ );
+ for sp in visitor.invalid_spans {
+ multispan.push_span_label(
+ sp,
+ format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
+ );
+ }
+ err.span_help(
+ multispan,
+ format!(
+ "you could relax the implicit `Sized` bound on `{T}` if it were \
+ used through indirection like `&{T}` or `Box<{T}>`",
+ T = param.name.ident(),
+ ),
+ );
+ true
+ }
+
+ fn is_recursive_obligation(
+ &self,
+ obligated_types: &mut Vec<Ty<'tcx>>,
+ cause_code: &ObligationCauseCode<'tcx>,
+ ) -> bool {
+ if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
+ let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
+ let self_ty = parent_trait_ref.skip_binder().self_ty();
+ if obligated_types.iter().any(|ot| ot == &self_ty) {
+ return true;
+ }
+ if let ty::Adt(def, args) = self_ty.kind()
+ && let [arg] = &args[..]
+ && let ty::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Adt(inner_def, _) = ty.kind()
+ && inner_def == def
+ {
+ return true;
+ }
+ }
+ false
+ }
+
+ fn get_standard_error_message(
+ &self,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ message: Option<String>,
+ predicate_is_const: bool,
+ append_const_msg: Option<AppendConstMessage>,
+ post_message: String,
+ ) -> String {
+ message
+ .and_then(|cannot_do_this| {
+ match (predicate_is_const, append_const_msg) {
+ // do nothing if predicate is not const
+ (false, _) => Some(cannot_do_this),
+ // suggested using default post message
+ (true, Some(AppendConstMessage::Default)) => {
+ Some(format!("{cannot_do_this} in const contexts"))
+ }
+ // overridden post message
+ (true, Some(AppendConstMessage::Custom(custom_msg))) => {
+ Some(format!("{cannot_do_this}{custom_msg}"))
+ }
+ // fallback to generic message
+ (true, None) => None,
+ }
+ })
+ .unwrap_or_else(|| {
+ format!("the trait bound `{trait_predicate}` is not satisfied{post_message}")
+ })
+ }
+
+ fn get_safe_transmute_error_and_reason(
+ &self,
+ obligation: PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ span: Span,
+ ) -> GetSafeTransmuteErrorAndReason {
+ use rustc_transmute::Answer;
+
+ // Erase regions because layout code doesn't particularly care about regions.
+ let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
+
+ let src_and_dst = rustc_transmute::Types {
+ dst: trait_ref.args.type_at(0),
+ src: trait_ref.args.type_at(1),
+ };
+ let scope = trait_ref.args.type_at(2);
+ let Some(assume) = rustc_transmute::Assume::from_const(
+ self.infcx.tcx,
+ obligation.param_env,
+ trait_ref.args.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(
+ obligation.cause,
+ src_and_dst,
+ scope,
+ assume,
+ ) {
+ Answer::No(reason) => {
+ let dst = trait_ref.args.type_at(0);
+ let src = trait_ref.args.type_at(1);
+ let err_msg = format!(
+ "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
+ );
+ let safe_transmute_explanation = match reason {
+ rustc_transmute::Reason::SrcIsUnspecified => {
+ format!("`{src}` does not have a well-specified layout")
+ }
+
+ rustc_transmute::Reason::DstIsUnspecified => {
+ 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}`")
+ }
+
+ rustc_transmute::Reason::DstIsPrivate => format!(
+ "`{dst}` is or contains a type or field that is not visible in that scope"
+ ),
+ rustc_transmute::Reason::DstIsTooBig => {
+ format!("The size of `{src}` is smaller than the size of `{dst}`")
+ }
+ rustc_transmute::Reason::SrcSizeOverflow => {
+ format!(
+ "values of the type `{src}` are too big for the current architecture"
+ )
+ }
+ rustc_transmute::Reason::DstSizeOverflow => {
+ format!(
+ "values of the type `{dst}` are too big for the current architecture"
+ )
+ }
+ rustc_transmute::Reason::DstHasStricterAlignment {
+ src_min_align,
+ dst_min_align,
+ } => {
+ format!(
+ "The minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
+ )
+ }
+ rustc_transmute::Reason::DstIsMoreUnique => {
+ format!("`{src}` is a shared reference, but `{dst}` is a unique reference")
+ }
+ // Already reported by rustc
+ rustc_transmute::Reason::TypeError => {
+ return GetSafeTransmuteErrorAndReason::Silent;
+ }
+ rustc_transmute::Reason::SrcLayoutUnknown => {
+ format!("`{src}` has an unknown layout")
+ }
+ rustc_transmute::Reason::DstLayoutUnknown => {
+ format!("`{dst}` has an unknown layout")
+ }
+ };
+ GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation }
+ }
+ // Should never get a Yes at this point! We already ran it before, and did not get a Yes.
+ Answer::Yes => span_bug!(
+ span,
+ "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
+ ),
+ other => span_bug!(span, "Unsupported rustc_transmute::Answer variant: `{other:?}`"),
+ }
+ }
+
+ 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;
+ let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } =
+ obligation.cause.code()
+ {
+ *rhs_span
+ } else {
+ span
+ };
+
+ // Try to report a help message
+ if is_fn_trait
+ && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
+ obligation.param_env,
+ trait_ref.self_ty(),
+ trait_predicate.skip_binder().polarity,
+ )
+ {
+ self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
+ } else if !trait_ref.has_non_region_infer()
+ && self.predicate_can_apply(obligation.param_env, *trait_predicate)
+ {
+ // If a where-clause may be useful, remind the
+ // user that they can add it.
+ //
+ // don't display an on-unimplemented note, as
+ // these notes will often be of the form
+ // "the type `T` can't be frobnicated"
+ // which is somewhat confusing.
+ self.suggest_restricting_param_bound(
+ err,
+ *trait_predicate,
+ None,
+ obligation.cause.body_id,
+ );
+ } else if trait_ref.def_id().is_local()
+ && self.tcx.trait_impls_of(trait_ref.def_id()).is_empty()
+ && !self.tcx.trait_is_auto(trait_ref.def_id())
+ && !self.tcx.trait_is_alias(trait_ref.def_id())
+ {
+ err.span_help(
+ self.tcx.def_span(trait_ref.def_id()),
+ crate::fluent_generated::trait_selection_trait_has_no_impls,
+ );
+ } else if !suggested && !unsatisfied_const {
+ // Can't show anything else useful, try to find similar impls.
+ let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
+ if !self.report_similar_impl_candidates(
+ &impl_candidates,
+ trait_ref,
+ body_def_id,
+ err,
+ true,
+ obligation.param_env,
+ ) {
+ self.report_similar_impl_candidates_for_root_obligation(
+ &obligation,
+ *trait_predicate,
+ body_def_id,
+ err,
+ );
+ }
+
+ self.suggest_convert_to_slice(
+ err,
+ obligation,
+ trait_ref,
+ impl_candidates.as_slice(),
+ span,
+ );
+ }
+ }
+
+ fn add_help_message_for_fn_trait(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ err: &mut 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().args.type_at(1);
+ if let ty::Tuple(given) = given_ty.kind()
+ && let ty::Tuple(expected) = expected_ty.kind()
+ {
+ if expected.len() != given.len() {
+ // Note number of types that were expected and given
+ err.note(
+ format!(
+ "expected a closure taking {} argument{}, but one taking {} argument{} was given",
+ given.len(),
+ pluralize!(given.len()),
+ expected.len(),
+ pluralize!(expected.len()),
+ )
+ );
+ } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
+ // Print type mismatch
+ let (expected_args, given_args) = self.cmp(given_ty, expected_ty);
+ err.note_expected_found(
+ &"a closure with arguments",
+ expected_args,
+ &"a closure with arguments",
+ given_args,
+ );
+ }
+ }
+ }
+
+ fn maybe_add_note_for_unsatisfied_const(
+ &self,
+ _obligation: &PredicateObligation<'tcx>,
+ _trait_ref: ty::PolyTraitRef<'tcx>,
+ _trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ _err: &mut Diagnostic,
+ _span: Span,
+ ) -> UnsatisfiedConst {
+ let unsatisfied_const = UnsatisfiedConst(false);
+ // FIXME(effects)
+ unsatisfied_const
+ }
+
+ fn report_closure_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ closure_def_id: DefId,
+ found_kind: ty::ClosureKind,
+ kind: ty::ClosureKind,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let closure_span = self.tcx.def_span(closure_def_id);
+
+ let mut err = ClosureKindMismatch {
+ closure_span,
+ expected: kind,
+ found: found_kind,
+ cause_span: obligation.cause.span,
+ fn_once_label: None,
+ fn_mut_label: None,
+ };
+
+ // Additional context information explaining why the closure only implements
+ // a particular trait.
+ if let Some(typeck_results) = &self.typeck_results {
+ let hir_id = self.tcx.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.fn_once_label = Some(ClosureFnOnceLabel {
+ span: *span,
+ place: ty::place_to_string_for_capture(self.tcx, &place),
+ })
+ }
+ (ty::ClosureKind::FnMut, Some((span, place))) => {
+ err.fn_mut_label = Some(ClosureFnMutLabel {
+ span: *span,
+ place: ty::place_to_string_for_capture(self.tcx, &place),
+ })
+ }
+ _ => {}
+ }
+ }
+
+ self.tcx.sess.create_err(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_opaque_type_auto_trait_leakage(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ def_id: DefId,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let name = match self.tcx.opaque_type_origin(def_id.expect_local()) {
+ hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
+ "opaque type".to_string()
+ }
+ hir::OpaqueTyOrigin::TyAlias { .. } => {
+ format!("`{}`", self.tcx.def_path_debug_str(def_id))
+ }
+ };
+ let mut err = self.tcx.sess.struct_span_err(
+ obligation.cause.span,
+ format!("cannot check whether the hidden type of {name} satisfies auto traits"),
+ );
+ err.span_note(self.tcx.def_span(def_id), "opaque type is declared here");
+ match self.defining_use_anchor {
+ DefiningAnchor::Bubble | DefiningAnchor::Error => {}
+ DefiningAnchor::Bind(bind) => {
+ err.span_note(
+ self.tcx.def_ident_span(bind).unwrap_or_else(|| self.tcx.def_span(bind)),
+ "this item depends on auto traits of the hidden type, \
+ but may also be registering the hidden type. \
+ This is not supported right now. \
+ You can try moving the opaque type and the item that actually registers a hidden type into a new submodule".to_string(),
+ );
+ }
+ };
+
+ if let Some(diag) =
+ self.tcx.sess.diagnostic().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle)
+ {
+ diag.cancel();
+ }
+
+ err
+ }
+
+ 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::Coroutine(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().args.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().args.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().coroutine_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::Clause(ty::ClauseKind::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"
+ )
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 55b5604b1..fb9cf51b5 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,4 +1,5 @@
use crate::infer::{InferCtxt, TyOrConstInferVar};
+use rustc_data_structures::captures::Captures;
use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
@@ -68,7 +69,7 @@ pub struct PendingPredicateObligation<'tcx> {
// should mostly optimize for reading speed, while modifying is not as relevant.
//
// For whatever reason using a boxed slice is slower than using a `Vec` here.
- pub stalled_on: Vec<TyOrConstInferVar<'tcx>>,
+ pub stalled_on: Vec<TyOrConstInferVar>,
}
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -669,7 +670,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
&mut self,
obligation: &PredicateObligation<'tcx>,
trait_obligation: PolyTraitObligation<'tcx>,
- stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+ stalled_on: &mut Vec<TyOrConstInferVar>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let infcx = self.selcx.infcx;
if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
@@ -722,7 +723,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
&mut self,
obligation: &PredicateObligation<'tcx>,
project_obligation: PolyProjectionObligation<'tcx>,
- stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+ stalled_on: &mut Vec<TyOrConstInferVar>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let tcx = self.selcx.tcx();
@@ -775,7 +776,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
fn args_infer_vars<'a, 'tcx>(
selcx: &SelectionContext<'a, 'tcx>,
args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
-) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
+) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> {
selcx
.infcx
.resolve_vars_if_possible(args)
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 956f8e047..fff5510bb 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -41,18 +41,13 @@ use std::ops::ControlFlow;
pub(crate) use self::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
-pub use self::FulfillmentErrorCode::*;
-pub use self::ImplSource::*;
-pub use self::ObligationCauseCode::*;
-pub use self::SelectionError::*;
-
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
pub use self::coherence::{OrphanCheckErr, OverlapResult};
pub use self::engine::{ObligationCtxt, TraitEngineExt};
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
-pub use self::object_safety::MethodViolationCode;
+pub use self::object_safety::object_safety_violations_for_assoc_item;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::project::NormalizeExt;
pub use self::project::{normalize_inherent_projection, normalize_projection_type};
@@ -204,7 +199,7 @@ fn do_normalize_predicates<'tcx>(
let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
Ok(predicates) => predicates,
Err(errors) => {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
}
};
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 5823b4508..17c7f94ee 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -97,6 +97,10 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
/// object. Note that object-safe traits can have some
/// non-vtable-safe methods, so long as they require `Self: Sized` or
/// otherwise ensure that they cannot be used when `Self = Trait`.
+///
+/// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards
+/// compatibility, see <https://github.com/rust-lang/rust/issues/51443> and
+/// [`WHERE_CLAUSES_OBJECT_SAFETY`].
pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool {
debug_assert!(tcx.generics_of(trait_def_id).has_self);
debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method);
@@ -105,10 +109,9 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A
return false;
}
- match virtual_call_violation_for_method(tcx, trait_def_id, method) {
- None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
- Some(_) => false,
- }
+ virtual_call_violations_for_method(tcx, trait_def_id, method)
+ .iter()
+ .all(|v| matches!(v, MethodViolationCode::WhereClauseReferencesSelf))
}
fn object_safety_violations_for_trait(
@@ -119,7 +122,7 @@ fn object_safety_violations_for_trait(
let mut violations: Vec<_> = tcx
.associated_items(trait_def_id)
.in_definition_order()
- .filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item))
+ .flat_map(|&item| object_safety_violations_for_assoc_item(tcx, trait_def_id, item))
.collect();
// Check the trait itself.
@@ -357,49 +360,52 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
/// Returns `Some(_)` if this item makes the containing trait not object safe.
#[instrument(level = "debug", skip(tcx), ret)]
-fn object_safety_violation_for_assoc_item(
+pub fn object_safety_violations_for_assoc_item(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
item: ty::AssocItem,
-) -> Option<ObjectSafetyViolation> {
+) -> Vec<ObjectSafetyViolation> {
// Any item that has a `Self : Sized` requisite is otherwise
// exempt from the regulations.
if tcx.generics_require_sized_self(item.def_id) {
- return None;
+ return Vec::new();
}
match item.kind {
// Associated consts are never object safe, as they can't have `where` bounds yet at all,
// and associated const bounds in trait objects aren't a thing yet either.
ty::AssocKind::Const => {
- Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span))
+ vec![ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)]
}
- ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| {
- let node = tcx.hir().get_if_local(item.def_id);
- // Get an accurate span depending on the violation.
- let span = match (&v, node) {
- (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
- (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
- (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
- (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
- node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
- }
- _ => item.ident(tcx).span,
- };
+ ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
+ .into_iter()
+ .map(|v| {
+ let node = tcx.hir().get_if_local(item.def_id);
+ // Get an accurate span depending on the violation.
+ let span = match (&v, node) {
+ (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
+ (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
+ (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
+ (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
+ node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
+ }
+ _ => item.ident(tcx).span,
+ };
- ObjectSafetyViolation::Method(item.name, v, span)
- }),
+ ObjectSafetyViolation::Method(item.name, v, span)
+ })
+ .collect(),
// Associated types can only be object safe if they have `Self: Sized` bounds.
ty::AssocKind::Type => {
if !tcx.features().generic_associated_types_extended
&& !tcx.generics_of(item.def_id).params.is_empty()
&& !item.is_impl_trait_in_trait()
{
- Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span))
+ vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)]
} else {
// We will permit associated types if they are explicitly mentioned in the trait object.
// We can't check this here, as here we only check if it is guaranteed to not be possible.
- None
+ Vec::new()
}
}
}
@@ -409,11 +415,11 @@ fn object_safety_violation_for_assoc_item(
/// object; this does not necessarily imply that the enclosing trait
/// is not object safe, because the method might have a where clause
/// `Self:Sized`.
-fn virtual_call_violation_for_method<'tcx>(
+fn virtual_call_violations_for_method<'tcx>(
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
method: ty::AssocItem,
-) -> Option<MethodViolationCode> {
+) -> Vec<MethodViolationCode> {
let sig = tcx.fn_sig(method.def_id).instantiate_identity();
// The method's first parameter must be named `self`
@@ -438,9 +444,14 @@ fn virtual_call_violation_for_method<'tcx>(
} else {
None
};
- return Some(MethodViolationCode::StaticMethod(sugg));
+
+ // Not having `self` parameter messes up the later checks,
+ // so we need to return instead of pushing
+ return vec![MethodViolationCode::StaticMethod(sugg)];
}
+ let mut errors = Vec::new();
+
for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) {
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) {
let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
@@ -452,20 +463,20 @@ fn virtual_call_violation_for_method<'tcx>(
} else {
None
};
- return Some(MethodViolationCode::ReferencesSelfInput(span));
+ errors.push(MethodViolationCode::ReferencesSelfInput(span));
}
}
if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
- return Some(MethodViolationCode::ReferencesSelfOutput);
+ errors.push(MethodViolationCode::ReferencesSelfOutput);
}
if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
- return Some(code);
+ errors.push(code);
}
// We can't monomorphize things like `fn foo<A>(...)`.
let own_counts = tcx.generics_of(method.def_id).own_counts();
- if own_counts.types + own_counts.consts != 0 {
- return Some(MethodViolationCode::Generic);
+ if own_counts.types > 0 || own_counts.consts > 0 {
+ errors.push(MethodViolationCode::Generic);
}
let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
@@ -485,7 +496,7 @@ fn virtual_call_violation_for_method<'tcx>(
} else {
None
};
- return Some(MethodViolationCode::UndispatchableReceiver(span));
+ errors.push(MethodViolationCode::UndispatchableReceiver(span));
} else {
// Do sanity check to make sure the receiver actually has the layout of a pointer.
@@ -584,20 +595,19 @@ fn virtual_call_violation_for_method<'tcx>(
// would already have reported an error at the definition of the
// auto trait.
if pred_trait_ref.args.len() != 1 {
- tcx.sess.diagnostic().delay_span_bug(
- span,
- "auto traits cannot have generic parameters",
- );
+ tcx.sess
+ .diagnostic()
+ .delay_span_bug(span, "auto traits cannot have generic parameters");
}
return false;
}
contains_illegal_self_type_reference(tcx, trait_def_id, pred)
}) {
- return Some(MethodViolationCode::WhereClauseReferencesSelf);
+ errors.push(MethodViolationCode::WhereClauseReferencesSelf);
}
- None
+ errors
}
/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
@@ -710,7 +720,6 @@ fn object_ty_for_trait<'tcx>(
// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
// `self: Wrapper<Self>`.
-#[allow(dead_code)]
fn receiver_is_dispatchable<'tcx>(
tcx: TyCtxt<'tcx>,
method: ty::AssocItem,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index f7b4794db..471d10dbd 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -783,7 +783,7 @@ pub struct BoundVarReplacer<'me, 'tcx> {
// the `var` (but we *could* bring that into scope if we were to track them as we pass them).
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
- mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+ mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
// The current depth relative to *this* folding, *not* the entire normalization. In other words,
// the depth of binders we've passed here.
current_index: ty::DebruijnIndex,
@@ -843,11 +843,11 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
T,
BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
BTreeMap<ty::PlaceholderType, ty::BoundTy>,
- BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+ BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
) {
let mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion> = BTreeMap::new();
let mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy> = BTreeMap::new();
- let mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar> = BTreeMap::new();
+ let mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar> = BTreeMap::new();
let mut replacer = BoundVarReplacer {
infcx,
@@ -898,7 +898,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
if debruijn.as_usize() + 1
> self.current_index.as_usize() + self.universe_indices.len() =>
{
- bug!("Bound vars outside of `self.universe_indices`");
+ bug!(
+ "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
+ self.universe_indices
+ );
}
ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
@@ -916,7 +919,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
if debruijn.as_usize() + 1
> self.current_index.as_usize() + self.universe_indices.len() =>
{
- bug!("Bound vars outside of `self.universe_indices`");
+ bug!(
+ "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
+ self.universe_indices
+ );
}
ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
@@ -935,7 +941,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
if debruijn.as_usize() + 1
> self.current_index.as_usize() + self.universe_indices.len() =>
{
- bug!("Bound vars outside of `self.universe_indices`");
+ bug!(
+ "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
+ self.universe_indices
+ );
}
ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
@@ -957,7 +966,7 @@ pub struct PlaceholderReplacer<'me, 'tcx> {
infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
- mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+ mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
universe_indices: &'me [Option<ty::UniverseIndex>],
current_index: ty::DebruijnIndex,
}
@@ -967,7 +976,7 @@ impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
infcx: &'me InferCtxt<'tcx>,
mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
- mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+ mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
universe_indices: &'me [Option<ty::UniverseIndex>],
value: T,
) -> T {
@@ -1644,7 +1653,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
let env_predicates = data
.projection_bounds()
.filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
- .map(|p| ty::Clause::from_projection_clause(tcx, p.with_self_ty(tcx, object_ty)));
+ .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
assemble_candidates_from_predicates(
selcx,
@@ -1789,7 +1798,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let lang_items = selcx.tcx().lang_items();
- if [lang_items.gen_trait(), lang_items.future_trait()].contains(&Some(trait_ref.def_id))
+ if [lang_items.coroutine_trait(), lang_items.future_trait(), lang_items.iterator_trait()].contains(&Some(trait_ref.def_id))
|| selcx.tcx().fn_trait_kind_from_def_id(trait_ref.def_id).is_some()
{
true
@@ -1811,8 +1820,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::FnPtr(..)
| ty::Dynamic(..)
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(..)
// Integers and floats always have `u8` as their discriminant.
@@ -1860,8 +1869,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::FnPtr(..)
| ty::Dynamic(..)
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Never
// Extern types have unit metadata, according to RFC 2850
| ty::Foreign(_)
@@ -2002,10 +2011,12 @@ fn confirm_select_candidate<'cx, 'tcx>(
ImplSource::Builtin(BuiltinImplSource::Misc, data) => {
let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx());
let lang_items = selcx.tcx().lang_items();
- if lang_items.gen_trait() == Some(trait_def_id) {
- confirm_generator_candidate(selcx, obligation, data)
+ if lang_items.coroutine_trait() == Some(trait_def_id) {
+ confirm_coroutine_candidate(selcx, obligation, data)
} else if lang_items.future_trait() == Some(trait_def_id) {
confirm_future_candidate(selcx, obligation, data)
+ } else if lang_items.iterator_trait() == Some(trait_def_id) {
+ confirm_iterator_candidate(selcx, obligation, data)
} else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() {
if obligation.predicate.self_ty().is_closure() {
confirm_closure_candidate(selcx, obligation, data)
@@ -2030,36 +2041,36 @@ fn confirm_select_candidate<'cx, 'tcx>(
}
}
-fn confirm_generator_candidate<'cx, 'tcx>(
+fn confirm_coroutine_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
- let ty::Generator(_, args, _) =
+ let ty::Coroutine(_, args, _) =
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
else {
unreachable!()
};
- let gen_sig = args.as_generator().poly_sig();
- let Normalized { value: gen_sig, obligations } = normalize_with_depth(
+ let coroutine_sig = args.as_coroutine().poly_sig();
+ let Normalized { value: coroutine_sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
- gen_sig,
+ coroutine_sig,
);
- debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate");
+ debug!(?obligation, ?coroutine_sig, ?obligations, "confirm_coroutine_candidate");
let tcx = selcx.tcx();
- let gen_def_id = tcx.require_lang_item(LangItem::Generator, None);
+ let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None);
- let predicate = super::util::generator_trait_ref_and_outputs(
+ let predicate = super::util::coroutine_trait_ref_and_outputs(
tcx,
- gen_def_id,
+ coroutine_def_id,
obligation.predicate.self_ty(),
- gen_sig,
+ coroutine_sig,
)
.map_bound(|(trait_ref, yield_ty, return_ty)| {
let name = tcx.associated_item(obligation.predicate.def_id).name;
@@ -2072,7 +2083,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
};
ty::ProjectionPredicate {
- projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.args),
+ projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
term: ty.into(),
}
});
@@ -2087,21 +2098,21 @@ fn confirm_future_candidate<'cx, 'tcx>(
obligation: &ProjectionTyObligation<'tcx>,
nested: Vec<PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
- let ty::Generator(_, args, _) =
+ let ty::Coroutine(_, args, _) =
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
else {
unreachable!()
};
- let gen_sig = args.as_generator().poly_sig();
- let Normalized { value: gen_sig, obligations } = normalize_with_depth(
+ let coroutine_sig = args.as_coroutine().poly_sig();
+ let Normalized { value: coroutine_sig, obligations } = normalize_with_depth(
selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
- gen_sig,
+ coroutine_sig,
);
- debug!(?obligation, ?gen_sig, ?obligations, "confirm_future_candidate");
+ debug!(?obligation, ?coroutine_sig, ?obligations, "confirm_future_candidate");
let tcx = selcx.tcx();
let fut_def_id = tcx.require_lang_item(LangItem::Future, None);
@@ -2110,13 +2121,13 @@ fn confirm_future_candidate<'cx, 'tcx>(
tcx,
fut_def_id,
obligation.predicate.self_ty(),
- gen_sig,
+ coroutine_sig,
)
.map_bound(|(trait_ref, return_ty)| {
debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
ty::ProjectionPredicate {
- projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.args),
+ projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
term: return_ty.into(),
}
});
@@ -2126,6 +2137,50 @@ fn confirm_future_candidate<'cx, 'tcx>(
.with_addl_obligations(obligations)
}
+fn confirm_iterator_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ nested: Vec<PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+ let ty::Coroutine(_, args, _) =
+ selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
+ else {
+ unreachable!()
+ };
+ let gen_sig = args.as_coroutine().poly_sig();
+ let Normalized { value: gen_sig, obligations } = normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ gen_sig,
+ );
+
+ debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate");
+
+ let tcx = selcx.tcx();
+ let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None);
+
+ let predicate = super::util::iterator_trait_ref_and_outputs(
+ tcx,
+ iter_def_id,
+ obligation.predicate.self_ty(),
+ gen_sig,
+ )
+ .map_bound(|(trait_ref, yield_ty)| {
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
+
+ ty::ProjectionPredicate {
+ projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+ term: yield_ty.into(),
+ }
+ });
+
+ confirm_param_env_candidate(selcx, obligation, predicate, false)
+ .with_addl_obligations(nested)
+ .with_addl_obligations(obligations)
+}
+
fn confirm_builtin_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
@@ -2172,7 +2227,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
};
let predicate =
- ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(item_def_id, args), term };
+ ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(tcx, item_def_id, args), term };
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
.with_addl_obligations(obligations)
@@ -2245,7 +2300,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
flag,
)
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
- projection_ty: tcx.mk_alias_ty(fn_once_output_def_id, trait_ref.args),
+ projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args),
term: ret_type.into(),
});
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 620b992ee..f8efa6a1f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -5,7 +5,7 @@ use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
-use rustc_span::source_map::{Span, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
/// This returns true if the type `ty` is "trivial" for
/// dropck-outlives -- that is, if it doesn't require any types to
@@ -35,7 +35,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::Char
- | ty::GeneratorWitness(..)
+ | ty::CoroutineWitness(..)
| ty::RawPtr(_)
| ty::Ref(..)
| ty::Str
@@ -72,7 +72,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::Placeholder(..)
| ty::Infer(_)
| ty::Bound(..)
- | ty::Generator(..) => false,
+ | ty::Coroutine(..) => false,
}
}
@@ -216,7 +216,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(_)
- | ty::GeneratorWitness(..) => {
+ | ty::CoroutineWitness(..) => {
// these types never have a destructor
}
@@ -261,22 +261,22 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
})?
}
- ty::Generator(_, args, _movability) => {
+ ty::Coroutine(_, args, _movability) => {
// rust-lang/rust#49918: types can be constructed, stored
- // in the interior, and sit idle when generator yields
+ // in the interior, and sit idle when coroutine yields
// (and is subsequently dropped).
//
// It would be nice to descend into interior of a
- // generator to determine what effects dropping it might
+ // coroutine to determine what effects dropping it might
// have (by looking at any drop effects associated with
// its interior).
//
// However, the interior's representation uses things like
- // GeneratorWitness that explicitly assume they are not
+ // CoroutineWitness that explicitly assume they are not
// traversed in such a manner. So instead, we will
- // simplify things for now by treating all generators as
+ // simplify things for now by treating all coroutines as
// if they were like trait objects, where its upvars must
- // all be alive for the generator's (potential)
+ // all be alive for the coroutine's (potential)
// destructor.
//
// In particular, skipping over `_interior` is safe
@@ -284,13 +284,13 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
// only take place through references with lifetimes
// derived from lifetimes attached to the upvars and resume
// argument, and we *do* incorporate those here.
- let args = args.as_generator();
+ let args = args.as_coroutine();
if !args.is_valid() {
// By the time this code runs, all type variables ought to
// be fully resolved.
tcx.sess.delay_span_bug(
span,
- format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
+ format!("upvar_tys for coroutine not found. Expected capture information for coroutine {ty}",),
);
return Err(NoSolution);
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index f785211c5..2e31b560b 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -230,17 +230,14 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
Reveal::All => {
let args = data.args.try_fold_with(self)?;
let recursion_limit = self.interner().recursion_limit();
+
if !recursion_limit.value_within_limit(self.anon_depth) {
- // A closure or generator may have itself as in its upvars.
- // This should be checked handled by the recursion check for opaque
- // types, but we may end up here before that check can happen.
- // In that case, we delay a bug to mark the trip, and continue without
- // revealing the opaque.
- self.infcx
+ let guar = self
+ .infcx
.err_ctxt()
.build_overflow_error(&ty, self.cause.span, true)
.delay_as_bug();
- return ty.try_super_fold_with(self);
+ return Ok(Ty::new_error(self.interner(), guar));
}
let generic_ty = self.interner().type_of(data.def_id);
@@ -293,7 +290,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
_ => unreachable!(),
}?;
// We don't expect ambiguity.
- if result.is_ambiguous() {
+ if !result.value.is_proven() {
// Rustdoc normalizes possibly not well-formed types, so only
// treat this as a bug if we're not in rustdoc.
if !tcx.sess.opts.actually_rustdoc {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index c99e018e9..c81bc5790 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -6,8 +6,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::{TyCtxt, TypeFoldable};
-use rustc_span::source_map::DUMMY_SP;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use std::fmt;
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index e415d7047..e345fc39e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -10,7 +10,7 @@ use rustc_middle::infer::canonical::CanonicalQueryResponse;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::source_map::DUMMY_SP;
+use rustc_span::DUMMY_SP;
use smallvec::{smallvec, SmallVec};
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index bead8758a..f4b6d3bcf 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -52,8 +52,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
- // The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl.
- // There are no compiler built-in rules for this.
+ // Negative trait predicates have different rules than positive trait predicates.
if obligation.polarity() == ty::ImplPolarity::Negative {
self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
self.assemble_candidates_from_impls(obligation, &mut candidates);
@@ -110,10 +109,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
}
- if lang_items.gen_trait() == Some(def_id) {
- self.assemble_generator_candidates(obligation, &mut candidates);
+ if lang_items.coroutine_trait() == Some(def_id) {
+ self.assemble_coroutine_candidates(obligation, &mut candidates);
} else if lang_items.future_trait() == Some(def_id) {
self.assemble_future_candidates(obligation, &mut candidates);
+ } else if lang_items.iterator_trait() == Some(def_id) {
+ self.assemble_iterator_candidates(obligation, &mut candidates);
}
self.assemble_closure_candidates(obligation, &mut candidates);
@@ -201,25 +202,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(())
}
- fn assemble_generator_candidates(
+ fn assemble_coroutine_candidates(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
- // Okay to skip binder because the args on generator types never
+ // Okay to skip binder because the args on coroutine types never
// touch bound regions, they just capture the in-scope
// type/region parameters.
let self_ty = obligation.self_ty().skip_binder();
match self_ty.kind() {
- // async constructs get lowered to a special kind of generator that
- // should *not* `impl Generator`.
- ty::Generator(did, ..) if !self.tcx().generator_is_async(*did) => {
- debug!(?self_ty, ?obligation, "assemble_generator_candidates",);
+ // `async`/`gen` constructs get lowered to a special kind of coroutine that
+ // should *not* `impl Coroutine`.
+ ty::Coroutine(did, ..) if self.tcx().is_general_coroutine(*did) => {
+ debug!(?self_ty, ?obligation, "assemble_coroutine_candidates",);
- candidates.vec.push(GeneratorCandidate);
+ candidates.vec.push(CoroutineCandidate);
}
ty::Infer(ty::TyVar(_)) => {
- debug!("assemble_generator_candidates: ambiguous self-type");
+ debug!("assemble_coroutine_candidates: ambiguous self-type");
candidates.ambiguous = true;
}
_ => {}
@@ -232,10 +233,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates: &mut SelectionCandidateSet<'tcx>,
) {
let self_ty = obligation.self_ty().skip_binder();
- if let ty::Generator(did, ..) = self_ty.kind() {
- // async constructs get lowered to a special kind of generator that
+ if let ty::Coroutine(did, ..) = self_ty.kind() {
+ // async constructs get lowered to a special kind of coroutine that
// should directly `impl Future`.
- if self.tcx().generator_is_async(*did) {
+ if self.tcx().coroutine_is_async(*did) {
debug!(?self_ty, ?obligation, "assemble_future_candidates",);
candidates.vec.push(FutureCandidate);
@@ -243,6 +244,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}
+ fn assemble_iterator_candidates(
+ &mut self,
+ obligation: &PolyTraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ let self_ty = obligation.self_ty().skip_binder();
+ if let ty::Coroutine(did, ..) = self_ty.kind() {
+ // gen constructs get lowered to a special kind of coroutine that
+ // should directly `impl Iterator`.
+ if self.tcx().coroutine_is_gen(*did) {
+ debug!(?self_ty, ?obligation, "assemble_iterator_candidates",);
+
+ candidates.vec.push(IteratorCandidate);
+ }
+ }
+ }
+
/// Checks for the artificial impl that the compiler will create for an obligation like `X :
/// FnMut<..>` where `X` is a closure type.
///
@@ -435,8 +453,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::RawPtr(_)
| ty::Ref(_, _, _)
| ty::Closure(_, _)
- | ty::Generator(_, _, _)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(_, _, _)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::Error(_) => return true,
@@ -492,7 +510,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// this trait and type.
}
ty::Param(..)
- | ty::Alias(ty::Projection | ty::Inherent, ..)
+ | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
| ty::Placeholder(..)
| ty::Bound(..) => {
// In these cases, we don't know what the actual
@@ -513,16 +531,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// The auto impl might apply; we don't know.
candidates.ambiguous = true;
}
- ty::Generator(_, _, movability)
+ ty::Coroutine(_, _, movability)
if self.tcx().lang_items().unpin_trait() == Some(def_id) =>
{
match movability {
hir::Movability::Static => {
- // Immovable generators are never `Unpin`, so
+ // Immovable coroutines are never `Unpin`, so
// suppress the normal auto-impl candidate for it.
}
hir::Movability::Movable => {
- // Movable generators are always `Unpin`, so add an
+ // Movable coroutines are always `Unpin`, so add an
// unconditional builtin candidate.
candidates.vec.push(BuiltinCandidate { has_nested: false });
}
@@ -536,20 +554,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);
}
- ty::Alias(_, _)
- if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) =>
- {
- // We do not generate an auto impl candidate for `impl Trait`s which already
- // reference our auto trait.
- //
- // For example during candidate assembly for `impl Send: Send`, we don't have
- // to look at the constituent types for this opaque types to figure out that this
- // trivially holds.
- //
- // Note that this is only sound as projection candidates of opaque types
- // are always applicable for auto traits.
+ ty::Alias(ty::Opaque, _) => {
+ if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) {
+ // We do not generate an auto impl candidate for `impl Trait`s which already
+ // reference our auto trait.
+ //
+ // For example during candidate assembly for `impl Send: Send`, we don't have
+ // to look at the constituent types for this opaque types to figure out that this
+ // trivially holds.
+ //
+ // Note that this is only sound as projection candidates of opaque types
+ // are always applicable for auto traits.
+ } else if self.infcx.intercrate {
+ // We do not emit auto trait candidates for opaque types in coherence.
+ // Doing so can result in weird dependency cycles.
+ candidates.ambiguous = true;
+ } else {
+ candidates.vec.push(AutoImplCandidate)
+ }
}
- ty::Alias(_, _) => candidates.vec.push(AutoImplCandidate),
ty::Bool
| ty::Char
@@ -565,10 +588,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::Closure(_, _)
- | ty::Generator(..)
+ | ty::Coroutine(..)
| ty::Never
| ty::Tuple(_)
- | ty::GeneratorWitness(..) => {
+ | ty::CoroutineWitness(..) => {
// Only consider auto impls if there are no manual impls for the root of `self_ty`.
//
// For example, we only consider auto candidates for `&i32: Auto` if no explicit impl
@@ -605,15 +628,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
self.infcx.probe(|_snapshot| {
- if obligation.has_non_region_late_bound() {
- return;
- }
+ let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
+ let placeholder_trait_predicate =
+ self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate);
- // The code below doesn't care about regions, and the
- // self-ty here doesn't escape this probe, so just erase
- // any LBR.
- let self_ty = self.tcx().erase_late_bound_regions(obligation.self_ty());
- let poly_trait_ref = match self_ty.kind() {
+ let self_ty = placeholder_trait_predicate.self_ty();
+ let principal_trait_ref = match self_ty.kind() {
ty::Dynamic(ref data, ..) => {
if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
debug!(
@@ -645,18 +665,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
_ => return,
};
- debug!(?poly_trait_ref, "assemble_candidates_from_object_ty");
-
- let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
- let placeholder_trait_predicate =
- self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate);
+ debug!(?principal_trait_ref, "assemble_candidates_from_object_ty");
// Count only those upcast versions that match the trait-ref
// we are looking for. Specifically, do not only check for the
// correct trait, but also the correct type parameters.
// For example, we may be trying to upcast `Foo` to `Bar<i32>`,
// but `Foo` is declared as `trait Foo: Bar<u32>`.
- let candidate_supertraits = util::supertraits(self.tcx(), poly_trait_ref)
+ let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref)
.enumerate()
.filter(|&(_, upcast_trait_ref)| {
self.infcx.probe(|_| {
@@ -699,7 +715,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let ty = traits::normalize_projection_type(
self,
param_env,
- tcx.mk_alias_ty(tcx.lang_items().deref_target()?, trait_ref.args),
+ ty::AliasTy::new(tcx, tcx.lang_items().deref_target()?, trait_ref.args),
cause.clone(),
0,
// We're *intentionally* throwing these away,
@@ -942,9 +958,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Array(..)
| ty::Slice(_)
| ty::Closure(..)
- | ty::Generator(..)
+ | ty::Coroutine(..)
| ty::Tuple(_)
- | ty::GeneratorWitness(..) => {
+ | ty::CoroutineWitness(..) => {
// These are built-in, and cannot have a custom `impl const Destruct`.
candidates.vec.push(ConstDestructCandidate(None));
}
@@ -1016,8 +1032,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
- | ty::Generator(_, _, _)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(_, _, _)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Alias(..)
| ty::Param(_)
@@ -1059,6 +1075,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates: &mut SelectionCandidateSet<'tcx>,
) {
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+
match self_ty.skip_binder().kind() {
ty::FnPtr(_) => candidates.vec.push(BuiltinCandidate { has_nested: false }),
ty::Bool
@@ -1077,8 +1094,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Placeholder(..)
| ty::Dynamic(..)
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(..)
| ty::Alias(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 08ee9c73b..4bfa341e3 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -83,9 +83,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
}
- GeneratorCandidate => {
- let vtable_generator = self.confirm_generator_candidate(obligation)?;
- ImplSource::Builtin(BuiltinImplSource::Misc, vtable_generator)
+ CoroutineCandidate => {
+ let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?;
+ ImplSource::Builtin(BuiltinImplSource::Misc, vtable_coroutine)
}
FutureCandidate => {
@@ -93,6 +93,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_future)
}
+ IteratorCandidate => {
+ let vtable_iterator = self.confirm_iterator_candidate(obligation)?;
+ ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
+ }
+
FnPointerCandidate { is_const } => {
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
ImplSource::Builtin(BuiltinImplSource::Misc, data)
@@ -711,23 +716,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
trait_obligations
}
- fn confirm_generator_candidate(
+ fn confirm_coroutine_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
- // Okay to skip binder because the args on generator types never
+ // Okay to skip binder because the args on coroutine types never
// touch bound regions, they just capture the in-scope
// type/region parameters.
let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
- let ty::Generator(generator_def_id, args, _) = *self_ty.kind() else {
+ let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
bug!("closure candidate for non-closure {:?}", obligation);
};
- debug!(?obligation, ?generator_def_id, ?args, "confirm_generator_candidate");
+ debug!(?obligation, ?coroutine_def_id, ?args, "confirm_coroutine_candidate");
- let gen_sig = args.as_generator().poly_sig();
+ let coroutine_sig = args.as_coroutine().poly_sig();
- // NOTE: The self-type is a generator type and hence is
+ // NOTE: The self-type is a coroutine type and hence is
// in fact unparameterized (or at least does not reference any
// regions bound in the obligation).
let self_ty = obligation
@@ -736,16 +741,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.no_bound_vars()
.expect("unboxed closure type should not capture bound vars from the predicate");
- let trait_ref = super::util::generator_trait_ref_and_outputs(
+ let trait_ref = super::util::coroutine_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
self_ty,
- gen_sig,
+ coroutine_sig,
)
.map_bound(|(trait_ref, ..)| trait_ref);
let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
- debug!(?trait_ref, ?nested, "generator candidate obligations");
+ debug!(?trait_ref, ?nested, "coroutine candidate obligations");
Ok(nested)
}
@@ -754,23 +759,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self,
obligation: &PolyTraitObligation<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
- // Okay to skip binder because the args on generator types never
+ // Okay to skip binder because the args on coroutine types never
// touch bound regions, they just capture the in-scope
// type/region parameters.
let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
- let ty::Generator(generator_def_id, args, _) = *self_ty.kind() else {
+ let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
bug!("closure candidate for non-closure {:?}", obligation);
};
- debug!(?obligation, ?generator_def_id, ?args, "confirm_future_candidate");
+ debug!(?obligation, ?coroutine_def_id, ?args, "confirm_future_candidate");
- let gen_sig = args.as_generator().poly_sig();
+ let coroutine_sig = args.as_coroutine().poly_sig();
let trait_ref = super::util::future_trait_ref_and_outputs(
self.tcx(),
obligation.predicate.def_id(),
obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(),
- gen_sig,
+ coroutine_sig,
)
.map_bound(|(trait_ref, ..)| trait_ref);
@@ -780,6 +785,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(nested)
}
+ fn confirm_iterator_candidate(
+ &mut self,
+ obligation: &PolyTraitObligation<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ // Okay to skip binder because the args on coroutine types never
+ // touch bound regions, they just capture the in-scope
+ // type/region parameters.
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+ let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
+ bug!("closure candidate for non-closure {:?}", obligation);
+ };
+
+ debug!(?obligation, ?coroutine_def_id, ?args, "confirm_iterator_candidate");
+
+ let gen_sig = args.as_coroutine().poly_sig();
+
+ let trait_ref = super::util::iterator_trait_ref_and_outputs(
+ self.tcx(),
+ obligation.predicate.def_id(),
+ obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(),
+ gen_sig,
+ )
+ .map_bound(|(trait_ref, ..)| trait_ref);
+
+ let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ debug!(?trait_ref, ?nested, "iterator candidate obligations");
+
+ Ok(nested)
+ }
+
#[instrument(skip(self), level = "debug")]
fn confirm_closure_candidate(
&mut self,
@@ -1234,13 +1269,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::Closure(_, args) => {
stack.push(args.as_closure().tupled_upvars_ty());
}
- ty::Generator(_, args, _) => {
- let generator = args.as_generator();
- stack.extend([generator.tupled_upvars_ty(), generator.witness()]);
+ ty::Coroutine(_, args, _) => {
+ let coroutine = args.as_coroutine();
+ stack.extend([coroutine.tupled_upvars_ty(), coroutine.witness()]);
}
- ty::GeneratorWitness(def_id, args) => {
+ ty::CoroutineWitness(def_id, args) => {
let tcx = self.tcx();
- stack.extend(tcx.generator_hidden_types(def_id).map(|bty| {
+ stack.extend(tcx.coroutine_hidden_types(def_id).map(|bty| {
let ty = bty.instantiate(tcx, args);
debug_assert!(!ty.has_late_bound_regions());
ty
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index ec46a6769..08208cc60 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -38,6 +38,7 @@ use rustc_infer::traits::TraitObligation;
use rustc_middle::dep_graph::dep_kinds;
use rustc_middle::dep_graph::DepNodeIndex;
use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::ty::_match::MatchAgainstFreshVars;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::relate::TypeRelation;
@@ -858,7 +859,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
subobligations,
);
if let Ok(eval_rslt) = res
- && (eval_rslt == EvaluatedToOk || eval_rslt == EvaluatedToOkModuloRegions)
+ && (eval_rslt == EvaluatedToOk
+ || eval_rslt == EvaluatedToOkModuloRegions)
&& let Some(key) =
ProjectionCacheKey::from_poly_projection_predicate(
self, data,
@@ -1884,8 +1886,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
ImplCandidate(..)
| AutoImplCandidate
| ClosureCandidate { .. }
- | GeneratorCandidate
+ | CoroutineCandidate
| FutureCandidate
+ | IteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1912,8 +1915,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
ImplCandidate(_)
| AutoImplCandidate
| ClosureCandidate { .. }
- | GeneratorCandidate
+ | CoroutineCandidate
| FutureCandidate
+ | IteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1946,8 +1950,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
ImplCandidate(..)
| AutoImplCandidate
| ClosureCandidate { .. }
- | GeneratorCandidate
+ | CoroutineCandidate
| FutureCandidate
+ | IteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -1960,8 +1965,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
ImplCandidate(..)
| AutoImplCandidate
| ClosureCandidate { .. }
- | GeneratorCandidate
+ | CoroutineCandidate
| FutureCandidate
+ | IteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -2066,8 +2072,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
(
ImplCandidate(_)
| ClosureCandidate { .. }
- | GeneratorCandidate
+ | CoroutineCandidate
| FutureCandidate
+ | IteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -2076,8 +2083,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| TraitAliasCandidate,
ImplCandidate(_)
| ClosureCandidate { .. }
- | GeneratorCandidate
+ | CoroutineCandidate
| FutureCandidate
+ | IteratorCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
@@ -2110,8 +2118,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::RawPtr(..)
| ty::Char
| ty::Ref(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Array(..)
| ty::Closure(..)
| ty::Never
@@ -2178,7 +2186,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
ty::Dynamic(..)
| ty::Str
| ty::Slice(..)
- | ty::Generator(_, _, hir::Movability::Static)
+ | ty::Coroutine(_, _, hir::Movability::Static)
| ty::Foreign(..)
| ty::Ref(_, _, hir::Mutability::Mut) => None,
@@ -2187,21 +2195,21 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
Where(obligation.predicate.rebind(tys.iter().collect()))
}
- ty::Generator(_, args, hir::Movability::Movable) => {
- if self.tcx().features().generator_clone {
+ ty::Coroutine(_, args, hir::Movability::Movable) => {
+ if self.tcx().features().coroutine_clone {
let resolved_upvars =
- self.infcx.shallow_resolve(args.as_generator().tupled_upvars_ty());
+ self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
let resolved_witness =
- self.infcx.shallow_resolve(args.as_generator().witness());
+ self.infcx.shallow_resolve(args.as_coroutine().witness());
if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
// Not yet resolved.
Ambiguous
} else {
let all = args
- .as_generator()
+ .as_coroutine()
.upvar_tys()
.iter()
- .chain([args.as_generator().witness()])
+ .chain([args.as_coroutine().witness()])
.collect::<Vec<_>>();
Where(obligation.predicate.rebind(all))
}
@@ -2210,8 +2218,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
}
}
- ty::GeneratorWitness(def_id, ref args) => {
- let hidden_types = bind_generator_hidden_types_above(
+ ty::CoroutineWitness(def_id, ref args) => {
+ let hidden_types = bind_coroutine_hidden_types_above(
self.infcx,
def_id,
args,
@@ -2309,14 +2317,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
t.rebind(vec![ty])
}
- ty::Generator(_, ref args, _) => {
- let ty = self.infcx.shallow_resolve(args.as_generator().tupled_upvars_ty());
- let witness = args.as_generator().witness();
+ ty::Coroutine(_, ref args, _) => {
+ let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
+ let witness = args.as_coroutine().witness();
t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
}
- ty::GeneratorWitness(def_id, ref args) => {
- bind_generator_hidden_types_above(self.infcx, def_id, args, t.bound_vars())
+ ty::CoroutineWitness(def_id, ref args) => {
+ bind_coroutine_hidden_types_above(self.infcx, def_id, args, t.bound_vars())
}
// For `PhantomData<T>`, we pass `T`.
@@ -2381,12 +2389,21 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
)
});
- let obligation = Obligation::new(
- self.tcx(),
- cause.clone(),
- param_env,
- ty::TraitRef::new(self.tcx(), trait_def_id, [normalized_ty]),
- );
+ let tcx = self.tcx();
+ let trait_ref = if tcx.generics_of(trait_def_id).params.len() == 1 {
+ ty::TraitRef::new(tcx, trait_def_id, [normalized_ty])
+ } else {
+ // If this is an ill-formed auto/built-in trait, then synthesize
+ // new error args for the missing generics.
+ let err_args = ty::GenericArgs::extend_with_error(
+ tcx,
+ trait_def_id,
+ &[normalized_ty.into()],
+ );
+ ty::TraitRef::new(tcx, trait_def_id, err_args)
+ };
+
+ let obligation = Obligation::new(self.tcx(), cause.clone(), param_env, trait_ref);
obligations.push(obligation);
obligations
})
@@ -2623,7 +2640,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
current: ty::PolyTraitPredicate<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
- let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
+ let mut matcher = MatchAgainstFreshVars::new(self.tcx(), param_env);
matcher.relate(previous, current).is_ok()
}
@@ -3052,12 +3069,12 @@ pub enum ProjectionMatchesProjection {
No,
}
-/// Replace all regions inside the generator interior with late bound regions.
+/// Replace all regions inside the coroutine interior with late bound regions.
/// Note that each region slot in the types gets a new fresh late bound region, which means that
/// none of the regions inside relate to any other, even if typeck had previously found constraints
/// that would cause them to be related.
#[instrument(level = "trace", skip(infcx), ret)]
-fn bind_generator_hidden_types_above<'tcx>(
+fn bind_coroutine_hidden_types_above<'tcx>(
infcx: &InferCtxt<'tcx>,
def_id: DefId,
args: ty::GenericArgsRef<'tcx>,
@@ -3072,7 +3089,7 @@ fn bind_generator_hidden_types_above<'tcx>(
let mut counter = num_bound_variables;
let hidden_types: Vec<_> = tcx
- .generator_hidden_types(def_id)
+ .coroutine_hidden_types(def_id)
// Deduplicate tys to avoid repeated work.
.filter(|bty| seen_tys.insert(*bty))
.map(|mut bty| {
@@ -3096,9 +3113,6 @@ fn bind_generator_hidden_types_above<'tcx>(
bty.instantiate(tcx, args)
})
.collect();
- if considering_regions {
- debug_assert!(!hidden_types.has_erased_regions());
- }
let bound_vars =
tcx.mk_bound_variable_kinds_from_iter(bound_vars.iter().chain(
(num_bound_variables..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon)),
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index fc9b42436..5960415a8 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -79,7 +79,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
ty::Closure(..) => {
return ControlFlow::Break(ty);
}
- ty::Generator(..) | ty::GeneratorWitness(..) => {
+ ty::Coroutine(..) | ty::CoroutineWitness(..) => {
return ControlFlow::Break(ty);
}
ty::FnDef(..) => {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index a76272e9d..bbde0c827 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable
use rustc_span::Span;
use smallvec::SmallVec;
-pub use rustc_infer::traits::{self, util::*};
+pub use rustc_infer::traits::util::*;
///////////////////////////////////////////////////////////////////////////
// `TraitAliasExpander` iterator
@@ -275,7 +275,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
sig.map_bound(|sig| (trait_ref, sig.output()))
}
-pub fn generator_trait_ref_and_outputs<'tcx>(
+pub fn coroutine_trait_ref_and_outputs<'tcx>(
tcx: TyCtxt<'tcx>,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
@@ -297,6 +297,17 @@ pub fn future_trait_ref_and_outputs<'tcx>(
sig.map_bound(|sig| (trait_ref, sig.return_ty))
}
+pub fn iterator_trait_ref_and_outputs<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ iterator_def_id: DefId,
+ self_ty: Ty<'tcx>,
+ sig: ty::PolyGenSig<'tcx>,
+) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
+ assert!(!self_ty.has_escaping_bound_vars());
+ let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]);
+ sig.map_bound(|sig| (trait_ref, sig.yield_ty))
+}
+
pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
assoc_item.defaultness(tcx).is_final()
&& tcx.defaultness(assoc_item.container_id(tcx)).is_final()
@@ -326,7 +337,8 @@ pub fn check_args_compatible<'tcx>(
if let Some(parent) = generics.parent
&& let parent_generics = tcx.generics_of(parent)
- && !check_args_compatible_inner(tcx, parent_generics, parent_args) {
+ && !check_args_compatible_inner(tcx, parent_generics, parent_args)
+ {
return false;
}
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index e41073937..f23c100a6 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -316,7 +316,7 @@ fn vtable_entries<'tcx>(
dump_vtable_entries(tcx, sp, trait_ref, &entries);
}
- tcx.arena.alloc_from_iter(entries.into_iter())
+ tcx.arena.alloc_from_iter(entries)
}
/// Find slot base for trait methods within vtable entries of another trait
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index b04008d9e..fe5b625e4 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -105,13 +105,13 @@ pub fn unnormalized_obligations<'tcx>(
/// Returns the obligations that make this trait reference
/// well-formed. For example, if there is a trait `Set` defined like
-/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
+/// `trait Set<K: Eq>`, then the trait bound `Foo: Set<Bar>` is WF
/// if `Bar: Eq`.
pub fn trait_obligations<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: LocalDefId,
- trait_pred: &ty::TraitPredicate<'tcx>,
+ trait_pred: ty::TraitPredicate<'tcx>,
span: Span,
item: &'tcx hir::Item<'tcx>,
) -> Vec<traits::PredicateObligation<'tcx>> {
@@ -129,12 +129,17 @@ pub fn trait_obligations<'tcx>(
wf.normalize(infcx)
}
+/// Returns the requirements for `clause` to be well-formed.
+///
+/// For example, if there is a trait `Set` defined like
+/// `trait Set<K: Eq>`, then the trait bound `Foo: Set<Bar>` is WF
+/// if `Bar: Eq`.
#[instrument(skip(infcx), ret)]
-pub fn predicate_obligations<'tcx>(
+pub fn clause_obligations<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: LocalDefId,
- predicate: ty::Predicate<'tcx>,
+ clause: ty::Clause<'tcx>,
span: Span,
) -> Vec<traits::PredicateObligation<'tcx>> {
let mut wf = WfPredicates {
@@ -148,45 +153,32 @@ pub fn predicate_obligations<'tcx>(
};
// It's ok to skip the binder here because wf code is prepared for it
- match predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(t)) => {
- wf.compute_trait_pred(&t, Elaborate::None);
+ match clause.kind().skip_binder() {
+ ty::ClauseKind::Trait(t) => {
+ wf.compute_trait_pred(t, Elaborate::None);
}
- ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) => {}
- ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
- ty,
- _reg,
- ))) => {
+ ty::ClauseKind::RegionOutlives(..) => {}
+ ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
wf.compute(ty.into());
}
- ty::PredicateKind::Clause(ty::ClauseKind::Projection(t)) => {
+ ty::ClauseKind::Projection(t) => {
wf.compute_projection(t.projection_ty);
wf.compute(match t.term.unpack() {
ty::TermKind::Ty(ty) => ty.into(),
ty::TermKind::Const(c) => c.into(),
})
}
- ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
+ ty::ClauseKind::ConstArgHasType(ct, ty) => {
wf.compute(ct.into());
wf.compute(ty.into());
}
- ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+ ty::ClauseKind::WellFormed(arg) => {
wf.compute(arg);
}
- ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
+ ty::ClauseKind::ConstEvaluatable(ct) => {
wf.compute(ct.into());
}
-
- ty::PredicateKind::ObjectSafe(_)
- | ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::Subtype(..)
- | ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::Ambiguous
- | ty::PredicateKind::AliasRelate(..) => {
- bug!("We should only wf check where clauses, unexpected predicate: {predicate:?}")
- }
}
wf.normalize(infcx)
@@ -233,7 +225,7 @@ enum Elaborate {
fn extend_cause_with_original_assoc_item_obligation<'tcx>(
tcx: TyCtxt<'tcx>,
- trait_ref: &ty::TraitRef<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
item: Option<&hir::Item<'tcx>>,
cause: &mut traits::ObligationCause<'tcx>,
pred: ty::Predicate<'tcx>,
@@ -262,7 +254,8 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
// projection coming from another associated type. See
// `tests/ui/associated-types/point-at-type-on-obligation-failure.rs` and
// `traits-assoc-type-in-supertrait-bad.rs`.
- if let Some(ty::Alias(ty::Projection, projection_ty)) = proj.term.ty().map(|ty| ty.kind())
+ if let Some(ty::Alias(ty::Projection, projection_ty)) =
+ proj.term.ty().map(|ty| ty.kind())
&& let Some(&impl_item_id) =
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id)
&& let Some(impl_item_span) = items
@@ -278,8 +271,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
// can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
if let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) = *pred.self_ty().kind()
- && let Some(&impl_item_id) =
- tcx.impl_item_implementor_ids(impl_def_id).get(&def_id)
+ && let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&def_id)
&& let Some(impl_item_span) = items
.iter()
.find(|item| item.id.owner_id.to_def_id() == impl_item_id)
@@ -336,9 +328,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
- fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
+ fn compute_trait_pred(&mut self, trait_pred: ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
let tcx = self.tcx();
- let trait_ref = &trait_pred.trait_ref;
+ let trait_ref = trait_pred.trait_ref;
// Negative trait predicates don't require supertraits to hold, just
// that their args are WF.
@@ -411,7 +403,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
// Compute the obligations that are required for `trait_ref` to be WF,
// given that it is a *negative* trait predicate.
- fn compute_negative_trait_pred(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
+ fn compute_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
for arg in trait_ref.args {
self.compute(arg);
}
@@ -608,7 +600,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
| ty::Float(..)
| ty::Error(_)
| ty::Str
- | ty::GeneratorWitness(..)
+ | ty::CoroutineWitness(..)
| ty::Never
| ty::Param(_)
| ty::Bound(..)
@@ -680,14 +672,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}
}
- ty::Generator(did, args, ..) => {
- // Walk ALL the types in the generator: this will
+ ty::Coroutine(did, args, ..) => {
+ // Walk ALL the types in the coroutine: this will
// include the upvar types as well as the yield
// type. Note that this is mildly distinct from
// the closure case, where we have to be careful
// about the signature of the closure. We don't
// have the problem of implied bounds here since
- // generators don't take arguments.
+ // coroutines don't take arguments.
let obligations = self.nominal_obligations(did, args);
self.out.extend(obligations);
}